Android M的App Links實現詳解

ny8p 9年前發布 | 54K 次閱讀 Android M Android開發 移動開發

  • 原文鏈接 : THINGS YOU MAY NOT KNOW: ONRESUMEFRAGMENTS
  • 譯文出自 : 開發技術前線 www.devtf.cn
  • 譯者 : jianghejie
  • </ul> </blockquote>

    谷歌2015年的I/O大會上宣布了一個新特性:允許開發者將app和他們的web域名關聯。這一舉措是為了最小化用戶遇到“打開方式”對話框的概率。

    比如,我們安裝了兩個推ter應用 – 官方的和Falcon Pro。當你在某個地方點擊了推ter URL的時候,你會看到如下的對話框:

    Android M的App Links實現詳解 Android M的App Links實現詳解

    但是在安卓M中,如果一個app明確的指定了App鏈接-這個對話框將不復存在。點擊一個鏈接將立即打開官方的app,沒有第三方app的機會,更不會打開一個瀏覽器。

    在上圖的例子中,當你點擊了那個鏈接,安卓系統會檢查是否有一個app可以處理推ter.com URL,然后跟推ter.com核對哪個app(s)可以處理該域名的鏈接,這樣我們就能避免影響用戶。

    注意安卓并不會在點擊鏈接的時候才核對這些鏈接,因此在安卓決定使用哪個app之前并不會有網絡阻塞。關于這點后面有更多討論。

    雖然這會使安卓更方便- 多數情況下,你確實希望點擊一個鏈接打開的是最合適的那個app- 但是對于那些喜歡使用第三方app的人來說,似乎是一件壞事。不過這種行為可以在Android M的系統設置中關掉。

    app開發者如何實現App Links

    實現的細節可以在Android Developers' Preview 網站上找到。

    如果你有一個需要處理鏈接(比如example.com)的app,你應該:

    • 有上傳文件到example.com根路徑的權限,如果沒有,你無法讓你的app成為這些鏈接的默認打開方式。
    • 在build.gradle文件中設置compileSdkVersion 'android-MNC'。
    • 為每個這樣的<intent-filter>標簽
    <intent-filter>
        <data android:scheme="http" />
        ...
    </intent-filter>

    添加屬性android:autoVerify="true"。http也可以是https。

    注:這里對filter的寫法略去了很多,其實官網(上面的那個鏈接)有完整的示例:

    <activity ...>
        <intent-filter android:autoVerify="true">
            <action android:name="android.intent.action.VIEW" />
            <category android:name="android.intent.category.DEFAULT" />
            <category android:name="android.intent.category.BROWSABLE" />
            <data android:scheme="http" android:host="www.android.com" />
            <data android:scheme="https" android:host="www.android.com" />
        </intent-filter>
    </activity>

    認證是以主機名為單位的而不是以intent filter為單位的,因此從技術上講,并不需要為每個標簽都添加該屬性,但是添加了也不會出什么問題。

    創建JSON文件

    為了能讓安卓可以認證,你的app需要被允許使用app鏈接行為,為此,需要提供一個JSON文件,JSON文件中需要包含app的ID以及APK的公鑰證書。

    這個文件必須包含一個JSON數組,數組中可以有一個或者多個對象,每個對象對應一個你想認證的app ID:

    [
      {
        "relation": ["delegate_permission/common.handle_all_urls"],
        "target": {
          "namespace": "android_app",
          "package_name": "com.example.myapp",
          "sha256_cert_fingerprints": ["6C:EC:C5:0E:34:AE....EB:0C:9B"]
        }
      }
    ]

    比如,你現在有一個com.example.myapp的發行版app,同時還有一個叫com.example.myapp.beta的beta版app,你可以通過在數組中設置兩個對象來允許兩者都可以接受認證,每個對象帶有各自的app ID和公鑰值。

    注意,這個文件的驗證是非常嚴格的:數組中的每個對象都必須和上面的那個一模一樣。在數組中添加了任意其他的對象,或者對象中有額外的屬性都會導致整個驗證失敗。- 即便這個app對象是有效的。

    為了防止為同一個構建注冊了不同的key,貌似一個app可以指定多個SHA256指紋證書,不管怎樣,指紋證書可以通過如下方式獲得:

    echo | keytool -list -v -keystore app.keystore 2> /dev/null | grep SHA256:
    1
    echo | keytool - list - v - keystore app . keystore 2 > / dev / null | grep SHA256 :

    上傳JSON文件

    創建完文件之后,你需要上傳它同時保證它可以使用這個URL訪問http://example.com/.well-known/statements.json。

    目前這個URL是http的,最終的M版本將只允許通過HTTPS訪問該URL。
    在第一個M預覽版中,重定向到HTTPS,或者任何其他重定向(301,302或者307)貌似都會被忽略并被視為失敗。

    URL的scheme和<intent-filter>標簽中的android:scheme值是互不相干的,即使你有一個只接受HTTPS URLs的filter,認證URL仍然需要通過HTTP訪問。

    在了解了安卓如何使用這些信息之后,我們來看看如果debug這個過程。

    Android M是如何實現App Links的

    App鏈接認證涉及到安卓系統的兩個組建:Package Manager和Intent Filter Verifier。

    PackageManager是一個無處不在的標準組建 – 它負責驗證所安裝的apk是否有效,授予app權限,另外還可以通過它知道系統上安裝了些什么app。

    Intent Filter Verifier則是Android M上才有的新玩意兒。這個組建負責獲取鏈接指向的JSON認證,解析它,驗證它,然后將報告返回給PackageManger。

    雖然這個組建不是用戶輕易就能替換的,但似乎系統中只能有一個活動狀態的Intent Filter Verifier – 想要注冊成為一個verifier,必須要有android.permission.INTENT_FILTER_VERIFICATION_AGENT 權限,而這個權限只有簽名了系統密鑰的app才能得到。

    你可以通過如下的命令查看當前激活的intent filter verifier:

    adb shell dumpsys package ifv
    1
    adb shell dumpsys package ifv

    在第一個M預覽版中,com.android.statementservice完全扮演了這個角色。

    How App Links are verified

    App鏈接認證在安裝的時候就一次性完成。這就是為什么剛剛我們說不必在每次點擊鏈接的時候都阻塞網絡。

    Android M的App Links實現詳解

    當一個package安裝的時候,或者現有的package升級的時候:

    • 1.PackageManager對即將安裝的apk做常規的驗證。
    • 2.如果成功,這個package將被安裝,同時發出一個帶有android.intent.action.INTENT_FILTER_NEEDS_VERIFICATION的廣播intent,intent中還攜帶有該package的信息。
    • 3.Intent Filter Verifier的廣播接收器將獲取這個廣播。
    • 4.從package的<intent-filter>標簽中編譯出一個特有主機名的列表。
    • 5.verifier嘗試從每個特有的主機名中獲取statements.json。
    • 6.每一個被獲取的JSON文件都會檢查它的application ID和安裝包的證書。
    • 7.只有當所有文件同時滿足時,才會發送成功信息到PackageManager,否則失敗。
    • 8.PackageManager存儲結果。

    如果認證失敗,app鏈接將無法指向你的app – 你的app會像往常一樣出現在“打開方式”對話框中(除非另一個app通過了同一域名的驗證)。

    就我所了解的而言,認證只會在安裝和升級的時候會發生,因此對大多數用戶來說,再次通過驗證的機會是在app下一次升級的時候。

    Intent Filter Verifier的行為

    主機名

    example.com和www.example.com會被認為是兩個獨立的主機名。因此要求statements.json在兩個主機名下都是可直達的。

    比如,如果你將所有的請求都重定向到http://www.example.com/* to https://example.com/*,則會讓這個主機名的認證失敗,從而導致整個app鏈接認證失敗。

    這種情況下,你可能需要為你的web服務器做特殊的配置,確保每個對于statements.json的請求都有能直接返回HTTP 200。這個約束在后面的版本中可能會有所放松。

    響應時間

    如果verifier不能在5秒之內和你的web服務器建立鏈接并接收到HTTP響應,認證會失敗。

    缺少鏈接環境

    同樣的,如果在認證開始的時候設備是離線的,或者網絡環境很差,認證也會失敗。

    HTTP 緩存

    目前Intent Filter Verifier的實現基本遵循HTTP緩存規則。

    如果你的statements.json響應包含了Cache-Control: max-age=[seconds]頭部,那么這個響應將被verifier緩存到磁盤。雖然 60秒以下的’max-age’會被忽略,但是60秒似乎也足夠了。同樣的一個Expiresheader 也會被緩存。

    如果你有ETag或者最近更新的headers,那么verifier將在下一次視情況使用這些值來驗證相應的主機。據我所知,如果這些header子退出之后沒有明確指定緩存控制頭,那么響應的緩存時間將是不確定的。

    緩存頭部只理會http 200的響應,如果是一個404響應,那么下次將忽略,verifier需要直接連接主機。

    Debugging App Links

    當安卓系統試圖認證你的app鏈接時,PackageManager除了向logcat中報告true/false值之外,還有一些其他反饋,比如:

     
    IntentFilter ActivityIntentInfo{1a61a0a com.example.myapp/.MainActivity}
     verified with result:true and hosts:example.com www.example.com


    但是,你可在任意時刻向系統查詢package的app鏈接認證狀態:

    adb shell dumpsys package d

    這會返回如下的認證條目信息:

     
    Package Name: com.example.myapp
    Domains: example.com www.example.com
    Status: always

    可能會有多個關于你package的條目:一個是系統的,零個或者多個用戶的- 有些用戶的偏好覆蓋了系統參數。

    可能會產生的狀態值大致如下:

    • undefined —  app沒有在manifest中啟用鏈接自動驗證功能。

    • ask — app驗證失敗(會通過打開方式對話框詢問用戶)

    • always — app通過了驗證(點擊這個域名總是打開這個app)

    • never — app通過了驗證,但是系統設置關閉了此功能。

    如果你沒能通過認證,你可以再次嘗試重新安裝同一版本:

    adb install -r app/build/outputs/apk/app-debug.apk

    如果你在安裝的時候沒有在服務器上看見statements.json URL的請求,你可以清空Intent Verifier服務的HTTP緩存,這樣下次就會直接請求服務器:

    adb shell pm clear com.android.statementservice

    如果你不知道statements.json的內容是否正確返回,可以使用安卓模擬器的-tcpdump選項來檢查網絡上發送的是什么 – 注意安卓M最終版出來之后就沒那么容易了,因為數據是加密的。

    還有一種選擇,那就是使用模擬器的-http-proxy選項,讓所有的網絡請求都通過代理,比如Charles代理。

    總結

    雖然在開始我擔心App Links會取代目前安卓上非常酷的intent機制,但是也樂于看到這對于大多數情況都是有用的,況且如果用戶不喜歡,使用簡單的方法就可以把它關掉。

    考慮到verifier服務對JSON解析和HTTP請求異常嚴格,希望這里所提到的一些細節對你實現app linking有所幫助。祝你好運!

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