喚醒 App 的那些事
移動互聯時代,很多互聯網服務都會同時具備網站以及移動客戶端,很多人認為APP的能幫助建立更穩固的用戶關系,于是經常會接到各種從瀏覽器、webview、短信、甚至是在其他APP中喚醒APP的運營需求。
運營推廣場景
1、微信、QQ等 -> 喚醒APP
用戶通過某APP分享了一條鏈接至微信或QQ,用戶B點開該鏈接后,會引導用戶B打開該APP或者下載該APP。
2、瀏覽器 -> 喚醒APP
用戶A通過瀏覽器打開了某APP的M站或者官網,如果檢測到A來自手機端,則會引導用戶打開該APP或者下載該APP。
3、 短信、郵件、二維碼等 -> 喚醒APP
用戶A打開了某APP的推廣短信,郵件或者掃描二維碼等,會引導用戶打開該APP或者下載該APP。
4、其他APP -> 喚醒APP
用戶A通過第三方APP分享了(任何可以分享信息的品臺或工具:IM或者短信等)一條鏈接至用戶B,用戶B點開該鏈接后,鏈接會引導用戶B打開指定APP或者下載指定APP。
APP服務化理念
所謂APP的服務化就是利用喚醒功能將APP的特定頁面做為一個單獨的服務或者內容,通過一定的渠道和載體傳播出去,并且能夠像傳統的網頁鏈接那樣被一鍵喚醒。
更多關于APP服務化理念,推薦大家看看這篇文章。
那么移動平臺提供了哪些喚醒APP的方法呢?
如何喚醒APP
目前常見的喚醒APP方式有幾種:
-
URL Scheme
URL Scheme 是iOS,Android平臺都支持,只需要原生APP開發時注冊 scheme , 那么用戶點擊到此類鏈接時,會自動喚醒APP,借助于 URL Router 機制,則還可以跳轉至指定頁面。比如:
<!-- 喚醒APP并跳轉至指定的path頁面 -->
<a href="<scheme>://<path>?<params>=<value>">打開APP</a>
<!-- JS設置iframe src跳轉至指定的path頁面 -->
//創建一個隱藏的iframe
var ifr = document.createElement('iframe');
ifr.src = '<scheme>://<path>?<params>=<value>';
ifr.style.display = 'none';
document.body.appendChild(ifr);
//記錄喚醒時間
var openTime = +new Date();
window.setTimeout(function(){
document.body.removeChild(ifr);
//如果setTimeout 回調超過2500ms,則彈出下載
if( (+new Date()) - openTime > 2500 ){
window.location = '指定的下載頁面';
}
},2000)
這種方式是當期使用最廣泛,也是最簡單的,但是需要手機,APP支持 URL Scheme 。
優點:開發成本低,絕大多數都支持,web-native協議制定也簡單。
缺點:錯誤處理情況因平臺不同,難以統一處理,部分APP會直接跳錯誤頁(比如Android Chrome/41,iOS中老版的Lofter);也有的停留在原頁面,但彈出提示“無法打開網頁”(比如iOS7);iOS8以及最新的Android Chrome/43 目前都是直接停留在當前頁,不會跳出錯誤提示。
支持情況:iOS在實際使用中,騰訊系的微信,QQ明確禁止使用,iOS9以后Safari不再支持通過js,iframe等來觸發scheme跳轉,并且還加入了確認機制,使得通過js超時機制來自動喚醒APP的方式基本不可用;Android平臺則各個app廠商差異很大,比如Chrome從25及以后就同Safari情況一樣。
-
Android intent
這是Android平臺獨有的,使用方式如下:
intent:
HOST/URI-path // Optional host
#Intent;
package=[string];
action=[string];
category=[string];
component=[string];
scheme=[string];
end;
這里的HOST/URI-path, 與普通http URL 的host/path書寫方式相同, package是Android APP的包名,其它參數如action、category、component不是很理解, 有興趣可以去了解官方文檔。代碼如下:
<!-- 喚醒APP并跳轉至指定的path頁面 -->
<a href="intent://<role>/<path>#Intent;scheme=<scheme>;package=com. domain;end"">打開APP</a>
如果手機能匹配到相應的APP,則會直接打開;如沒有安裝,則會跳到手機默認的應用商店,比如Google原生系統Nexus 5,將會直接跳到Google Play,對于國內各廠商定制過的系統,則跳轉到各自的默認應用商店,或者彈出商店供選擇。 intent 比 scheme 相對完善的一點是,提供一個打開失敗去向URL的選項,可以通過指定參數 S.browser_fallback_url 來指定去向URL。比如打開APP動作,如果打開失敗,則跳轉到APP下載頁,這對于國內的特殊網絡環境,還是挺有用的。
-
Safari內置APP廣告條
在頁面 Head 中增加如下 meta , 添加智能App廣告條,可以自動判斷是否已安裝應用,只能用于Safari,在第三方應用中就不行了。
<meta"apple-itunes-app"content"app-id=myAppStoreID, affiliate-data=myAffiliateData, app-argument=myURL"
-
Android Chrome內置APP安裝提示
這個是Mobile Chrome 43 beta新加入的特性,在用戶瀏覽某一個網站多次后,如果Chrome發現該站點有原生APP,則會提示用戶下載原生APP,此項特性開發者無法干預,完全是Google的推薦行為。
-
Universal Links
在2015年的WWDC大會上,Apple推出了iOS 9的一個功能:Universal Links通用鏈接。如果你的App支持Universal Links,那就可以訪問HTTP/HTTPS鏈接直接喚起APP進入具體頁面,不需要其他額外判斷;如果未安裝App,訪問此通用鏈接時,可以一個自定義網頁。
優點:
1、唯一性:不像自定義的scheme,因為它使用標準的HTTP/HTTPS鏈接到你的web站點,所以它不會被其它的APP所聲明。另外,URL scheme 因為是自定義的協議,所以在沒有安裝 APP 的情況下是無法直接打開的,而Universal Links本身是一個HTTP/HTTPS鏈接,所以有更好的兼容性;
2、安全:當用戶的手機上安裝了你的 APP ,那么iOS將去你的網站上去下載你上傳上去的說明文件(這個說明文件聲明了APP可以打開哪些類型的http鏈接)。因為只有你自己才能上傳文件到你網站的根目錄,所以你的網站和你的 APP 之間的關聯是安全的;
3、可變:當用戶手機上沒有安裝你的 APP 的時候,Universal Links也能夠工作。如果你愿意,在沒有安裝APP的時候,用戶點擊鏈接,會在safari中展示你網站的內容;
4、簡單:一個URL鏈接,可以同時作用于網站和 APP ,可以定義統一的web-native協議;
5、私有:其它APP可以在不需要知道是否安裝了的情況下和你的APP相互通信;
缺點:
1、只支持iOS9及以上系統;當使用Universal Link打開APP之后,狀態欄右上角會出現鏈接地址,點擊它會取消Universal Link,需引導用戶重新使用Safari再次打開該鏈接,彈出Safari內置APP廣告條,再點擊打開重新開啟Universal Link。
iOS9開啟Universal Links
首先,你必須有一個域名,且這個域名的網站需要支持https,然后擁有網站的上傳到.well-known目錄的權限(這個權限是為了上傳一個Apple指定的文件 apple-app-site-association ),有了這個先決條件才能夠繼續下面的步驟:
1、創建一個json格式的命名為 apple-app-site-association 文件,注意這個文件必須沒有后綴名,文件名必須為 apple-app-site-association !!!
{
"applinks": {
"apps": [],
"details": [
{
"appID": "9JA89QQLNQ.com.apple.wwdc",
"paths": [ "/wwdc/news/", "/videos/wwdc/2015/*"]
},
{
"appID": "ABCD1234.com.apple.wwdc",
"paths": [ "*" ]
}
]
}
}
說明: appID = teamId.yourapp's bundle identifier paths = APP支持的路徑列表,只有這些指定的路徑的鏈接,才能被APP所處理,大小寫敏感。舉個例子,如果你的網站是 www.domain.com ,你的path寫的是"/support/*",那么當用戶點擊 www.domain.com/support/<path>?<params>=<value> ,就可以喚醒APP了,相反 www.domain.com/other 就不會。此外Apple為了方便開發者,提供了一個網址來驗證我們編寫的這個 apple-app-site-association 是否合法有效。
2、 激活Xcode工程中的 Associated Domains 能力,在其中的Domains中填入你想支持的域名(這里不是隨便填的,是可以支持你需要的Universal Links的域名), 必須以 applinks: 為前綴,例如: applinks:www.domain.com Apple將會在合適的時候,從這個域名請求 apple-app-site-association 文件。注意:當你打開 Associated Domains 后,Xcode會在你的工程中添加 .entitlements 文件,并且登錄開發者中心,可以看到 Associated Domains 處于Enable狀態。
3、在 AppDelegate 里實現如下代理方法:
- (BOOL)application:(UIApplication *)application continueUserActivity:(NSUserActivity *)userActivity restorationHandler:(void (^)(NSArray *))restorationHandler {
// NSUserActivityTypeBrowsingWeb 由Universal Links喚醒的APP
if ([userActivity.activityType isEqualToString:NSUserActivityTypeBrowsingWeb]) {
NSURL *webpageURL = userActivity.webpageURL;
NSString *host = webpageURL.host;
if ([host isEqualToString:@"yohunl.com"]) {
//進行我們需要的處理
} else {
[[UIApplication sharedApplication]openURL:webpageURL];
}
}
return YES;
}
至此APP已經開啟 Universal Links ,可以通過鏈接喚醒APP,并跳轉至指定頁面了。
-
Android App Links
在2015年的Google I/O大會上,Android M宣布了一個新特性:App Links讓用戶在點擊一個普通web鏈接的時候可以打開指定APP的指定頁面,前提是這個APP已經安裝并且經過了驗證,否則會顯示一個打開確認選項的彈出框。在推動deep linking上Google和Apple可謂英雄所見略同,優缺點也大致相同,只支持Android M以上系統。
Android M開啟Universal Links
開啟 Android App Links 的方式也大致同iOS一致:
先決條件:
-
注冊一個域名
-
域名的SSL通道
-
具有上傳JSON文件到域名的能力
-
Android Studio 1.3 Preview 及以上
-
Gradle 版本 — com.android.tools.build:gradle:1.3.0-beta3 及以上
-
設置 compileSdkVersion 為 android-MNC 及以上
-
buildToolsVersion — 23.0.0 rc2 及以上
創建一個json格式的web-app關聯文件,如 assetlinks.json ,上傳到web端
[{
"relation": ["delegate_permission/common.handle_all_urls"],
"target": {
"namespace": "android_app",
"package_name": "example.com.puppies.app",
"sha256_cert_fingerprints":
["14:6D:E9:83:C5:73:06:50:D8:EE:B9:95:2F:34:FC:64:16:A0:83:42:E6:1D:BE:A8:8A:04:96:B2:3F:CF:44:E5"]
}
},
{
"relation": ["delegate_permission/common.handle_all_urls"],
"target": {
"namespace": "android_app",
"package_name": "example.com.monkeys.app",
"sha256_cert_fingerprints":
["14:6D:E9:83:C5:73:06:50:D8:EE:B9:95:2F:34:FC:64:16:A0:83:42:E6:1D:BE:A8:8A:04:96:B2:3F:CF:44:E5"]
}
}]
其中 package_name : manifest中聲明的包名。 sha256_cert_fingerprints : 可以使用如下命令生成APP的sha256指紋簽名 // keystore中持有app release keys的app路徑。 // 這個路徑依賴于項目設置,因此不同的app是不同的。 keytool -list -v -keystore my-release-key.keystore 上傳這個文件到服務器的 .well-known/assetlinks.json ,為了避免今后每個app鏈接請求都訪問網絡,安卓只會在app安裝的時候檢查這個文件。
1、創建一個處理 App Links 的activity,這個activity的目的是為了實現一種這樣的機制:負責捕獲與解析深度鏈接,同時轉發用戶到正確的視圖。同時配置激活 App Links 能力,如下所示:
<activity
android:name="com.your.app.activity.ParseDeepLinkActivity"
android:alwaysRetainTaskState="true"
android:launchMode="singleTask"
android:noHistory="true"
android:theme="@android:style/Theme.Translucent.NoTitleBar">
// 此處激活 App Links
<intent-filter android:autoVerify="true">
// 注意yourdomain.com 與 www.yourdomain.com 被看成兩個不同的域名,因此你需要為每個域名添加一對http和https
<data android:scheme="http" android:host="yourdomain.com" />
<data android:scheme="https" android:host="yourdomain.com" />
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
</intent-filter>
</activity>
2、實現 App Links activity的處理邏輯
public class ParseDeepLinkActivity extends Activity {
public static final String PRODUCTS_DEEP_LINK = "/products";
public static final String XMAS_DEEP_LINK = "/campaigns/xmas";
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
// Extrapolates the deeplink data
Intent intent = getIntent();
Uri deeplink = intent.getData();
// Parse the deeplink and take the adequate action
if (deeplink != null) {
parseDeepLink(deeplink);
}
}
private void parseDeepLink(Uri deeplink) {
// The path of the deep link, e.g. '/products/123?coupon=save90'
String path = deeplink.getPath();
if (path.startsWith(PRODUCTS_DEEP_LINK)) {
// Handles a product deep link
Intent intent = new Intent(this, ProductActivity.class);
intent.putExtra("id", deeplink.getLastPathSegment()); // 123
intent.putExtra("coupon", deeplink.getQueryParameter("coupon")); // save90
startActivity(intent);
} else if (XMAS_DEEP_LINK.equals(path)) {
// Handles a special xmas deep link
startActivity(new Intent(this, XmasCampaign.class));
} else {
// Fall back to the main activity
startActivity(new Intent(context, MainActivity.class));
}
}
}
至此APP已經開啟 App Links ,可以通過鏈接喚醒APP,并跳轉至指定頁面了。
后記
總結以上各種方案,喚醒能力似乎都不是很完美,從長遠技術趨勢來看都是Deep Links,都需要
-
一個支持HTTPS的web站
但面對移動互聯網浪潮中海量APP的喚醒能力需求,一定會有創業公司來做這件事,比如國外的HoKoLinks,國內的魔窗,是自己造輪子,還是用輪子,各有利弊。
來自:http://mp.weixin.qq.com/s?__biz=MzAwNjAzNjMyOQ==&mid=2650215008&idx=1&sn=5de38cea68bb86589680a93e679fc9d1&chksm=83103c66b467b5703c1b78d8bafc79a867a611be5672b9ed259577757fb6fa0ff8d42c954f69&scene=1&srcid=09247GuNPrKh2VyqHt6Pydxe&from=groupmessage&isappinstalled=0