目錄介紹
- 01.先看一個場景
- 02.什么是DeepLink
- 03.什么是Deferred DeepLink
- 04.什么是AppLink
- 05.DeepLink和AppLink核心技術
- 06.DeepLink實踐方案
- 07.AppLink實踐方案
- 08.部分問題思考總結
- 09.DeepLink原理分析
- 10.AppLink原理分析
01.先看一個場景
- 假設一個場景:
- 小明告訴小楊,一鹿有車APP上有一個很有創意的抽獎活動,小新想要參與這個活動
- 如果小楊已經安裝了APP,他需要找到且打開APP,然后找到相應的活動,共計2步;
- 如果小楊沒有安裝APP,他需要在應用市場搜索一鹿有車APP、下載、打開APP且找到相應的活動,共計4步;
- 關於那些途徑實現
- 通過短信息,比如收到脈脈好友信息,通過短信息打開app跳轉制定頁面。
- 通過短信息,比如收到天貓推薦消息,通過短信息打開瀏覽器,然后通過瀏覽器跳轉指定頁面。
- 通過分享到微信中h5頁面,在微信中打開app(這個需要到微信開放平台做配置,其實是微信——>應用寶——>app指定頁面)。
- 小明告訴小楊,一鹿有車APP上有一個很有創意的抽獎活動,小新想要參與這個活動
- 提出的需求:
- 在瀏覽器或者短信中喚起APP,如果安裝了就喚起,否則引導下載。對於Android而言,這里主要牽扯的技術就是deeplink,也可以簡單看成scheme,Android一直是支持scheme的,本文只簡單分析下link的原理,包括deeplink,也包括Android6.0之后的AppLink。
- 其實,AppLink就是特殊的deeplink,只不過它多了一種類似於驗證機制,如果驗證通過,就設置默認打開,如果驗證不過,則退化為deeplink,如果單從APP端來看,區別主要在Manifest文件中的android:autoVerify="true"。
- 既而,在微信中,也可以作出這樣操作。如果用戶已經安裝app,點擊跳轉app則會通過應用寶,打開該應用並且跳轉到相應的頁面。這種也是一種AppLink。
- 然后看看下面截圖
- 提出的問題
- 1.如何實現點擊自己的網站跳到我們的App而不是任意的鏈接?
- 2.通過鏈接跳轉到App中不同的頁面,應該怎么做?某些頁面需要參數,如何攜帶參數?
- 3.短信中,有時候看到的鏈接並非http或者https開頭,短信息是如何識別這是一個鏈接,而不是一個字符串?具體看上面的短信截圖……
- 4.出現了一個彈框讓我二次確認(一般是選擇瀏覽器,只要是瀏覽器,都會相應http或者http開頭的shceme,如果你的APP安裝了多個瀏覽器,都會出現在這個彈框的選項中),如何去掉這個惡心的選擇瀏覽器的的彈框?
- 5.短信息中常見的非http或者https開頭的鏈接,究竟是如何生成的,是怎么來的?
- 6.scheme協議跳轉的原理是什么?微信打開app的原理是什么?
- 7.跳轉指定頁面,有的需要傳遞參數,有的參數是url,如何避免被非法篡改?
- 8.跳轉指定頁面,有的頁面需要登錄才能進入,沒有登錄則先跳轉登錄頁面,登錄了才跳轉指定頁面,這種如何操作?
02.什么是DeepLink
- 什么是DeepLink
- 移動端深度鏈接,簡稱deeplink。這是一種通過uri鏈接到app特定位置的一種跳轉技術,不單是簡單地通過網頁、app等打開目標app,還能達到利用傳遞標識跳轉至不同頁面的效果。
03.什么是Deferred DeepLink
- 什么是Deferred DeepLink
- 相比DeepLink,它增加了判斷APP是否被安裝,用戶匹配的2個功能;
- 1.當用戶點擊鏈接的時候判斷APP是否安裝,如果用戶沒有安裝時,引導用戶跳轉到應用商店下載應用。
- 2.用戶匹配功能,當用戶點擊鏈接時和用戶啟動APP時,分別將這兩次用戶Device Fingerprint(設備指紋信息)傳到服務器進行模糊匹配,使用戶下載且啟動APP時,直接打開相應的指定頁面。
- 相比DeepLink,它增加了判斷APP是否被安裝,用戶匹配的2個功能;
04.什么是AppLink
- 什么是AppLink
- AppLink相對復雜,需要App與Web協作完成系統驗證,但可以保證直接喚起目標App,無需用戶二次選擇或確認。
05.DeepLink和AppLink核心技術
- DeepLink和AppLink不同點。下面這個總結很重要!
不同點 DeepLink AppLink Intent scheme 任意 要求http或https Intent action 任意Action 要求配置andorid.intent.action.VIEW Intent category 任意Category 要求配置android.intent.category.BROWSABLE和android.intent.category.DEFAULT 鏈接認證 無需驗證 要求進行Digital Asset Links文件驗證 用戶體驗 可能展示一個多選項彈窗或確認彈窗,用戶需要二次選擇或確認 無彈窗,直接由App處理鏈接 兼容性 所有版本 Android6.0及以上版本 - DeepLink和AppLink用到的核心技術
- URL SCHEMES。不論是IOS還是Android。
- 比如微信:URL Schemes:weixin://dl/moments(打開微信朋友圈)
- DeepLink與AppLink,本質上都是基於Intent框架,使App能夠識別並處理來自系統或其他App的某種特殊URL,在原生App之間相互跳轉,實現良好的用戶體驗
06.DeepLink實踐方案
- 1.指定scheme跳轉規則,關於scheme的協議規則,這里不作過多解釋,[scheme]://[host]/[path]?[query]。比如暫時是這樣設定的:yilu://link/?page=main。
- 2.被喚起方,客戶端需要配置清單文件activity。關於SchemeActivity注意查看下面代碼:
- 為什么要配置intent-filter,它是針對你跳轉的目標來講的,比如你要去某個朋友的家,就類似於門牌的修飾,他會在門牌上定義上述介紹的那些屬性,方便你定位。當有intent發送過來的時候,就會篩選出符合條件的app來。
- action.VIEW是打開一個視圖,在Android 系統中點擊鏈接會發送一條action=VIEW的隱式意圖,這個必須配置。
- category.DEFAULT為默認,category.DEFAULT為設置該組件可以使用瀏覽器啟動,這個是關鍵,從瀏覽器跳轉,就要通過這個屬性。
- 解析數據的操作
- 3.喚起方也需要操作
- 4.關於問題疑惑點解決方案
- 配置了scheme協議,測試可以打開app,但是想跳到具體頁面,攜帶參數,又該如何實現呢?
- 比如則可以配置:yilu://link/?page=car&id=520,則可以跳轉到汽車詳情頁面,然后傳遞的id參數是520。
- 5.跳轉頁面后的優化
- 通過以上規則匹配上,你點擊跳轉以后,如果用戶結束這個Activity的話,就直接回到桌面了,這個是比較奇怪的。參考一些其他app,發現不管是跳轉指定的幾級頁面,點擊返回是回到首頁,那么這個是如何做到的呢?代碼如下所示
- 6.短信息竟無法識別scheme協議?
- 把yilu://link/?page=main以短信息發送出去,然后在短信息里點擊鏈接,發現在短信里面添加的鏈接自定義的scheme被認為不是一個scheme……可見終究跳不開的http/https訪問。
- 7.如何將一個http或https鏈接生成短鏈接
- 這個很容易,直接找個短鏈接生成的網站,然后把鏈接轉化一下就可以。至於轉化的原理,我暫時也不清楚……
07.AppLink實踐方案
- 1.Android App Links是一種特殊的Deep Links
- 它使Android系統能夠直接通過網站地址打開應用程序對應的內容頁面,而不需要用戶選擇使用哪個應用來處理網站地址。
- 要添加Android App Links到應用中,需要在應用里定義通過Http(s)地址打開應用的intent filter,並驗證你確實擁有該應用和該網站。如果系統成功驗證到你擁有該網站,那么系統會直接把URL對應的intent路由到你的應用。
- 2.和Deep Link對比多些約束條件
- APP Link 多了許多約束條件,比如scheme必須是http或者https的,但是體驗更好,沒有用戶選擇彈框,(實測下來,原生系統直接喚起來,大部分定制系統會提示是否打開鏈接,如果用戶確認以后,就直接跳到APP)調起APP之后邏輯都一樣,可以用同樣的方式取數據等。
- 3.Manifest文件中添加配置如下
- 最關鍵的是這個:android:autoVerify="true"。那這個屬性是干嘛的呢?是為了驗證我們點擊的鏈接和我們的APP是否有關聯。具體如何驗證呢?接着往下看:
- 當android:autoVerify="true"出現在你任意一個intent filter里,在Android6.0及以上的系統上安裝應用的時候,會觸發系統對APP里和URL有關的每一個域名的驗證。驗證過程設計以下步驟:
- 系統會檢查所有包含以下特征的intent filter:Action為 android.intent.action.VIEW、Category為android.intent.category.BROWSABLE和android.intent.category.DEFAULT、Data scheme為http或https
- 對於在上述intent filter里找到的每一個唯一的域名,Android系統會到對應的域名下查找數字資產文件,地址是:https://域名/.well-known/assetlinks.json
- 只有當系統為AndroidManifest里找到的每一個域名找到對應的數字資產文件,系統才會把你的應用設置為特定鏈接的默認處理器。
- 4.需要添加驗證操作
- 為了驗證你對應用和網站的所有權,以下兩個步驟是必須的:
- 1.在AndroidManifest里要求系統自動進行App Links的所有權驗證。這個配置會告訴Android系統去驗證你的應用是否屬於在intent filter內指定的URL域名。
- 2.在以下鏈接地址里,放置一個數字資產鏈接的Json文件,聲明你的網址和應用之間的關系。需要一個服務端文件讓APP知道關聯關系,APP,在安裝的時候會去校驗這個文件,校驗文件上聲明的應用包名、文件所在的域名、以及文件聲明的APP密鑰,是否能和app中的配置匹配上,如果匹配上了,在點擊該域名下的任何鏈接的時候,都會直接定向到我們的APP。
- 關於json文件的內容如下所示:
- package_name:在build.gradle里定義的application ID
- sha256_cert_fingerprints:應用簽名的SHA256指紋信息。你可以用下面的命令,通過Java keytool來生成指紋信息:$ keytool -list -v -keystore my-release-key.keystore
- json文件的注意點
- 這個文件的格式的content-type必須是application/json
- 這個文件只能放在https的鏈接中,不管你之前在action中聲明的是http或者https
- 這個文件不能有任何重定向,並且必須是以/.well-known/assetlinks.json 后綴結尾
- 你也可以在這個文件上聲明多個APP,注意看它的格式,是一個list
09.DeepLink原理分析
- deeplink的scheme相應分兩種:一種是只有一個APP能相應,另一種是有多個APP可以相應,比如,如果為一個APP的Activity配置了http scheme類型的deepLink,如果通過短信或者其他方式喚起這種link的時候,一般會出現一個讓用戶選擇的彈窗,因為一般而言,系統會帶個瀏覽器,也相應這類scheme。這里就不舉例子了,因為上面已經已經提到呢。當然,如果私有scheme跟其他APP的重復了,還是會喚起APP選擇界面(其實是一個ResolverActivity)。下面就來看看scheme是如何匹配並拉起對應APP的。
- startActivity入口與ResolverActivity
- 無論APPLink跟DeepLink其實都是通過喚起一個Activity來實現界面的跳轉,無論從APP外部:比如短信、瀏覽器,還是APP內部。通過在APP內部模擬跳轉來看看具體實現,寫一個H5界面,然后通過Webview加載,不過Webview不進行任何設置,這樣跳轉就需要系統進行解析,走deeplink這一套:
- 點擊Scheme跳轉,一般會喚起如下界面,讓用戶選擇打開方式:
- 通過adb打印log,你會發現ActivityManagerService會打印這樣一條Log:
- 其實看到的選擇對話框就是ResolverActivity
- 不過我們先來看看到底是走到ResolverActivity的,也就是這個scheme怎么會喚起App選擇界面,在短信中,或者Webview中遇到scheme,他們一般會發出相應的Intent(當然第三方APP可能會屏蔽掉,比如微信就換不起APP),其實上面的作用跟下面的代碼結果一樣:
- 那剩下的就是看startActivity,在源碼中,startActivity最后會通過ActivityManagerService調用ActivityStatckSupervisor的startActivityMayWait
- startActivityMayWait會通過resolveActivity先找到目標Activity,這個過程中,可能找到多個匹配的Activity,這就是ResolverActivity的入口:
- 可以認為,所有的四大組件的信息都在PackageManagerService中有登記,想要找到這些類,就必須向PackagemanagerService查詢
- PackageManagerService會通過queryIntentActivities找到所有適合的Activity,再通過chooseBestActivity提供選擇的權利。這里分如下三種情況:
- 僅僅找到一個,直接啟動
- 找到了多個,並且設置了其中一個為默認啟動,則直接啟動相應Acitivity
- 找到了多個,切沒有設置默認啟動,則啟動ResolveActivity供用戶選擇
- 關於如何查詢,匹配的這里不詳述,僅僅簡單看看如何喚起選擇頁面,或者默認打開,比較關鍵的就是chooseBestActivity
- 其實上述流程比較復雜,這里只是自己簡單猜想下流程,找到目標Activity后,無論是真的目標Acitiviy,還是ResolveActivity,都會通過startActivityLocked繼續走啟動流程,這里就會看到之前打印的Log信息:
- 如果是ResolveActivity還會根據用戶選擇的信息將一些設置持久化到本地,這樣下次就可以直接啟動用戶的偏好App。其實以上就是deeplink的原理,說白了一句話:scheme就是隱式啟動Activity,如果能找到唯一或者設置的目標Acitivity則直接啟動,如果找到多個,則提供APP選擇界面。
10.AppLink原理分析
- 之前分析deeplink的時候提到了ResolveActivity這么一個選擇過程,而AppLink就是自動幫用戶完成這個選擇過程,並且選擇的scheme是最適合它的scheme(開發者的角度)。因此對於AppLink要分析的就是如何完成了這個默認選擇的過程。
- 目前Android源碼提供的是一個雙向認證的方案:在APP安裝的時候,客戶端根據APP配置像服務端請求,如果滿足條件,scheme跟服務端配置匹配的上,就為APP設置默認啟動選項,所以這個方案很明顯,在安裝的時候需要聯網才行,否則就是完全不會驗證,那就是普通的deeplink,既然是在安裝的時候去驗證,那就看看PackageManagerService是如何處理這個流程的,具體找到installPackageLI方法:
- 可以看到發送了一個handler消息,那么消息里做了什么呢?看一下startIntentFilterVerifications發送一個消息開啟驗證,隨后調用verifyIntentFiltersIfNeeded進行驗證,代碼如下所示:
- 以看出,驗證就三步:檢查、搜集、驗證。在檢查階段,首先看看是否有設置http/https scheme的Activity,並且是否滿足設置了Intent.ACTION_DEFAULT與Intent.ACTION_VIEW,如果沒有,則壓根不需要驗證
- 具體看一下hasDomainURLs到底做了什么?
- 檢查的第二步試看看是否設置了autoverify,當然中間還有些是否設置過,用戶是否選擇過的操作,比較復雜,不分析,不過不影響對流程的理解:
- 只要找到一個滿足以上條件的Activity,就開始驗證。如果想要開啟applink,Manifest中配置必須像下面這樣
- 搜集其實就是搜集intentfilter信息,下面直接看驗證過程
- 目前Android的實現是通過發送一個廣播來進行驗證的,也就是說,這是個異步的過程,驗證是需要耗時的(網絡請求),所以安裝后,一般要等個幾秒Applink才能生效,廣播的接受處理者是:IntentFilterVerificationReceiver
- IntentFilterVerificationReceiver收到驗證消息后,通過start一個DirectStatementService進行驗證,兜兜轉轉最終調用IsAssociatedCallable的verifyOneSource
- IsAssociatedCallable會逐一對需要驗證的intentfilter進行驗證,具體是通過DirectStatementRetriever的retrieveStatements來實現:
- AndroidAppAsset好像是Google的另一套assetlink類的東西,好像用在APP web登陸信息共享之類的地方 ,不看,直接看retrieveFromWeb:從名字就能看出,這是獲取服務端Applink的配置,獲取后跟本地校驗,如果通過了,那就是applink啟動成功:
- 其實就是通過UrlFetcher獲取服務端配置,然后發給之前的receiver進行驗證:
- 看到這里的HttpURLConnection就知道為什么Applink需在安裝時聯網才有效,到這里其實就可以理解的差不多,后面其實就是針對配置跟App自身的配置進行校驗,如果通過就設置默認啟動,並持久化,驗證成功的話可以通過。
01.關於博客匯總鏈接
02.關於我的博客
- github:https://github.com/yangchong211
- 知乎:https://www.zhihu.com/people/yczbj/activities
- 簡書:http://www.jianshu.com/u/b7b2c6ed9284
- csdn:http://my.csdn.net/m0_37700275
- 喜馬拉雅聽書:http://www.ximalaya.com/zhubo/71989305/
- 開源中國:https://my.oschina.net/zbj1618/blog
- 泡在網上的日子:http://www.jcodecraeer.com/member/content_list.php?channelid=1
- 郵箱:yangchong211@163.com
- 阿里雲博客:https://yq.aliyun.com/users/article?spm=5176.100- 239.headeruserinfo.3.dT4bcV
- segmentfault頭條:https://segmentfault.com/u/xiangjianyu/articles
- 掘金:https://juejin.im/user/5939433efe88c2006afa0c6e