DeepLink的实现原理「建议收藏」

DeepLink的实现原理「建议收藏」前言之前我们又是看源码又是研究动画,今天分享一个比较简单的技术点:DeepLink。DeepLink,深度链接技术,主要应用场景是通过Web页面直接调用Android原生app,并且把需要的参数通过Uri的形式,直接传递给app,节省用户的注册成本。简单的介绍DeepLink概念之后,我们看一个实际的例子:朋友通过京东分享给我一个购物链接:于是我通过微信打开了这条链接:…

大家好,又见面了,我是你们的朋友全栈君。

前言

之前我们又是看源码又是研究动画,今天分享一个比较简单的技术点:DeepLink。

DeepLink,深度链接技术,主要应用场景是通过Web页面直接调用Android原生app,并且把需要的参数通过Uri的形式,直接传递给app,节省用户的注册成本。简单的介绍DeepLink概念之后,我们看一个实际的例子:

朋友通过京东分享给我一个购物链接:

DeepLink的实现原理「建议收藏」

于是我通过微信打开了这条链接:

DeepLink的实现原理「建议收藏」

在微信中打开这个网址链接,提示我打开京东app,如果我点击了允许,就会打开我手机中的京东app,并且跳转到这个商品的详情页:

DeepLink的实现原理「建议收藏」

通过这种形式,我可以快速的找到需要查看的商品,并且完成购买相关的操作。是不是非常方便,这就是DeepLink。

正文

这么流弊的DeepLink是不是非常的难?其实DeepLink的基本实现是简单到不可思议,他的核心思想实际上是Android的隐式启动。我们平时的隐式启动主要是通过Action和Category配合启动指定类型的Activity:

<activity
      android:name=".SecondActivity"
      android:exported="true">
      <intent-filter>
           <action android:name="com.lzp.deeplinkdemo.SECOND" />
           <category android:name="android.intent.category.DEFAULT" />
      </intent-filter>
</activity>
val intent = Intent("com.lzp.deeplinkdemo.SECOND")
intent.addCategory(Intent.CATEGORY_DEFAULT)
startActivity(intent)

除了action和category,还有一种隐式启动的用法是配置data:

<data
     android:scheme="xxxx"
     android:host="xxxx"
     android:port="xxxx"
     android:path="xxxx"
     android:pathPattern="xxxx"
     android:pathPrefix="xxxx"
     android:mimeType="xxxx"/>

scheme:协议类型,我们可以自定义,一般是项目或公司缩写,String

host:域名地址,String

port:端口,int。

path:访问的路径,String

pathPrefix:访问的路径的前缀,String

pathPattern:访问路径的匹配格式,相对于path和pathPrefix更为灵活,String

mimeType:资源类型,例如常见的:video/*, image/png, text/plain。

通过这几个配置项,我们发现data实际上为当前的页面绑定了一个Uri地址,这样就可以通过Uri直接打开这个Activity。

复习一下Uri的结构:

<scheme> :// <host> : <port> / [ <path> | <pathPrefix> | <pathPattern> ]

示例:https://zhidao.baidu.com/question/2012197558423339788.html

scheme和host不可缺省,否则配置无效;path,pathPrefix,pathPattern一般指定一个就可以了,pathPattern与host不可同时使用;mimeType可以不设置,如果设置了,跳转的时候必须加上mimeType,否则不能匹配到Activity。

现在我们修改SecondActivity的intent-filer:

<activity
    android:name=".SecondActivity"
    android:exported="true">

        <intent-filter>
            <action android:name="com.lzp.deeplinkdemo.SECOND" />
            <category android:name="android.intent.category.DEFAULT" />
        </intent-filter>

        <intent-filter>              

            <data
                android:scheme="lzp"
                android:host="demo"
                android:port="8888"
                android:path="/second"
                android:pathPattern="/second"
                android:pathPrefix="/second"
                android:mimeType="text/plain"/>

        </intent-filter>
</activity>

打开SecondActivity:

val intent = Intent()
intent.setDataAndType(Uri.parse("lzp://demo:8888/second"), "text/plain")
startActivity(intent)

现在在App中已经可以打开页面了,那么用web能不能正常打开呢?首先配置MainActivity的intent-filter:

<activity
    android:name=".MainActivity"
    android:exported="true">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>

        <intent-filter>
            <data
                android:scheme="lzp"
                android:host="demo"
                android:path="/main"/>
        </intent-filter>

</activity>

Web需要打开url链接,所以我们不需要配置mimeType,

手写一个简单的Html页面:

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
  <meta http-equiv="Content-Style-Type" content="text/css">
  <title></title>
  <meta name="Generator" content="Cocoa HTML Writer">
  <meta name="CocoaVersion" content="1561.4">
  <style type="text/css">
    p.p1 {margin: 0.0px 0.0px 0.0px 0.0px; line-height: 17.0px; font: 12.0px 'Songti SC'; color: #000000; -webkit-text-stroke: #000000; min-height: 17.0px}
    span.s1 {font-kerning: none}
  </style>
</head>
<body>
<a href="lzp://demo/main">打开main</a>
</html>

Html页面添加了一个链接,点击打开lzp://demo/main这个地址。把html导入到手机中,用浏览器打开,点击“打开app”,毫无反应!!!

没错,如果只是配置了data,Web还是没办法通过url地址打开我们的Activity,那怎么解决这个问题呢?

/**
     * Activities that can be safely invoked from a browser must support this
     * category.  For example, if the user is viewing a web page or an e-mail
     * and clicks on a link in the text, the Intent generated execute that
     * link will require the BROWSABLE category, so that only activities
     * supporting this category will be considered as possible actions.  By
     * supporting this category, you are promising that there is nothing
     * damaging (without user intervention) that can happen by invoking any
     * matching Intent.
     */
    @SdkConstant(SdkConstantType.INTENT_CATEGORY)
    public static final String CATEGORY_BROWSABLE = "android.intent.category.BROWSABLE";

我们还需要配置

<category android:name="android.intent.category.BROWSABLE" />

从官方的注释上写明:需要浏览器打开Activity,需要设置这个分类。例如邮件,只有设置了这个分类的Activity才会考虑被打开。加上这个配置后,再次点击看看有没有效果。

如果你真的亲自尝试了,你会发现还是没有效果。这个时候我们需要回顾一下action和category的用法:

首先需要尝试匹配action,action匹配成功了之后,才会继续匹配设置的category,所以单独匹配category是没有任何效果的。

因为我们要打开的仅仅是一个页面,所以我们设置

/**
     * Activity Action: Display the data to the user.  This is the most common
     * action performed on data -- it is the generic action you can use on
     * a piece of data to get the most reasonable thing to occur.  For example,
     * when used on a contacts entry it will view the entry; when used on a
     * mailto: URI it will bring up a compose window filled with the information
     * supplied by the URI; when used with a tel: URI it will invoke the
     * dialer.
     * <p>Input: {@link #getData} is URI from which to retrieve data.
     * <p>Output: nothing.
     */
    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
    public static final String ACTION_VIEW = "android.intent.action.VIEW";

官方的注释说明ACTION_VIEW表示展示数据的页面,系统默认的Action就是ACTION_VIEW。添加上ACTION_VIEW,再次点击打开app。

还是不行,但是跟之前不同的是,这次出现了启动app的提示窗口,但是app却闪退了,看一下崩溃日志:

09-06 14:35:15.459 1216-3270/? W/IntentResolver: resolveIntent failed: found match, but none with CATEGORY_DEFAULT
09-06 14:35:15.473 26708-26708/? E/AKAD: thread:Thread[main,5,main]
    android.content.ActivityNotFoundException: No Activity found to handle Intent { act=android.intent.action.VIEW cat=[android.intent.category.BROWSABLE] dat=lzp://demo/main?id=111 flg=0x10000000 (has extras) }
        at android.app.Instrumentation.checkStartActivityResult(Instrumentation.java:1805)
        at android.app.Activity.startActivityIfNeeded(Activity.java:4420)
        at android.app.Activity.startActivityIfNeeded(Activity.java:4367)
        at org.chromium.chrome.browser.externalnav.ExternalNavigationDelegateImpl$3.onClick(ExternalNavigationDelegateImpl.java:239)
        at com.qihoo.browser.dialog.CustomDialog$3.onClick(CustomDialog.java:274)
        at android.view.View.performClick(View.java:5267)
        at android.view.View$PerformClick.run(View.java:21249)
        at android.os.Handler.handleCallback(Handler.java:739)
        at android.os.Handler.dispatchMessage(Handler.java:95)
        at android.os.Looper.loop(Looper.java:148)
        at android.app.ActivityThread.main(ActivityThread.java:5541)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:745)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:635)

日志上写的很明确,虽然找到了匹配的页面,但是没有设置CATEGORY_DEFAULT。看来Web通过url来打开链接,必须要求设置CATEGORY_DEFAULT,添加上后,看一下我们完整的xml配置:

<activity
    android:name=".MainActivity"
            android:exported="true">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>

        <intent-filter>
            <action android:name="android.intent.action.VIEW" />
            <category android:name="android.intent.category.DEFAULT" />
            <category android:name="android.intent.category.BROWSABLE" />
            <data
                android:scheme="lzp"
                android:host="demo"
                android:path="/main"/>
        </intent-filter>
</activity>

最后看一下效果:

DeepLink的实现原理「建议收藏」

那么如何在通过url给app传递参数呢?要实现这个也很简单,首先我们知道要想给url添加参数,直接在url后拼接key=value就可以了,例如:

http://www.baidu.com/s?wd=android

其中wd=android就是我们要添加的参数,现在假设我们需要为Activity传递一个参数id,我们就可以修改uri为:

lzp://demo/main?id=111

客户端接收key为id的参数的方法:

if (intent != null && intent.data != null) {
       Log.e("lzp", intent.data.getQueryParameter("id"))
}

如果只是接收参数的话,客户端不需要进行任何修改,但是这里有一种情况,如果我们Activity必须传递id,如果不传递id不允许跳转怎么办呢?我们有两种办法解决这个问题:

1、在刚才的if语句增加else判断,当参数为空的时候,进行finish操作。

2、通过pathPattern,通过通配符设置必须有参数。

我们看一下第二种的实现方式:

<data
    android:pathPattern="lzp://demo/main?id=*"
    android:scheme="lzp" />

之前已经说过,pathPattern不能和host同时使用,所以我们只能删除host,pathPattern匹配的是整个Uri,这样我们还可以指定多个参数。但是AndroidManifest.xml会报错,我们忽略就可以了

总结

其实DeepLink的实现原理就是这么简单,只是我们对于隐式启动理解的不够。是不是也想给自己的App加上DeepLink呢?赶快尝试一下吧~

 

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/149745.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • CentOS 7修改网络接口名称

    CentOS 7修改网络接口名称

    2021年6月12日
    150
  • MP4格式详解_mp4格式有哪些

    MP4格式详解_mp4格式有哪些一、mp4概述MP4文件中的所有数据都装在box(QuickTime中为atom)中,也就是说MP4文件由若干个box组成,每个box有类型和长度,可以将box理解为一个数据对象块。box中可以包含另一个box,这种box称为containerbox。一个MP4文件首先会有且只有一个“ftyp”类型的box,作为MP4格式的标志并包含关于文件的一些信息;之后会有且只有一个“moov”类型的box(MovieBox),它是一种containerbox,子box包含了媒体的metadata信息;MP4文

    2022年10月16日
    0
  • mysql中去重 distinct 用法「建议收藏」

    mysql中去重 distinct 用法

    2022年2月10日
    367
  • 2018年NGINX最新版高级视频教程[通俗易懂]

    2018年NGINX最新版高级视频教程

    2022年2月9日
    52
  • javah详解[通俗易懂]

    javah详解[通俗易懂]java开发中如果使用到JNI,则难免需要使用javah来生成C++或C的头文件信息,下面就讲解javah的命令:第一种:直接cd到当前程序的target/class目录下(一定不能是子目录)(maven项目,如果是普通项目则到bin目录下)。然后使用:javahcom.yongcheng.liuyang.utils.TestJni,其中javah后面的是需要生成头文件类的全路径(包名+类名),当然生成的.h文件位于当前class的目录下。第二种:直接在运行中cmd到dos窗口,使用如下命令:j

    2022年9月25日
    0
  • python收集数据做主神_里纲_[综漫]收集数据做主神小说无防盗章节_作者忘却的悠_新书包网(www.51aslz.com)…[通俗易懂]

    python收集数据做主神_里纲_[综漫]收集数据做主神小说无防盗章节_作者忘却的悠_新书包网(www.51aslz.com)…[通俗易懂]“里包恩怎么了?”“没什么,只是在想,你做为里包恩的学生,能不能帮我个忙?”“帮忙?”纲不好意思的抓了抓头发,所有的心思都写在了脸上。什么我这么废柴能帮什么忙,虽然我很想帮忙,但是我真的什么都做不好。找里包恩本人更快吧,实在不行还有山本和狱寺他们。不过……库洛洛先生是黑手党吧?黑手党的事情,我们几个小孩子能帮什么忙呢?果然还是找里包恩比较好。能把心思在脸上表达的这么明明白白,你也算…

    2022年4月19日
    45

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号