移動(dòng)互聯(lián)時(shí)代,很多互聯(lián)網(wǎng)服務(wù)都會(huì)同時(shí)具備網(wǎng)站以及移動(dòng)客戶端句各,很多人認(rèn)為APP的能幫助建立更穩(wěn)固的用戶關(guān)系链患,于是經(jīng)常會(huì)接到各種從瀏覽器巧鸭、webview、短信麻捻、甚至是在其他APP中喚醒APP的運(yùn)營(yíng)需求纲仍。
運(yùn)營(yíng)推廣場(chǎng)景
-
微信、QQ等 -> 喚醒APP
用戶通過(guò)某APP分享了一條鏈接至微信或QQ贸毕,用戶B點(diǎn)開(kāi)該鏈接后郑叠,會(huì)引導(dǎo)用戶B打開(kāi)該APP或者下載該APP。 -
瀏覽器 -> 喚醒APP
用戶A通過(guò)瀏覽器打開(kāi)了某APP的M站或者官網(wǎng)明棍,如果檢測(cè)到A來(lái)自手機(jī)端乡革,則會(huì)引導(dǎo)用戶打開(kāi)該APP或者下載該APP。 -
短信摊腋、郵件沸版、二維碼等 -> 喚醒APP
用戶A打開(kāi)了某APP的推廣短信,郵件或者掃描二維碼等兴蒸,會(huì)引導(dǎo)用戶打開(kāi)該APP或者下載該APP视粮。 -
其他APP -> 喚醒APP
用戶A通過(guò)第三方APP分享了(任何可以分享信息的品臺(tái)或工具:IM或者短信等)一條鏈接至用戶B,用戶B點(diǎn)開(kāi)該鏈接后橙凳,鏈接會(huì)引導(dǎo)用戶B打開(kāi)指定APP或者下載指定APP蕾殴。
APP服務(wù)化理念
所謂APP的服務(wù)化就是利用喚醒功能將APP的特定頁(yè)面做為一個(gè)單獨(dú)的服務(wù)或者內(nèi)容笑撞,通過(guò)一定的渠道和載體傳播出去,并且能夠像傳統(tǒng)的網(wǎng)頁(yè)鏈接那樣被一鍵喚醒钓觉。
更多關(guān)于APP服務(wù)化理念茴肥,推薦大家看看這篇文章。
那么移動(dòng)平臺(tái)提供了哪些喚醒APP的方法呢荡灾?
如何喚醒APP
目前常見(jiàn)的喚醒APP方式有幾種:
- URL Scheme
URL Scheme
是iOS炉爆,Android平臺(tái)都支持,只需要原生APP開(kāi)發(fā)時(shí)注冊(cè)scheme
卧晓, 那么用戶點(diǎn)擊到此類鏈接時(shí),會(huì)自動(dòng)喚醒APP赴捞,借助于URL Router
機(jī)制逼裆,則還可以跳轉(zhuǎn)至指定頁(yè)面。比如:
<!-- 喚醒APP并跳轉(zhuǎn)至指定的path頁(yè)面 -->
<a href="<scheme>://<path>?<params>=<value>">打開(kāi)APP</a>
<!-- JS設(shè)置iframe src跳轉(zhuǎn)至指定的path頁(yè)面 -->
//創(chuàng)建一個(gè)隱藏的iframe
var ifr = document.createElement('iframe');
ifr.src = '<scheme>://<path>?<params>=<value>';
ifr.style.display = 'none';
document.body.appendChild(ifr);
//記錄喚醒時(shí)間
var openTime = +new Date();
window.setTimeout(function(){
document.body.removeChild(ifr);
//如果setTimeout 回調(diào)超過(guò)2500ms赦政,則彈出下載
if( (+new Date()) - openTime > 2500 ){
window.location = '指定的下載頁(yè)面';
}
},2000)
這種方式是當(dāng)期使用最廣泛胜宇,也是最簡(jiǎn)單的,但是需要手機(jī)恢着,APP支持URL Scheme
桐愉。
優(yōu)點(diǎn): 開(kāi)發(fā)成本低,絕大多數(shù)都支持掰派,web-native協(xié)議制定也簡(jiǎn)單从诲。
缺點(diǎn): 錯(cuò)誤處理情況因平臺(tái)不同,難以統(tǒng)一處理靡羡,部分APP會(huì)直接跳錯(cuò)誤頁(yè)(比如Android Chrome/41系洛,iOS中老版的Lofter);也有的停留在原頁(yè)面略步,但彈出提示“無(wú)法打開(kāi)網(wǎng)頁(yè)”(比如iOS7)描扯;iOS8以及最新的Android Chrome/43 目前都是直接停留在當(dāng)前頁(yè),不會(huì)跳出錯(cuò)誤提示趟薄。
支持情況: iOS在實(shí)際使用中绽诚,騰訊系的微信,QQ明確禁止使用杭煎,iOS9以后Safari不再支持通過(guò)js恩够,iframe等來(lái)觸發(fā)scheme跳轉(zhuǎn),并且還加入了確認(rèn)機(jī)制岔帽,使得通過(guò)js超時(shí)機(jī)制來(lái)自動(dòng)喚醒APP的方式基本不可用玫鸟;Android平臺(tái)則各個(gè)app廠商差異很大,比如Chrome從25及以后就同Safari情況一樣犀勒。
- Android intent
這是Android平臺(tái)獨(dú)有的屎飘,使用方式如下:
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的包名,其它參數(shù)如action钦购、category檐盟、component不是很理解, 有興趣可以去了解官方文檔。代碼如下:
<!-- 喚醒APP并跳轉(zhuǎn)至指定的path頁(yè)面 -->
<a href="intent://<role>/<path>#Intent;scheme=<scheme>;package=com. domain;end"">打開(kāi)APP</a>
如果手機(jī)能匹配到相應(yīng)的APP押桃,則會(huì)直接打開(kāi)葵萎;如沒(méi)有安裝,則會(huì)跳到手機(jī)默認(rèn)的應(yīng)用商店唱凯,比如Google原生系統(tǒng)Nexus 5羡忘,將會(huì)直接跳到Google Play,對(duì)于國(guó)內(nèi)各廠商定制過(guò)的系統(tǒng)磕昼,則跳轉(zhuǎn)到各自的默認(rèn)應(yīng)用商店卷雕,或者彈出商店供選擇。intent
比scheme
相對(duì)完善的一點(diǎn)是票从,提供一個(gè)打開(kāi)失敗去向URL的選項(xiàng)漫雕,可以通過(guò)指定參數(shù)S.browser_fallback_url
來(lái)指定去向URL。比如打開(kāi)APP動(dòng)作峰鄙,如果打開(kāi)失敗浸间,則跳轉(zhuǎn)到APP下載頁(yè),這對(duì)于國(guó)內(nèi)的特殊網(wǎng)絡(luò)環(huán)境吟榴,還是挺有用的魁蒜。
- Safari內(nèi)置APP廣告條
在頁(yè)面Head
中增加如下meta
, 添加智能App廣告條吩翻,可以自動(dòng)判斷是否已安裝應(yīng)用梅惯,只能用于Safari,在第三方應(yīng)用中就不行了仿野。
<meta"apple-itunes-app"content"app-id=myAppStoreID, affiliate-data=myAffiliateData, app-argument=myURL"
- Android Chrome內(nèi)置APP安裝提示
這個(gè)是Mobile Chrome 43 beta新加入的特性铣减,在用戶瀏覽某一個(gè)網(wǎng)站多次后,如果Chrome發(fā)現(xiàn)該站點(diǎn)有原生APP脚作,則會(huì)提示用戶下載原生APP葫哗,此項(xiàng)特性開(kāi)發(fā)者無(wú)法干預(yù),完全是Google的推薦行為球涛。
- Universal Links
在2015年的WWDC大會(huì)上劣针,Apple推出了iOS 9的一個(gè)功能:Universal Links通用鏈接。如果你的App支持Universal Links亿扁,那就可以訪問(wèn)HTTP/HTTPS鏈接直接喚起APP進(jìn)入具體頁(yè)面捺典,不需要其他額外判斷;如果未安裝App从祝,訪問(wèn)此通用鏈接時(shí)襟己,可以一個(gè)自定義網(wǎng)頁(yè)引谜。
優(yōu)點(diǎn):
- 唯一性:不像自定義的scheme,因?yàn)樗褂脴?biāo)準(zhǔn)的HTTP/HTTPS鏈接到你的web站點(diǎn),所以它不會(huì)被其它的app所聲明.另外,Custom URL scheme 因?yàn)槭亲远x的協(xié)議,所以在沒(méi)有安裝 app 的情況下是無(wú)法直接打開(kāi)的擎浴,而Universal Links本身是一個(gè)HTTP/HTTPS鏈接员咽,所以有更好的兼容性;
- 安全:當(dāng)用戶的手機(jī)上安裝了你的app贮预,那么iOS將去你的網(wǎng)站上去下載你上傳上去的說(shuō)明文件(這個(gè)說(shuō)明文件聲明了APP可以打開(kāi)哪些類型的http鏈接)贝室。因?yàn)橹挥心阕约翰拍苌蟼魑募侥憔W(wǎng)站的根目錄,所以你的網(wǎng)站和你的app之間的關(guān)聯(lián)是安全的;
- 可變:當(dāng)用戶手機(jī)上沒(méi)有安裝你的app的時(shí)候仿吞,Universal Links也能夠工作滑频。如果你愿意,在沒(méi)有安裝APP的時(shí)候唤冈,用戶點(diǎn)擊鏈接误趴,會(huì)在safari中展示你網(wǎng)站的內(nèi)容;
- 簡(jiǎn)單:一個(gè)URL鏈接务傲,可以同時(shí)作用于網(wǎng)站和app,可以定義統(tǒng)一的web-native協(xié)議枣申;
- 私有:其它APP可以在不需要知道是否安裝了的情況下和你的APP相互通信售葡;
缺點(diǎn):
- 只支持iOS9及以上系統(tǒng);當(dāng)使用Universal Link打開(kāi)APP之后忠藤,狀態(tài)欄右上角會(huì)出現(xiàn)鏈接地址挟伙,點(diǎn)擊它會(huì)取消Universal Link,需引導(dǎo)用戶重新使用Safari再次打開(kāi)該鏈接模孩,彈出Safari內(nèi)置APP廣告條尖阔,再點(diǎn)擊打開(kāi)重新開(kāi)啟Universal Link。
iOS9開(kāi)啟Universal Links
首先榨咐,你必須有一個(gè)域名介却,且這個(gè)域名的網(wǎng)站需要支持https,然后擁有網(wǎng)站的上傳到.well-known目錄的權(quán)限(這個(gè)權(quán)限是為了上傳一個(gè)Apple指定的文件apple-app-site-association
)块茁,有了這個(gè)先決條件才能夠繼續(xù)下面的步驟:
- 創(chuàng)建一個(gè)json格式的命名為
apple-app-site-association
文件齿坷,注意這個(gè)文件必須沒(méi)有后綴名,文件名必須為```apple-app-site-association``!!!
{
"applinks": {
"apps": [],
"details": [
{
"appID": "9JA89QQLNQ.com.apple.wwdc",
"paths": [ "/wwdc/news/", "/videos/wwdc/2015/*"]
},
{
"appID": "ABCD1234.com.apple.wwdc",
"paths": [ "*" ]
}
]
}
}
說(shuō)明: appID = teamId.yourapp's bundle identifier
paths = APP支持的路徑列表数焊,只有這些指定的路徑的鏈接永淌,才能被APP所處理,大小寫敏感佩耳。舉個(gè)例子遂蛀,如果你的網(wǎng)站是www.domain.com
,你的path寫的是"/support/*"干厚,那么當(dāng)用戶點(diǎn)擊www.domain.com/support/<path>?<params>=<value>
李滴,就可以喚醒APP了螃宙,相反www.domain.com/other
就不會(huì)。此外Apple為了方便開(kāi)發(fā)者悬嗓,提供了一個(gè)網(wǎng)址來(lái)驗(yàn)證我們編寫的這個(gè)apple-app-site-association
是否合法有效污呼。
激活Xcode工程中的
Associated Domains
能力,在其中的Domains中填入你想支持的域名(這里不是隨便填的,是可以支持你需要的Universal Links的域名), 必須以applinks:
為前綴包竹,例如:applinks:www.domain.com
Apple將會(huì)在合適的時(shí)候燕酷,從這個(gè)域名請(qǐng)求apple-app-site-association
文件。注意:當(dāng)你打開(kāi)Associated Domains
后周瞎,Xcode會(huì)在你的工程中添加.entitlements
文件苗缩,并且登錄開(kāi)發(fā)者中心,可以看到Associated Domains
處于Enable狀態(tài)声诸。在
AppDelegate
里實(shí)現(xiàn)如下代理方法:
- (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"]) {
//進(jìn)行我們需要的處理
} else {
[[UIApplication sharedApplication]openURL:webpageURL];
}
}
return YES;
}
至此APP已經(jīng)開(kāi)啟Universal Links
酱讶,可以通過(guò)鏈接喚醒APP,并跳轉(zhuǎn)至指定頁(yè)面了彼乌。
- Android App Links
在2015年的Google I/O大會(huì)上泻肯,Android M宣布了一個(gè)新特性:App Links讓用戶在點(diǎn)擊一個(gè)普通web鏈接的時(shí)候可以打開(kāi)指定APP的指定頁(yè)面,前提是這個(gè)APP已經(jīng)安裝并且經(jīng)過(guò)了驗(yàn)證慰照,否則會(huì)顯示一個(gè)打開(kāi)確認(rèn)選項(xiàng)的彈出框灶挟。在推動(dòng)deep linking上Google和Apple可謂英雄所見(jiàn)略同,優(yōu)缺點(diǎn)也大致相同毒租,只支持Android M以上系統(tǒng)稚铣。
Android M開(kāi)啟Universal Links
開(kāi)啟Android App Links
的方式也大致同iOS一致:
先決條件:
- 注冊(cè)一個(gè)域名
域名的SSL通道
具有上傳JSON文件到域名的能力
Android Studio 1.3 Preview 及以上
Gradle 版本 — com.android.tools.build:gradle:1.3.0-beta3 及以上
設(shè)置 compileSdkVersion 為 android-MNC 及以上
buildToolsVersion — 23.0.0 rc2 及以上
創(chuàng)建一個(gè)json格式的web-app關(guān)聯(lián)文件,如
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路徑。
// 這個(gè)路徑依賴于項(xiàng)目設(shè)置算色,因此不同的app是不同的抬伺。
keytool -list -v -keystore my-release-key.keystore
上傳這個(gè)文件到服務(wù)器的.well-known/assetlinks.json
,為了避免今后每個(gè)app鏈接請(qǐng)求都訪問(wèn)網(wǎng)絡(luò)灾梦,安卓只會(huì)在app安裝的時(shí)候檢查這個(gè)文件沛简。
- 創(chuàng)建一個(gè)處理
App Links
的activity,這個(gè)activity的目的是為了實(shí)現(xiàn)一種這樣的機(jī)制:負(fù)責(zé)捕獲與解析深度鏈接斥废,同時(shí)轉(zhuǎn)發(fā)用戶到正確的視圖椒楣。同時(shí)配置激活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 被看成兩個(gè)不同的域名牡肉,因此你需要為每個(gè)域名添加一對(duì)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>
- 實(shí)現(xiàn)
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已經(jīng)開(kāi)啟App Links
捧灰,可以通過(guò)鏈接喚醒APP,并跳轉(zhuǎn)至指定頁(yè)面了。
后記
總結(jié)以上各種方案毛俏,喚醒能力似乎都不是很完美炭庙,從長(zhǎng)遠(yuǎn)技術(shù)趨勢(shì)來(lái)看都是Deep Links,都需要
- 一個(gè)支持HTTPS的web站
但面對(duì)移動(dòng)互聯(lián)網(wǎng)浪潮中海量APP的喚醒能力需求煌寇,一定會(huì)有創(chuàng)業(yè)公司來(lái)做這件事焕蹄,比如國(guó)外的HoKoLinks,國(guó)內(nèi)的魔窗阀溶,是自己造輪子腻脏,還是用輪子,各有利弊银锻。