Android APP Links 小结
介绍
最近接入Passkey和Fido2时使用了Digital Asset Links来实现网页和Android APP共享凭据,
Digital Asset Links还有个更通用的场景是在APP Links中用于网页和Android APP的关联凭证,本着来都来了,不能不到此一游的精神,写一篇关于APP Links总结。
我们经常有一种需求是从Web 页面中直接跳转到客户端应用内,在 Web 页面中唤起移动应用程序来增强功能和交互性,无论是在用户点击特定链接时打开应用程序,还是在特定条件下自动跳转到应用程序,这种无缝的切换可以帮助用户更流畅地进行操作和获取所需的信息。
Deep Links (自定义 URL Scheme)和App Links(应用链接)是实现在 Web 中唤起移动应用程序的常见技术。通过自定义 URL Scheme,开发人员可以为应用程序定义特定的 URL 格式,当用户点击相应的链接时,操作系统会尝试打开对应的应用程序。这种方法在跨平台开发中被广泛使用,可以方便地在不同移动平台上实现。这个方案在Android和iOS平台都支持。
应用链接则提供了更灵活和标准化的方式来实现在 Web 页面中唤起移动应用程序。通过在应用程序和网站之间建立关联,应用链接允许使用普通的 HTTP/HTTPS 链接来唤起应用程序,而不再需要特定的 URL Scheme。这种方法在 Android 得到了官方支持,并提供了更高的兼容性和更好的用户体验。在iOS平台相对应的方案叫做Universal Link,这部分的详情可以参考官方文档。
文章后面还补充了一种更为小众的方案:Intents with Chrome,大家也可以简单了解下。
Deep Links
URL组成:[scheme:][//authority][path][?query][#fragment]
清单文件配置
AndroidManifest.xml
中配置目标Activity
的intent-filter
data
中可以指定需要匹配的URL的scheme
, host
, path
, pathPrefix
注意:这里exported
要设置成true
,以便可以被其他应用打开,Android12开始如果Activity
配置了intent-filter
,强制要求显示设置exported
值。
<activity android:name="com.will.LoginActivity"
android:exported="true">
<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="will"
android:pathPrefix="/login" />
</intent-filter>
</activity>
接收Intent中的数据
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Intent intent = getIntent();
String action = intent.getAction();
Uri data = intent.getData();
String host = appLinkData.getHost();
String lastPathSegment = appLinkData.getLastPathSegment();
String source = appLinkData.getQueryParameter("source");
}
Web页面跳转
scheme
和path
匹配上文清单文件中的配置
window.location.href = 'will://login?source=web'
Deep Links方案的问题
-
如果定义的URL Scheme有多个APP满足的话,会弹出选择框让用户确认
-
URL来源没有做验证,只要知道APP的自定义URL Scheme,例如a标签到
mqq://
, 就可以打开QQ -
判断客户端是否成功唤起没有可靠的解决方案(通常是通过判断页面是否隐藏)
总的来说就是网页和APP之间双向都没有做身份校验,但是优点是具有通用性,对于Android和iOS来说都通用,也支持自定义Scheme。
App Links
清单文件配置
第一步同样是需要在AndroidManifest.xml
中配置目标Activity
的intent-filter
,
不同的是这次需要加上autoVerify="true"
的属性,用户安装应用时,Android 会看到包含 autoVerify
属性的 intent 过滤器,并检查指定URL是否是关联验证链接。
scheme
只支持http
或者https
action
: android.intent.action.VIEW
category
: android.intent.category.BROWSABLE
和android.intent.category.DEFAULT
<activity android:name="com.will.LoginActivity"
android:exported="true">
<intent-filter android:autoVerify="true"
tools:targetApi="m">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="http" />
<data android:scheme="https" />
<data android:host="demo.will.com"/>
</intent-filter>
</activity>
接收Intent中的数据
数据接收的部分和Deep Links方法一样处理
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Intent intent = getIntent();
String action = intent.getAction();
Uri data = intent.getData();
String host = appLinkData.getHost();
String lastPathSegment = appLinkData.getLastPathSegment();
String source = appLinkData.getQueryParameter("source");
}
Digital Asset Links配置
创建文件assetlinks.json
[{ "relation": ["delegate_permission/common.handle_all_urls"],
"target": {
"namespace": "android_app",
"package_name": "com.demo.will",
"sha256_cert_fingerprints":
["B0:4E:29:05:4E:AB:44:C6:9A:CB:D5:89:A3:A8:1C:FF:09:6B:45:00:C5:FD:D1:3E:3E:12:C5:F3:FB:BD:BA:D3"]
}
}]
json文件中包含了声明语句列表,这代表一个域名可以配置多个关联的APP,例如带有不同签名的测试版本和生产版本。
-
relation: 描述了网页和目标应用的关联关系(目标应用可以是APP,可以是其他的网页),
delegate_permission/common.handle_all_urls
表示目标应用可以打开当前网页,其他的例如delegate_permission/common.get_login_creds
表示目标应用可以获取当前的登录凭证。 -
target: 当前网页关联的目标应用,可以是
web
和android_app
-
namespace:
android_app
或者web
-
package_name: Android应用的Application Id
-
sha256_cert_fingerprints: 应用签名
-
sha256_cert_fingerprints 通常有俩种获取方式:
-
针对签名文件keystore,执行命令
keytool -list -v -keystore [my-release-key.keystore]
-
针对已经签名的APK文件,执行命令
keytool -printcert -jarfile [path-to-apk]
上传assetlinks.json
到网页
上传assetlinks.json
到你网页的指定路径下:
https://domain.name/.well-known/assetlinks.json
。
例如:Google的AssetLink地址。
网页和APP的关联验证
用户安装应用时,Android 会看到包含 autoVerify
属性的 intent 过滤器,并查看intent data
中指定URL下的.well-known
路径下的关联应用列表中是否包含当前应用,如果包含当前应用,那么Android就会认为该网页为经过验证的允许此应用打开的网络连接(.well-known
路径段通常用于存放一些标准化的元数据或配置文件,这些文件被用来提供关于网站、应用或服务的信息)。
从Android12开始,除了Android系统会在应用安装时自动验证以外,我们也可以通过ADB命令手动执行和查看关联验证,
-
手动执行验证
adb shell pm verify-app-links --re-verify PACKAGE_NAME
-
查看验证结果
adb shell pm get-app-links PACKAGE_NAME
可以看到结果显示类似
com.xxx.xxx: ID: f9a077eb-0311-4d7d-8eb7-b5e02ae462d7 Signatures: [***] Domain verification state: demo.will.com: verified
其他一些可能用到的相关ADB命令:
查看机器中的所有APP关联的APP Links
adb shell dumpsys package d
App Links方案的问题
-
Android6.0及以上支持
-
URL Scheme只支持http或者https
Intents with Chrome
另外再补充一种小众的方案,Chrome支持Android Intent的格式来唤起APP
基于Intent的URL格式
intent:
HOST/URI-path // Optional host
#Intent;
package=\[string\];
action=\[string\];
category=\[string\];
component=\[string\];
scheme=\[string\];
end;
Chrome Intents还支持设置fallback URL,如果APP无法被成功唤起时,跳转到fallback URL
S.browser_fallback_url=[encoded_full_url]
如果未设置fallback URL,目标APP未安装时会跳转到Google Play的APP下载页。
Web页面跳转
window.location.href =
'intent:#Intent;scheme=will;package=com.will.app;S.browser_fallback_url=https%3A%2F%2Fbackup.com;end'
APP端清单文件的注册和Activity中Intent的处理和上面URL Scheme处理一样。
Chrome Intents在其他浏览器测试下有俩种情况:
-
跳转到fallback URL
-
无响应
更多详情参考Chrome官网。
App Links Assistant
另外Android Studio提供了App Links Assistant 来帮助开发人员更方便的接入Deep Links以及App Links,可以通过[官网](添加 Android App Links | Android Studio | Android Developers)查看更多详情。