前言
Deep Links 与 App Links 被统称为深度链接。Deep Links 相信很多人都有用过,我记得久远之前还看过两个功能的文章,这次因为产品准备使用,所以这里就具体的对比一下,然后具体使用。
对比
差别 | Deep Links | App Links |
---|---|---|
起效时间 | 立刻起效 | 首次安装后几十秒后(需要链接网络) |
提示用户 | 提示(用户一旦勾选记住选择,会造成以后都无法唤醒App) | 不需要用户选择 |
系统要求 | 无要求 | Android 6.0 及以上版本 |
scheme问题 | 如果以 htttp/https 开头,部分手机或浏览器会当作链接打开网页 | 只允许使用 http/https 或 同时使用 |
域名注册 | 不需要域名 | 需要梯子去注册域名,并在域名内部准备验证文件 assetlinks.json |
Deep Links
使用方式
-
配置清单注册
<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>
备注:
-
data 可以注册多个 scheme ,然后拼接单独注册的 host 如:
<data android:scheme="http"/> <data android:scheme="https"/> <data android:host="www.google.com"/>
-
URI 不像多态,如果你路径定义后匹配到多个,那么则会弹出多个:比如设定了两个页面:
-
页面 A
<data android:host="com.withwings.threeactivity" android:path="/path" android:scheme="withwings" />
-
页面 B
<data android:scheme="withwings" />
此时如果调用 withwings://com.withwings.threeactivity/path 则 两个页面都会相应
-
-
虽然 data 标签是拆开的,但是实际组合是根据所有的 scheme 等 混合拼接的,不会根据标签分组,当然,使用多个 data 会看起来比较清晰
-
-
代码调用
// 这里不会跟正常的多态一样选择最合适的,只要条件满足,就会弹窗提示用选择 // Uri.parse(scheme + "://" + host + path) // uri 的三阶都必须有 许多不许少,即使是你没有设置后面的两项 编也要写上 Uri uri = Uri.parse("withwings://com.withwings.threeactivity/path?param1=abc¶m2=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); }
-
被打开界面解析:
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"); } }
-
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 \
注意事项
-
通过路由不能将 category 设置为 LAUNCHER
-
scheme 如果以 htttp/https 开头,部分手机或浏览器会当作链接打开网页
-
最好在配置清单注册 Uri 的时候,最好还是都完成三级注册
-
如果同一个 Activity 下有配置多个 host ,则需要通过不同的 Intent Filter 设置
App Links
App Links 属于 6.0 新特性:当用户点击对应 URI 时会直接启动对应 APP,不会有跟 Deep Links 一样的弹窗出现
官网说明
优势
-
安全,因为是精确到您自己的网站域名,所以没有其他应用可以使用您的链接!
-
无缝的用户体验:只要您自己没有注册重复的 URI 接收页面,则我们可以保证,有安装时访问您的 APP,没有安装时访问对应 URL 的网址
-
可以支付 Instant Apps (Google 的小程序)
-
可以通过网页为 APP 引流,吸引用户
使用方式
-
配置清单注册
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 安装后自动验证
注意:
-
如果是在启动页,请不要与启动页的 intent-filter 放在一起
-
一个正常的 Uri 格式
scheme://host:port/path or pathPrefix or pathPattern
-
path、pathPrefix、pathPattern 之间的区别
-
path 用来匹配完整的路径,如:http://example.com/blog/abc.html,这里将 path 设置为 /blog/abc.html 才能够进行匹配;
-
pathPrefix 用来匹配路径的开头部分,拿上面的 Uri 来说,这里将 pathPrefix 设置为 /blog 就能进行匹配了;
-
pathPattern 用表达式来匹配整个路径,这里需要说下匹配符号与转义。
-
匹配符号:
-
“” 用来匹配0次或更多,如:“a” 可以匹配“a”、“aa”、“aaa”...
-
“.” 用来匹配任意字符,如:“.” 可以匹配“a”、“b”,“c”...
-
因此 “.” 就是用来匹配任意字符0次或更多,如:“.html” 可以匹配 “abchtml”、“chtml”,“html”,“sdf.html”...
-
-
转义:
因为当读取 Xml 的时候,“\” 是被当作转义字符的(当它被用作 pathPattern 转义之前),因此这里需要两次转义,读取 Xml 是一次,在 pathPattern 中使用又是一次。如:“” 这个字符就应该写成 “\”,“\” 这个字符就应该写成 “\\”。
-
-
-
-
注册 assetlinks.json
-
填写host,包名,fingerprint
-
Hosting site domain: 为服务器域名请不要添加 www 有部分手机添加后会发现无法验证
baidu.com
-
App package name: APP 包名
-
App package fingerprint (SHA256): keystore 使用的 sha256,可以通过以下命令获取
keytool -list -v -keystore my-release-key.keystore
-
-
然后点击Generate Statement生成assetlinks.json
-
将生成的文字存储在 assetlinks.json
-
assetlinks.json 存储在服务器指定位置,如:
https://host路径/.well-known/assetlinks.json
-
点击 Test Statement
Success!…… 代表验证成功
-
国内生成 assetlinks.json
-
手动拼写文件 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
-
assetlinks.json 存储在服务器指定位置,如:
https://host路径/.well-known/assetlinks.json
-
手动测试
访问路径:
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
-
-
代码调用
// 这里不会跟正常的多态一样选择最合适的,只要条件满足,就会弹窗提示用选择 // 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 但是如果有多个符合条件的协议,仍然会提示用户选择
-
被打开界面解析:
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"); } }
-
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"
-
检查 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通过了验证,但是系统设置关闭了此功能。
-
备注说明:
-
App Links 是通过配置清单注册的 host 寻找路径前去验证 assetlinks.json 文件,然后如果该 host 对应的文件验证包名为当前包名,则该 App 的 该 host 验证通过
-
因为 App Links 的验证是网络验证,所以才会要求接口 scheme 必须为 https / http
-
要求域名必须是支持 HTTPS 的,因为即使你配置的 scheme 没有 https ,它验证的文件仍然是 https 的
-
如果注册了多个 host 那么多个 host 对应的路径都要准备 assetlinks.json 文件
-
APP Links 因为使用规范,如果要注意不能与正常 URL 访问路径出现冲突,这样可能会造成用户 访问该页面直接打开 APP,而没有跳转 URL (如果有这样的需求自然正好:比如 H5 主页 与 App 启动页 就可以使用同一个 URI)
-
如果同一域名 (host) 下有多个 APP ,可以在json数组拼接多个 字符串
-
网友评论