1. 场景

很多app (如电商类app: 某宝、某东等)为了引流或者增加曝光率,在浏览器、邮件、信息等地方点击一条链接就能打开app。如:一些浏览器网页上挂着一些商品链接,点开链接,在链接的详情会提示打开app或者下载app。如果本地有安装app,则直接可以打开本地app 的商品页面。

2. 实现技术

深层链接 或者 Android 应用链接

3. 例子实现效果

Android 浏览器选择文件 android 浏览器跳转app_Android 浏览器选择文件

4. 深层链接实现

4.1 添加 Intent 过滤器

浏览器调起用的链接会跟 Android 系统 Intent 进行匹配。若本地应用存在匹配的 Intent,会隐式打开当前匹配合适的 activity,并启动该 activity,从而实现打开 app

// 在activity 中添加<intent-filter>(过滤器),设置方式如下:
<activity ...>
        <intent-filter>
            <action android:name="android.intent.action.VIEW" />
            <category android:name="android.intent.category.DEFAULT" />
            <category android:name="android.intent.category.BROWSABLE" />
            <!-- 接受以“test://open.my.app/launch/app” 开头的uri -->
            <data android:scheme="test"
                  android:host="open.my.app"
                  android:pathPrefix="/launch/app" />
        </intent-filter>
        
</activity>

intent 过滤器

  • < action >
    指定 “android.intent.action.VIEW” ,必须这样写。
  • < category >
    指定 “android.intent.category.DEFAULT”,必须这样写。这样应用才可以响应隐式 Intent
    指定 “android.intent.category.BROWSABLE”,必须这样写。网络浏览器中访问 Intent
    过滤器,就必须提供该类别。否则,在浏览器中点击链接便无法解析为您的应用
  • < data >
    可以添加一个或者多个 标记。每个标记都代表一个解析为 ActivityURI 格式。 标记必须至少包含 android:scheme (协议)属性,scheme 属性值可以为http、https,也可以自定义(如上面的“test”)android:path (路径)属性前缀必须添加斜杠 “/”android:host 域名

注意事项:

  1. 如果想声明唯一网址(例如特定的 schemehost 组合),推荐使用单独创建的过滤器(一个过滤器(Intent-filter)中只包含一个 < data > )。
  2. 同一 Intent-filter 元素中存在多个 < data> 元素会合并成多种组合。如:
<intent-filter>
    ...
    <data android:scheme="https" android:host="www.test.com" />
    <data android:scheme="test" android:host="open.my.app" />
</intent-filter>

上面<data>会匹配4种前缀格式:https://www.test.com | test://open.my.app | test://www.test.com | https://open.my.app

4.2 读取传入 intent 中的数据

启动 activity(该activity一般只做为中转,不展示内容) 后,可以从 activity 获取 intent 中传入的数据,进行特定页面的跳转。

如:从浏览器网页的商品详情页直接打开app,并跳转到app的商品详情页。

@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        try {
            Intent intent = getIntent();
            if (intent != null) {
                //  test://open.my.app/launch/app?type=1
                String metaData = intent.getDataString();
                int type = 0;
                String packeName = getPackageName();
                if (metaData != null && !TextUtils.isEmpty(packeName)) {
                    Pattern pattern = Pattern.compile("([^&?]*)");
                    Matcher matcher = pattern.matcher(metaData);
                    while (matcher.find()) {
                        String group = matcher.group();
                        if (!group.contains(getPackageName())) {
                            String[] param = group.split("=");
                            if (group.contains("type")) {
                                type = Integer.parseInt(param[1]);
                            }
                        }
                    }
                    if (type == 1) {
                        //打开详情页
                        
                    } else {
                        //默认启动首页
                        
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        finish();
    }

至此,app 的深层链接已经实现。在网页中请求调用 URI intent,对应的app就会被拉起来。
为了更好的用户体验,谷歌推荐遵循以下做法:

  • 被拉起的app直接转到相应内容,而不会出现任何提示、转到任何插页式网页或登录页。确保用户即使之前从未打开过相应应用,也可以查看应用内容。您可以在后续互动中或在用户从启动器中打开应用时进行提示。
  • 遵循使用“返回”和“向上”导航中所述的设计指南,确保您的应用能达到用户通过深层链接进入您的应用后对向后导航体验的预期。

4.3 对深层链接进行测试

方式1:通过浏览器拉起app进行验证

这种方法是模拟实际情况来测试是否能真正拉起app并跳转特定页面。

  1. 新建一个 html文件名为 test.html,仅仅是作为测试使用,所以内容比较简单,仅仅展示超链接文字即可。 内容如下:
<!DOCTYPE html>
<html>
<head>
	<title></title>
</head>

<body>
<div id="write" class="is-node">
	<p> </p>
	<p> </p>
	<p> </p>
	<p> </p>
	<h2>
		<a href="test://open.my.app/launch/app?type=1" target="_blank">打开app详情页面</a> 
	</h2>
	<p> </p>
	<p> </p>
	<p> </p>
	<p> </p>
	<h2>
		<a href="test://open.my.app/launch/app?type=-1" target="_blank">打开app</a> 
	</h2>
</div>
</body>
</html>
  1. test.html 发布到服务器,可以自行在本地搭建一个测试服务器。
  2. 在浏览器上打开链接到 test.html 的地址,点击链接文字即可打开本地app,若不能拉起则检查配置是否完整。

方式2:Android ADB与Android 管理器工具结合使用。

测试前提条件:本地安装Android ADB和管理工具,测试机确保已经连接电脑。
这种方法无需自行编写 html,也无需搭建服务器,在命令行就可调试。

// 在命令行工具运行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 "test://open.my.app/launch/app" com.test.android

5. Android 应用链接实现

Android 应用链接是一种特殊类型的深层链接。

5.1 添加 Intent 过滤器

<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" />
        <!--scheme 属性值必须为 http 或 https  -->
        <data android:scheme="http" android:host="www.test.com" />
        <data android:scheme="https" />
    </intent-filter>

</activity>

intent 过滤器

  • android:autoVerify="true"
    intent 过滤器上存在 android:autoVerify=“true” 时,在 Android 6.0 及更高版本的设备 上安装的app会自动到所列的 host 中做验证。如果验证成功,该app 将成为匹配 URI 默认打开方式。
  • < action>
    指定 “android.intent.action.VIEW” ,必须这样写。
  • < category>
    指定 “android.intent.category.DEFAULT”,必须这样写。这样应用才可以响应隐式 Intent
    指定 “android.intent.category.BROWSABLE” ,必须这样写。网络浏览器中访问 Intent
    过滤器,就必须提供该类别。否则,在浏览器中点击链接便无法解析为您的应用
  • < data>
    可以添加 一个或者多个< data> 标记。每个标记都代表一个解析为 ActivityURI 格式。< data> 标记必须至少包含 android:scheme 属性,scheme 属性值必须为 http 或 httpsandroid:path 属性前缀必须添加斜杠 "/"

5.2 读取传入 intent 中的数据

与深层链接的处理方式一致

5.3 配置 assetlinks.json

5.3.1 生成 assetlinks.json。

选择以下其中一种方式生成即可。

  1. 如果你可以科学上网,访问 这里

配置 【Hosting site domain】=> host
【App package name】=>应用包名
【App package fingerprint (SHA256)】=>app指纹证书(获取指纹证书)。
然后点击 【Generate Statement】 即可生成 assetlinks.json 内容。

Android 浏览器选择文件 android 浏览器跳转app_json_02

  1. 如果无法科学上网,可以手动生成 assetlinks.json
  • 创建 assetlinks.json 文件
  • 拷贝以下内容

[{ "relation": ["delegate_permission/common.handle_all_urls"], "target" : { "namespace": "android_app", "package_name": "com.test.app", "sha256_cert_fingerprints": >["14:6D:E9:83:C5:73:06:50:D8:EE:B9:95:2F:34:FC:64:16:A0:83:42:E6:1D:BE:A8:8A:04:9>6:B2:3F:CF:44:E5"] } }]

  • 修改其中的 package_namesha256_cert_fingerprints 即可。

5.3.2 部署 assetlinks.json

assetlinks.json 文件部署到网站的 .well-known 目录下。如:hostwww.test.com,那么就将 assetlinks.json 放到 https://www.test.com/.well-known/assetlinks.json

5.3.3 测试 assetlinks.json

  1. 如果是测试现有的语句文件,打开 测试器工具,配置好相关参数,点击【Test statement】即可测试。如果返回 success, 代表测试成功。
  2. 可以使用 Digital Asset Links API 测试是否已正确托管和定义 assetlinks.json 文件。
// 替换host 和 optional_port

 https://digitalassetlinks.googleapis.com/v1/statements:list?
       source.web.site=https://host:optional_port&
       relation=delegate_permission/common.handle_all_urls

5.4 测试应用链接

  • 测试网址 intent
adb shell am start -a android.intent.action.VIEW \
    -c android.intent.category.BROWSABLE \
    -d "http://domain.name:optional_port"
  • 测试链接政策
//执行
adb shell dumpsys package domain-preferred-apps
// 或者
adb shell dumpsys package d

输出类似结果:
    Package: com.android.vending
    Domains: play.google.com market.android.com
    Status: always : 200000002
/**
 * Package - 以软件包名称标识应用,与应用清单文件中声明的内容一致。
 * Domains - 链接的host 列表,使用空格作为分隔符。上面结果表示app会链接play.google.com 和market.android.com两个域名的URI
 * Status - 显示该应用的现有链接处理设置,已通过验证并且清单文件中包含 android:autoVerify="true" 的应用会显示 always 状态
 **/

执行以上命令可以获取已连接设备上所有应用的现有链接处理列表。

注意:确保在安装应用后等待至少 20 秒,以让系统完成验证流程。

6. 深度链接和应用链接的区别

  1. 本质

深度链接是一种 intent 过滤器。
应用链接是一种特殊的深度链接,基于已验证的网站网址。

  1. 用户体验
  • 深度链接
    在询问用户是否app打开时,如果用户选择了“取消”,那么下次再想点击链接打开app时,将不会有反应。
    当点击链接,而本地有多个app 匹配时,会弹出“应用选择弹框”,用户必须选择对应的应用才能打开app。
  • 应用链接
    直接打开匹配的应用,不会出现对话框。
  1. 兼容性

深度链接兼容所有 Android 版本,应用链接只兼容Android 6.0 及更高版本。

  1. 开发难度

相比深度链接,应用链接更加繁琐。

需要在过滤器添加 android:autoVerify=“true”

< data> 中的 android:scheme 属性必须为 “http 或者 https”

需要配置 assetlinks.json