DeepLink用法及原理解析

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意圖時,Android系統(tǒng)按順序依次嘗試以下每一個操作,直到請求成功為止:

  1. 打開用戶首選的應(yīng)用程序,它可以處理URI,如果指定的話。
  2. 打開可以處理URI的惟一可用應(yīng)用程序。
  3. 允許用戶從對話框中選擇應(yīng)用程序。

意思也就是用戶可以自己寫一串字符串,系統(tǒng)會對該字符串進(jìn)行解析,然后調(diào)起注冊過相應(yīng)scheme的應(yīng)用,如果有多個注冊了,那么就會彈出對話框讓用戶選擇。

2. 用法

Google官方給了一個樣例: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>

在上面有兩個<intent-filter ..>這兩個<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>

上面在同一個<intent-filter ..>里面寫的兩個<data ..>,他們除了組合https://www.example.comapp://open.my.appapp://www.example.comhttps://open.my.app也是滿足上面的<intent-filter ..>的。而分開寫的時候,不存在上面的問題。
當(dāng)你添加了上面的<intent-filter..>當(dāng)你的Activity上面時,其他App,就可以通過一個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的生命周期的任何時段進(jìn)行獲取,不過一般別人應(yīng)用要調(diào)你應(yīng)用,肯定都是希望進(jìn)入你的應(yīng)用某個界面,或?qū)崿F(xiàn)某個功能。其他應(yīng)用會把該傳的信息都傳給你,最好的解析地方肯定是onCreate(或onStart但onStart還是會晚一些)。對于這個官方給了以下建議:

*   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

意思就是:

  1. 打開應(yīng)用后應(yīng)該直接到內(nèi)容,不要有任何提示,間接的頁面,或登錄。確保用戶可以看到應(yīng)用程序的內(nèi)容,即使他們以前從未打開過應(yīng)用程序。可以在隨后的交互中提示用戶,或者在啟動程序中打開應(yīng)用程序。這與網(wǎng)站第一次點(diǎn)擊免費(fèi)體驗(yàn)的原理是相同的。
  2. 遵循導(dǎo)航與后退和向上描述的設(shè)計(jì)指南,使您的應(yīng)用程序與用戶通過向后鏈接進(jìn)入您的應(yīng)用程序的深度導(dǎo)航的期望相符。

實(shí)現(xiàn)上面代碼后就可以進(jìn)行測試了。在測試時可以使用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)在瀏覽器都會解析這個intent然后調(diào)起對應(yīng)的應(yīng)用,即可以直接在網(wǎng)頁中調(diào)起應(yīng)用。

DeepLink使得開發(fā)網(wǎng)站和自己的App能很好的相互交互。而且一個intent字符串也好發(fā)送,比如你想推廣你的App,你就可以把這個intent發(fā)給廣告商,然后點(diǎn)擊的時候就把這個intent給手機(jī)瀏覽器,通過瀏覽器調(diào)起你自己的應(yīng)用。這個最好的應(yīng)用還在搜索上,在搜索的時候,當(dāng)用戶搜到對應(yīng)內(nèi)容的時候,現(xiàn)在一般都是跳網(wǎng)站。但是如果有DeepLink,那么就可以直接通過DeepLink的intent直接跳轉(zhuǎn)到你自己的App,這既方便了用戶,也方便了開發(fā)者。

3. DeepLink原理分析

3.1 DeepLinkDispatch框架

DeepLinkDispatch是Airbnb推出的一個以注解形式來實(shí)現(xiàn)dispatch跳轉(zhuǎn)的框架。這個它的簡單介紹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
    }
  }
}

多個<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
    }
  }
}

某個方法的注解:

@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中還可以注冊一個廣播接收者來接收分發(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文件,主要的文件有以下幾個:


class.png

在DeepLinkDispatch框架中主要是通過DeepLinkDelegate代理來處理傳來的Uri,在DeepLinkDelegate中主要是dispatchFrom這個方法來處理Uri。代碼如下:


DeepLinkResult.png
  1. 收下根據(jù)getIntent.getData()即可獲取到對應(yīng)的uri。

  2. 然后通過DeepLinkLoader.load()來加載注冊的uri。代碼如下


    load.png
  3. 調(diào)用loader.parseUri去解析Uri,解析完成后返回的是DeepLinkEntry來供我們使用。

  4. 解析Uri中的key-value對,代碼仍然在dispatchFrom中。


    parseUri.png

其中DeepLinkUri.getParameters代碼如下:


getParameters.png

然后調(diào)用了該類的parseParameters獲取patterns集合。


parseParameters.png

從DeepLink的intent中獲取的就是key,具體跳轉(zhuǎn)的內(nèi)容就是value。

  1. DeepLinkUri.queryParameterNames
    通過queryParameterNames就把真實(shí)的Uri解析成對應(yīng)的注解了,之后就會進(jìn)行分發(fā)邏輯了。
  2. 具體分發(fā)邏輯


    dispatch.png

    dispatch1.png

    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é)

  1. DeepLink實(shí)現(xiàn)了網(wǎng)頁直接和App直接跳轉(zhuǎn)。之前手機(jī)上的每個App都相當(dāng)于一個個孤島,沒有辦法和廣泛的網(wǎng)站實(shí)現(xiàn)直接的跳轉(zhuǎn)。現(xiàn)在比如你在瀏覽微博的時候看到某個App上面有精彩的內(nèi)容,你就可以直接點(diǎn)擊鏈接跳轉(zhuǎn)到App里面(甚至可以判斷如果按照了App就進(jìn)入App里面,如果不安裝那么就進(jìn)入應(yīng)用市場的該App下載界面),這樣的交互很方便,很好的將App連接到了整個網(wǎng)絡(luò)世界,以后有個瀏覽器就能隨意的跳轉(zhuǎn)。
  2. DeepLink完全可以在搜索中使用,目前的搜索都是搜到了內(nèi)容還是調(diào)網(wǎng)頁。以后如果開發(fā)者把自己的DeepLink鏈接提交給搜索公司,那么在搜索到對應(yīng)的結(jié)果的時候就可以直接點(diǎn)擊搜到的結(jié)果跳轉(zhuǎn)到自己的App了。這個還能應(yīng)用到廣告上去。推廣自己的App就更容易了。
  3. DeepLink使得大企業(yè)的眾多App之間相互拉活,相互跳轉(zhuǎn)。假如某公司有個超級App,那么想推廣自己的其他App就可以使用DeepLink在開啟自己某個子頁面的時候,把這個子頁面交給其他App進(jìn)行處理。這樣就拉活了自己的其他App了。
  4. 在DeepLink的基礎(chǔ)上,Google又新出了一個AppLinks,AppLinks就是你自己的網(wǎng)站和你自己的App相互關(guān)聯(lián)了。比如用戶在短信中點(diǎn)擊了你的網(wǎng)站,那么就可以直接跳轉(zhuǎn)到你的App,而不會出現(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ù)我會專門寫篇文章介紹下AppLinks及其用法。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容