美文网首页
Android深度链接 Deep Links 与 App Lin

Android深度链接 Deep Links 与 App Lin

作者: 谜一样的阿瑜 | 来源:发表于2019-01-22 19:00 被阅读2次

前言

Deep Links 与 App Links 被统称为深度链接。Deep Links 相信很多人都有用过,我记得久远之前还看过两个功能的文章,这次因为产品准备使用,所以这里就具体的对比一下,然后具体使用。

对比

差别 Deep Links App Links
起效时间 立刻起效 首次安装后几十秒后(需要链接网络)
提示用户 提示(用户一旦勾选记住选择,会造成以后都无法唤醒App) 不需要用户选择
系统要求 无要求 Android 6.0 及以上版本
scheme问题 如果以 htttp/https 开头,部分手机或浏览器会当作链接打开网页 只允许使用 http/https 或 同时使用
域名注册 不需要域名 需要梯子去注册域名,并在域名内部准备验证文件 assetlinks.json

Deep Links

使用方式

  1. 配置清单注册

    <activity android:name=".ThreeActivity">
        <intent-filter>
            <!-- 两项为必填项 -->
            <action android:name="android.intent.action.VIEW" />
            <category android:name="android.intent.category.DEFAULT" />
            <!-- 该项为是否支持JS调用 -->
            <category android:name="android.intent.category.BROWSABLE" />
    
            <!-- 协议部分,随便设置:支持多协议,如果匹配到多个,则交由用户选择 -->
            <data
                android:host="com.withwings.threeactivity"
                android:path="/path"
                android:scheme="withwings" />
            <data android:scheme="helloworld" />
            <data android:pathPrefix="/path2"/>
        </intent-filter>
    </activity>
    

    备注:

    1. data 可以注册多个 scheme ,然后拼接单独注册的 host 如:

      <data android:scheme="http"/>
      <data android:scheme="https"/>
      <data android:host="www.google.com"/>
      
    2. URI 不像多态,如果你路径定义后匹配到多个,那么则会弹出多个:比如设定了两个页面:

      1. 页面 A

        <data
            android:host="com.withwings.threeactivity"
            android:path="/path"
            android:scheme="withwings" />
        
      2. 页面 B

        <data android:scheme="withwings" />
        

      此时如果调用 withwings://com.withwings.threeactivity/path 则 两个页面都会相应

    3. 虽然 data 标签是拆开的,但是实际组合是根据所有的 scheme 等 混合拼接的,不会根据标签分组,当然,使用多个 data 会看起来比较清晰

  2. 代码调用

    // 这里不会跟正常的多态一样选择最合适的,只要条件满足,就会弹窗提示用选择
    // Uri.parse(scheme + "://" + host + path)
    // uri 的三阶都必须有  许多不许少,即使是你没有设置后面的两项  编也要写上
    Uri uri = Uri.parse("withwings://com.withwings.threeactivity/path?param1=abc&param2=cde");
    Intent schemeIntent = new Intent();
    schemeIntent.setAction(Intent.ACTION_VIEW);
    schemeIntent.setData(uri);
    PackageManager packageManager = getPackageManager();
    ComponentName componentName = schemeIntent.resolveActivity(packageManager);
    // 判断该协议是否存在
    if (componentName != null) {
        startActivity(schemeIntent);
    }
    
  3. 被打开界面解析:

    Intent intent = getIntent();
    Uri uri = intent.getData();
    if (uri != null) {
        List<String> pathSegments = uri.getPathSegments(); // 获得 path 列表  可能多层path的
        this.getIntent().getScheme();//获得Scheme名称
        this.getIntent().getDataString();//获得Uri全部路径
        String uriQuery = uri.getQuery(); // 参数字符串
        if (pathSegments != null && pathSegments.size() > 0) {
            // 解析SCHEME
    
            uri.toString(); // 全路径
            uri.getScheme(); // scheme
            uri.getHost(); // host服务器地址类型
            uri.getPort(); // 端口号
            uri.getPath(); // 路径 /path 这种
            uri.getQuery(); // 参数 ? 号后面的字符串
            uri.getQueryParameterNames(); // 获得参数key集合
            uri.getQueryParameter("key"); // 获得指定参数
            String param1 = uri.getQueryParameter("param1");
            String param2 = uri.getQueryParameter("param2");
        }
    }
    
  4. adb 测试

    格式:

    $ adb shell am start \
        -W -a android.intent.action.VIEW \
        -d <URI> <PACKAGE>
    

    例:

    $ adb shell am start
        -W -a android.intent.action.VIEW \
        -d "withwings://com.withwings.threeactivity/path" com.package.name \
    

注意事项

  1. 通过路由不能将 category 设置为 LAUNCHER

  2. scheme 如果以 htttp/https 开头,部分手机或浏览器会当作链接打开网页

  3. 最好在配置清单注册 Uri 的时候,最好还是都完成三级注册

  4. 如果同一个 Activity 下有配置多个 host ,则需要通过不同的 Intent Filter 设置

App Links

App Links 属于 6.0 新特性:当用户点击对应 URI 时会直接启动对应 APP,不会有跟 Deep Links 一样的弹窗出现

官网说明

优势

  1. 安全,因为是精确到您自己的网站域名,所以没有其他应用可以使用您的链接!

  2. 无缝的用户体验:只要您自己没有注册重复的 URI 接收页面,则我们可以保证,有安装时访问您的 APP,没有安装时访问对应 URL 的网址

  3. 可以支付 Instant Apps (Google 的小程序)

  4. 可以通过网页为 APP 引流,吸引用户

使用方式

  1. 配置清单注册

    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" />
    
        <!--注意这里不要使用 www 等开头-->
        <data android:scheme="http" android:host="baidu.com" />
        <data android:scheme="https" android:host="baidu.com" />
        <data android:path="/path" />
    </intent-filter>
    

    autoVerify 是 App Links 自动验证后面配置的 json 文件的 这样设置可以让我们的 App 安装后自动验证

    注意:

    1. 如果是在启动页,请不要与启动页的 intent-filter 放在一起

    2. 一个正常的 Uri 格式

      scheme://host:port/path or pathPrefix or pathPattern
      
    3. path、pathPrefix、pathPattern 之间的区别

      • path 用来匹配完整的路径,如:http://example.com/blog/abc.html,这里将 path 设置为 /blog/abc.html 才能够进行匹配;

      • pathPrefix 用来匹配路径的开头部分,拿上面的 Uri 来说,这里将 pathPrefix 设置为 /blog 就能进行匹配了;

      • pathPattern 用表达式来匹配整个路径,这里需要说下匹配符号与转义。

        1. 匹配符号:

          • ” 用来匹配0次或更多,如:“a” 可以匹配“a”、“aa”、“aaa”...

          • “.” 用来匹配任意字符,如:“.” 可以匹配“a”、“b”,“c”...

          • 因此 “.” 就是用来匹配任意字符0次或更多,如:“.html” 可以匹配 “abchtml”、“chtml”,“html”,“sdf.html”...

        2. 转义:

          因为当读取 Xml 的时候,“\” 是被当作转义字符的(当它被用作 pathPattern 转义之前),因此这里需要两次转义,读取 Xml 是一次,在 pathPattern 中使用又是一次。如:“” 这个字符就应该写成 “\”,“\” 这个字符就应该写成 “\\”。

  2. 注册 assetlinks.json

    1. 访问Google Developers

    2. 填写host,包名,fingerprint

      1. Hosting site domain: 为服务器域名请不要添加 www 有部分手机添加后会发现无法验证

        baidu.com
        
      2. App package name: APP 包名

      3. App package fingerprint (SHA256): keystore 使用的 sha256,可以通过以下命令获取

        keytool -list -v -keystore my-release-key.keystore
        
    3. 然后点击Generate Statement生成assetlinks.json

    4. 将生成的文字存储在 assetlinks.json

    5. assetlinks.json 存储在服务器指定位置,如:

      https://host路径/.well-known/assetlinks.json
      
    6. 点击 Test Statement

      Success!…… 代表验证成功
      
  3. 国内生成 assetlinks.json

    1. 手动拼写文件 assetlinks.json ,如:

      [{
      "relation": ["delegate_permission/common.handle_all_urls"],
      "target" : { 
          "namespace": "android_app", 
          "package_name": "com.withwings.package",
          "sha256_cert_fingerprints": ["8E:80:FF:EB:42:78:07:63:32:13:1B:E7:0D:42:64:04:31:6E:97:07:73:0F:37:89:23:A2:61:CD:D2:51:32:E3"] }
      }]
      

      你真正需要修改的就是 package_name 和 sha256_cert_fingerprints

    2. assetlinks.json 存储在服务器指定位置,如:

      https://host路径/.well-known/assetlinks.json
      
    3. 手动测试

      访问路径:

      https://digitalassetlinks.googleapis.com/v1/statements:list?source.web.site=https://<domain1>:<port>&relation=delegate_permission/common.handle_all_urls
      

      如:

      https://digitalassetlinks.googleapis.com/v1/statements:list?source.web.site=https://baidu.com&relation=delegate_permission/common.handle_all_urls
      
  4. 代码调用

    // 这里不会跟正常的多态一样选择最合适的,只要条件满足,就会弹窗提示用选择
    // Uri.parse(scheme + "://" + host + path)
    // uri 的三阶都必须有  许多不许少,即使是你没有设置后面的两项  编也要写上
    Uri uri = Uri.parse("https://baidu.com/path");
    Intent schemeIntent = new Intent();
    schemeIntent.setAction(Intent.ACTION_VIEW);
    schemeIntent.setData(uri);
    PackageManager packageManager = getPackageManager();
    ComponentName componentName = schemeIntent.resolveActivity(packageManager);
    // 判断该协议是否存在
    if (componentName != null) {
        startActivity(schemeIntent);
    }
    

    备注:这里的不会弹框询问用户是指不会提示用户是否打开 APP 但是如果有多个符合条件的协议,仍然会提示用户选择

  5. 被打开界面解析:

    Intent intent = getIntent();
    Uri uri = intent.getData();
    if (uri != null) {
        List<String> pathSegments = uri.getPathSegments(); // 获得 path 列表  可能多层path的
        this.getIntent().getScheme();//获得Scheme名称
        this.getIntent().getDataString();//获得Uri全部路径
        String uriQuery = uri.getQuery(); // 参数字符串
        if (pathSegments != null && pathSegments.size() > 0) {
            // 解析SCHEME
    
            uri.toString(); // 全路径
            uri.getScheme(); // scheme
            uri.getHost(); // host服务器地址类型
            uri.getPort(); // 端口号
            uri.getPath(); // 路径 /path 这种
            uri.getQuery(); // 参数 ? 号后面的字符串
            uri.getQueryParameterNames(); // 获得参数key集合
            uri.getQueryParameter("key"); // 获得指定参数
            String param1 = uri.getQueryParameter("param1");
            String param2 = uri.getQueryParameter("param2");
        }
    }
    
  6. adb 测试

    格式:端口号为可选项

    adb shell am start -a android.intent.action.VIEW \
        -c android.intent.category.BROWSABLE \
        -d "http://<domain1>:<port>"
    

    例:

    adb shell am start -a android.intent.action.VIEW \
        -c android.intent.category.BROWSABLE \
        -d "http://baidu.com/path"
    
  7. 检查 links 策略

    格式:

    adb shell dumpsys package domain-preferred-apps
    --or--
    adb shell dumpsys package d
    

    结果:

    Package: com.withwings.packagedemo
    Domains: baidu.com
    Status: always : 200000002
    

    说明:

    undefined — app没有在manifest中启用链接自动验证功能。
    ask — app验证失败(会通过打开方式对话框询问用户)
    always — app通过了验证(点击这个域名总是打开这个app)
    never — app通过了验证,但是系统设置关闭了此功能。
    
  8. 备注说明:

    1. App Links 是通过配置清单注册的 host 寻找路径前去验证 assetlinks.json 文件,然后如果该 host 对应的文件验证包名为当前包名,则该 App 的 该 host 验证通过

    2. 因为 App Links 的验证是网络验证,所以才会要求接口 scheme 必须为 https / http

    3. 要求域名必须是支持 HTTPS 的,因为即使你配置的 scheme 没有 https ,它验证的文件仍然是 https 的

    4. 如果注册了多个 host 那么多个 host 对应的路径都要准备 assetlinks.json 文件

    5. APP Links 因为使用规范,如果要注意不能与正常 URL 访问路径出现冲突,这样可能会造成用户 访问该页面直接打开 APP,而没有跳转 URL (如果有这样的需求自然正好:比如 H5 主页 与 App 启动页 就可以使用同一个 URI)

    6. 如果同一域名 (host) 下有多个 APP ,可以在json数组拼接多个 字符串

相关文章

网友评论

      本文标题:Android深度链接 Deep Links 与 App Lin

      本文链接:https://www.haomeiwen.com/subject/jkurjqtx.html