1. 簡介
DeepLink官網(wǎng)上有這樣的解釋:
When a clicked link or programmatic request invokes a web URI intent, the Android system tries each of the following actions, in sequential order, until the request succeeds:
1. Open the user's preferred app that can handle the URI, if one is designated.
2. Open the only available app that can handle the URI.
3. Allow the user to select an app from a dialog.
Follow the steps below to create and test links to your content. You can also use the [App Links Assistant](https://developer.android.com/studio/write/app-link-indexing.html) in Android Studio to add Android App Links
翻譯后的意思就是:
當(dāng)單擊鏈接或編程請求調(diào)用Web URI意圖時(shí)肄程,Android系統(tǒng)按順序依次嘗試以下每一個(gè)操作,直到請求成功為止:
- 打開用戶首選的應(yīng)用程序选浑,它可以處理URI蓝厌,如果指定的話。
- 打開可以處理URI的惟一可用應(yīng)用程序古徒。
- 允許用戶從對話框中選擇應(yīng)用程序拓提。
意思也就是用戶可以自己寫一串字符串,系統(tǒng)會(huì)對該字符串進(jìn)行解析隧膘,然后調(diào)起注冊過相應(yīng)scheme的應(yīng)用代态,如果有多個(gè)注冊了,那么就會(huì)彈出對話框讓用戶選擇疹吃。
2. 用法
Google官方給了一個(gè)樣例:search-samples
以下根據(jù)Android官方的deep-linking的樣例來說明如何使用蹦疑。
<activity
android:name="com.example.android.GizmosActivity"
android:label="@string/title_gizmos" >
<intent-filter android:label="@string/filter_view_http_gizmos">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<!-- Accepts URIs that begin with "http://www.example.com/gizmos” -->
<data android:scheme="http"
android:host="www.example.com"
android:pathPrefix="/gizmos" />
<!-- note that the leading "/" is required for pathPrefix-->
</intent-filter>
<intent-filter android:label="@string/filter_view_example_gizmos">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<!-- Accepts URIs that begin with "example://gizmos” -->
<data android:scheme="example"
android:host="gizmos" />
</intent-filter>
</activity>
在上面有兩個(gè)<intent-filter ..>這兩個(gè)<intent-filter ..>只是在<data ..>上有所區(qū)別,但是官方仍然建議我們分開寫萨驶。比如:
<intent-filter>
...
<data android:scheme="https" android:host="www.example.com" />
<data android:scheme="app" android:host="open.my.app" />
</intent-filter>
上面在同一個(gè)<intent-filter ..>里面寫的兩個(gè)<data ..>歉摧,他們除了組合https://www.example.com和app://open.my.app外app://www.example.com和 https://open.my.app也是滿足上面的<intent-filter ..>的。而分開寫的時(shí)候,不存在上面的問題叁温。
當(dāng)你添加了上面的<intent-filter..>當(dāng)你的Activity上面時(shí)再悼,其他App,就可以通過一個(gè)intent去調(diào)起你的應(yīng)用膝但,官方這樣說到:
Once you've added intent filters with URIs for activity content to your app manifest, Android is able to route any Intent that has matching URIs to your app at runtime.
當(dāng)注冊了<intent-filter..>后冲九,便可以在Activity的中獲取其他應(yīng)用傳過來的intent值,具體調(diào)用如下:
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Intent intent = getIntent();
String action = intent.getAction();
Uri data = intent.getData();
}
getIntent可以在Activity的生命周期的任何時(shí)段進(jìn)行獲取跟束,不過一般別人應(yīng)用要調(diào)你應(yīng)用莺奸,肯定都是希望進(jìn)入你的應(yīng)用某個(gè)界面,或?qū)崿F(xiàn)某個(gè)功能冀宴。其他應(yīng)用會(huì)把該傳的信息都傳給你灭贷,最好的解析地方肯定是onCreate(或onStart但onStart還是會(huì)晚一些)。對于這個(gè)官方給了以下建議:
* The deep link should take users directly to the content, without any prompts, interstitial pages, or logins. Make sure that users can see the app content even if they never previously opened the application. It is okay to prompt users on subsequent interactions or when they open the app from the Launcher. This is the same principle as the [first click free](https://support.google.com/webmasters/answer/74536?hl=en) experience for web sites.
* Follow the design guidance described in [Navigation with Back and Up](https://developer.android.com/design/patterns/navigation.html) so that your app matches users' expectations for backward navigation after they enter your app through a deep link
意思就是:
- 打開應(yīng)用后應(yīng)該直接到內(nèi)容花鹅,不要有任何提示,間接的頁面枫浙,或登錄刨肃。確保用戶可以看到應(yīng)用程序的內(nèi)容,即使他們以前從未打開過應(yīng)用程序箩帚≌嬗眩可以在隨后的交互中提示用戶,或者在啟動(dòng)程序中打開應(yīng)用程序紧帕。這與網(wǎng)站第一次點(diǎn)擊免費(fèi)體驗(yàn)的原理是相同的盔然。
- 遵循導(dǎo)航與后退和向上描述的設(shè)計(jì)指南,使您的應(yīng)用程序與用戶通過向后鏈接進(jìn)入您的應(yīng)用程序的深度導(dǎo)航的期望相符是嗜。
實(shí)現(xiàn)上面代碼后就可以進(jìn)行測試了愈案。在測試時(shí)可以使用adb的shell命令進(jìn)行測試,語法格式如下:
$ adb shell am start
-W -a android.intent.action.VIEW
-d <URI> <PACKAGE>
例如我們上面的例子就可以采用如下方式進(jìn)行打開:
$ adb shell am start
-W -a android.intent.action.VIEW
-d "example://gizmos" com.example.android
上面的intent也可以通過瀏覽器里面的網(wǎng)頁進(jìn)行設(shè)置鹅搪,現(xiàn)在瀏覽器都會(huì)解析這個(gè)intent然后調(diào)起對應(yīng)的應(yīng)用站绪,即可以直接在網(wǎng)頁中調(diào)起應(yīng)用。
DeepLink使得開發(fā)網(wǎng)站和自己的App能很好的相互交互丽柿。而且一個(gè)intent字符串也好發(fā)送恢准,比如你想推廣你的App,你就可以把這個(gè)intent發(fā)給廣告商甫题,然后點(diǎn)擊的時(shí)候就把這個(gè)intent給手機(jī)瀏覽器馁筐,通過瀏覽器調(diào)起你自己的應(yīng)用。這個(gè)最好的應(yīng)用還在搜索上坠非,在搜索的時(shí)候敏沉,當(dāng)用戶搜到對應(yīng)內(nèi)容的時(shí)候,現(xiàn)在一般都是跳網(wǎng)站。但是如果有DeepLink赦抖,那么就可以直接通過DeepLink的intent直接跳轉(zhuǎn)到你自己的App舱卡,這既方便了用戶,也方便了開發(fā)者队萤。
3. DeepLink原理分析
3.1 DeepLinkDispatch框架
DeepLinkDispatch是Airbnb推出的一個(gè)以注解形式來實(shí)現(xiàn)dispatch跳轉(zhuǎn)的框架轮锥。這個(gè)它的簡單介紹README.md。
3.2 Dispatch框架使用例子
@DeepLink("foo://example.com/deepLink/{id}")
public class MainActivity extends Activity {
@Override protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Intent intent = getIntent();
if (intent.getBooleanExtra(DeepLink.IS_DEEP_LINK, false)) {
Bundle parameters = intent.getExtras();
String idString = parameters.getString("id");
// Do something with idString
}
}
}
多個(gè)<intent-filter..>的注解
//多filter的注解
@DeepLink({"foo://example.com/deepLink/{id}", "foo://example.com/anotherDeepLink"})
public class MainActivity extends Activity {
@Override protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Intent intent = getIntent();
if (intent.getBooleanExtra(DeepLink.IS_DEEP_LINK, false)) {
Bundle parameters = intent.getExtras();
String idString = parameters.getString("id");
// Do something with idString
}
}
}
某個(gè)方法的注解:
@DeepLink("foo://example.com/methodDeepLink/{param1}")
public static Intent intentForDeepLinkMethod(Context context, Bundle extras) {
Uri.Builder uri = Uri.parse(extras.getString(DeepLink.URI)).buildUpon();
return new Intent(context, MainActivity.class)
.setData(uri.appendQueryParameter("bar", "baz").build())
.setAction(ACTION_DEEP_LINK_METHOD);
}
上面的注解相當(dāng)于DeepLink中在manifest中的Activity標(biāo)簽下注冊的<intent-filter..>要尔,在DeepLinkDispatch中還可以注冊一個(gè)廣播接收者來接收分發(fā)的DeepLink字符串舍杜。
public class DeepLinkReceiver extends BroadcastReceiver {
private static final String TAG = "DeepLinkReceiver";
@Override public void onReceive(Context context, Intent intent) {
String deepLinkUri = intent.getStringExtra(DeepLinkHandler.EXTRA_URI);
if (intent.getBooleanExtra(DeepLinkHandler.EXTRA_SUCCESSFUL, false)) {
Log.i(TAG, "Success deep linking: " + deepLinkUri);
} else {
String errorMessage = intent.getStringExtra(DeepLinkHandler.EXTRA_ERROR_MESSAGE);
Log.e(TAG, "Error deep linking: " + deepLinkUri + " with error message +" + errorMessage);
}
}
}
public class YourApplication extends Application {
@Override public void onCreate() {
super.onCreate();
IntentFilter intentFilter = new IntentFilter(DeepLinkHandler.ACTION);
//使用應(yīng)用內(nèi)廣播注冊的,不用擔(dān)心其他應(yīng)用收到
LocalBroadcastManager.getInstance(this).registerReceiver(new DeepLinkReceiver(), intentFilter);
}
}
下面就來分析下它的原理赵辕。
3.3 源碼剖析
3.3.1 根據(jù)注解生成對應(yīng)class文件
在AS點(diǎn)擊build后即可生成對應(yīng)的class文件既绩,主要的文件有以下幾個(gè):
在DeepLinkDispatch框架中主要是通過DeepLinkDelegate代理來處理傳來的Uri,在DeepLinkDelegate中主要是dispatchFrom這個(gè)方法來處理Uri还惠。代碼如下:
收下根據(jù)getIntent.getData()即可獲取到對應(yīng)的uri饲握。
-
然后通過DeepLinkLoader.load()來加載注冊的uri。代碼如下
調(diào)用loader.parseUri去解析Uri蚕键,解析完成后返回的是DeepLinkEntry來供我們使用救欧。
-
解析Uri中的key-value對,代碼仍然在dispatchFrom中锣光。
其中DeepLinkUri.getParameters代碼如下:
然后調(diào)用了該類的parseParameters獲取patterns集合笆怠。
從DeepLink的intent中獲取的就是key,具體跳轉(zhuǎn)的內(nèi)容就是value誊爹。
- DeepLinkUri.queryParameterNames
通過queryParameterNames就把真實(shí)的Uri解析成對應(yīng)的注解了蹬刷,之后就會(huì)進(jìn)行分發(fā)邏輯了。 -
具體分發(fā)邏輯
6.1 首先生成Intent對象
6.2 setAction和data频丘,通過以上將action和data放入Intent中办成。
6.3 處理Bundle。
6.4 調(diào)用callingActivity搂漠。
6.5 startActivity
6.6 createResultAndNotify
通過以上步驟就完成了DeepLink調(diào)起應(yīng)用頁面的操作了诈火,具體代碼稍后再貼。
4. 總結(jié)
- DeepLink實(shí)現(xiàn)了網(wǎng)頁直接和App直接跳轉(zhuǎn)状答。之前手機(jī)上的每個(gè)App都相當(dāng)于一個(gè)個(gè)孤島冷守,沒有辦法和廣泛的網(wǎng)站實(shí)現(xiàn)直接的跳轉(zhuǎn)。現(xiàn)在比如你在瀏覽微博的時(shí)候看到某個(gè)App上面有精彩的內(nèi)容惊科,你就可以直接點(diǎn)擊鏈接跳轉(zhuǎn)到App里面(甚至可以判斷如果按照了App就進(jìn)入App里面拍摇,如果不安裝那么就進(jìn)入應(yīng)用市場的該App下載界面),這樣的交互很方便馆截,很好的將App連接到了整個(gè)網(wǎng)絡(luò)世界充活,以后有個(gè)瀏覽器就能隨意的跳轉(zhuǎn)蜂莉。
- DeepLink完全可以在搜索中使用,目前的搜索都是搜到了內(nèi)容還是調(diào)網(wǎng)頁混卵。以后如果開發(fā)者把自己的DeepLink鏈接提交給搜索公司映穗,那么在搜索到對應(yīng)的結(jié)果的時(shí)候就可以直接點(diǎn)擊搜到的結(jié)果跳轉(zhuǎn)到自己的App了。這個(gè)還能應(yīng)用到廣告上去幕随。推廣自己的App就更容易了蚁滋。
- DeepLink使得大企業(yè)的眾多App之間相互拉活,相互跳轉(zhuǎn)赘淮。假如某公司有個(gè)超級App辕录,那么想推廣自己的其他App就可以使用DeepLink在開啟自己某個(gè)子頁面的時(shí)候,把這個(gè)子頁面交給其他App進(jìn)行處理梢卸。這樣就拉活了自己的其他App了走诞。
- 在DeepLink的基礎(chǔ)上,Google又新出了一個(gè)AppLinks蛤高,AppLinks就是你自己的網(wǎng)站和你自己的App相互關(guān)聯(lián)了蚣旱。比如用戶在短信中點(diǎn)擊了你的網(wǎng)站,那么就可以直接跳轉(zhuǎn)到你的App戴陡,而不會(huì)出現(xiàn)選擇對話框塞绿。Google官方是這樣說的:
Android App Links are a special type of deep link that allow your website URLs to immediately open the
corresponding content in your Android app (without requiring the user to select the app).
To add Android App Links to your app, define intent filters that open your app content using HTTP URLs (as
described in [Create Deep Links to App Content]), and verify that you own both your app and the website URLs (as described in this guide). If the
system successfully verifies that you own the URLs, the system automatically routes those URL intents to your app.
創(chuàng)建你自己的AppLinks,可以參考如下Create Deep Links to App Content猜欺。后續(xù)我會(huì)專門寫篇文章介紹下AppLinks及其用法位隶。