喚醒 App 的那些事

zxmnb68 8年前發布 | 64K 次閱讀 安卓開發 移動開發

移動互聯時代,很多互聯網服務都會同時具備網站以及移動客戶端,很多人認為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

 

 本文由用戶 zxmnb68 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!