Android凭据共享:解决跨应用密码同步难题
2024-12-24 20:14:30
Android凭据管理器应用间密码共享
应用间共享用户凭据(例如用户名和密码)的需求,在某些情况下颇为常见,例如同一服务商的不同客户端应用。Android凭据管理器提供了一套机制来实现这种共享。但开发者在实践过程中可能会遇到问题,原因通常在于配置不当。 本文将分析凭据共享过程中的一些常见问题,并给出相应的解决方案。
问题分析
要使多个应用之间能够共享凭据,需要在以下几个方面进行正确的设置:
assetlinks.json
文件 : 必须在服务器上托管assetlinks.json
文件,其中包含应用之间的关系声明。- 应用签名 : 应用的签名指纹(SHA256)必须与
assetlinks.json
文件中声明的签名指纹匹配。 asset_statements
: 每个应用需要在其 manifest 文件中指定asset_statements
元数据,并引用assetlinks.json
文件的路径。- Intent Filter : 应用需要一个合适的 Intent Filter,允许系统验证
assetlinks.json
。 - 凭据管理API调用 : 应用需要使用 Android 提供的凭据管理 API 正确地读取和保存凭据。
如果以上任何一个环节存在问题,凭据共享功能就会失效。
解决方案
检查 assetlinks.json
文件
-
问题:
assetlinks.json
文件配置不正确或服务器托管问题,会导致应用无法正确识别彼此的关联。 -
解决方案:
- 确保
assetlinks.json
文件格式正确,且所有target
中的package_name
和sha256_cert_fingerprints
与实际应用的完全匹配。 特别是sha256_cert_fingerprints
, 如果是 debug 应用,要使用 debug 的 key, 发布的应用使用发布 key。 relation
字段必须设置为delegate_permission/common.get_login_creds
, 否则凭据共享将无法正常运作。- 检查托管
assetlinks.json
文件的 URL 可通过 HTTPS 访问,并且文件放置在.well-known
目录下。
- 确保
-
示例 : 一个正确的
assetlinks.json
文件如下:[ { "relation": [ "delegate_permission/common.get_login_creds" ], "target": { "namespace": "android_app", "package_name": "com.practice.app1", "sha256_cert_fingerprints": [ "B0:99:5C:C8:07:12:8E:62:D6:99:D7:54:B2:FC:D8:AA:F4:A2:13:94:A8:38:22:D1:D3:40:59:5E:16:C3:69:8F" ] } }, { "relation": [ "delegate_permission/common.get_login_creds" ], "target": { "namespace": "android_app", "package_name": "com.practice.app2", "sha256_cert_fingerprints": [ "B0:99:5C:C8:07:12:8E:62:D6:99:D7:54:B2:FC:D8:AA:F4:A2:13:94:A8:38:22:D1:D3:40:59:5E:16:C3:69:8F" ] } } ]
-
操作步骤
- 获取应用的 SHA256 指纹。 可以通过
keytool
命令来获取 (例如:keytool -printcert -v -file "path/to/your/keystore.jks"
)。 - 更新
assetlinks.json
的对应sha256_cert_fingerprints
和package_name
。 - 确保
assetlinks.json
能通过https协议访问到。
- 获取应用的 SHA256 指纹。 可以通过
验证应用签名
- 问题 : 应用的签名指纹和
assetlinks.json
中定义的指纹不匹配会导致验证失败。 - 解决方案: 确保应用的 SHA256 证书指纹与
assetlinks.json
文件中记录的指纹完全一致。调试构建(debug)与发布构建(release)使用的签名可能不同。 - 操作步骤 :
- 使用
keytool
命令查看应用程序签名证书的 SHA256 指纹,如上一部分所述。 - 确认所生成的指纹是否与
assetlinks.json
中使用的指纹一致。如不一致,更新assetlinks.json
或者用对应的证书签名app.
配置 asset_statements
-
问题 :
asset_statements
配置错误,可能导致系统无法验证凭据的关联。 -
解决方案:
- 确保
asset_statements
的值是一个有效的 JSON 字符串,包含include
字段,指向assetlinks.json
文件的 HTTPS 地址。 - 在 Android Manifest 中声明
asset_statements
元数据:
<meta-data android:name="asset_statements" android:resource="@string/asset_statements"/>
- 确保
strings.xml
文件中配置了asset_statements
。
<string name="asset_statements" translatable="false"> [{ \"include\": \"https://<git-hub-name>.github.io/.well-known/assetlinks.json\" }] </string>
- 确保
-
操作步骤
- 在 app 的
strings.xml
文件中添加asset_statements
string资源,务必填写正确的 url,include
指向托管的assetlinks.json
地址。 - 在 Manifest 文件中注册这个 resource, 上面的示例代码中给出。
设置 Intent Filter
-
问题 : Intent filter 配置不正确,会导致系统无法自动验证
assetlinks.json
,或者在验证过程中发生错误。 -
解决方案 :
- 使用
android:autoVerify="true"
以便在安装应用程序时尝试验证assetlinks.json
文件,减少验证步骤,优化用户体验。 - 配置带有
android.intent.action.VIEW
,android.intent.category.DEFAULT
,android.intent.category.BROWSABLE
这些 action 和 category 的 intent filter, 并指定http
或https
以及assetlinks.json
所在的域名。
<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" /> <data android:scheme="http" /> <data android:scheme="https" /> <data android:host="<git-hub-name>.github.io" /> </intent-filter>
- 使用
-
操作步骤
- 在每个需要参与共享凭据的应用的 AndroidManifest.xml 中添加 Intent Filter, 并修改
<data>
中的 host 部分以匹配你assetlinks.json
的地址。
凭据API的使用
-
问题 : 使用凭据管理API时,没有正确设置请求或者处理响应,也会造成共享失败。
-
解决方案:
-
确保通过
CredentialManager.create()
方法获取 CredentialManager 实例。 -
创建
GetCredentialRequest
时,必须指定密码凭据类型:GetPasswordOption()
。 -
妥善处理请求的各类异常。
-
使用正确的凭据ID从凭据管理器获取数据:凭据保存时的凭据ID就是
PasswordCredential
的 ID 属性。 -
示例代码:
private val credentialManager = CredentialManager.create(activity) suspend fun signIn(): SignInResult { return try { val credentialResponse = credentialManager.getCredential( context = activity, request = GetCredentialRequest( credentialOptions = listOf(GetPasswordOption()) ) ) val credential = credentialResponse.credential as? PasswordCredential ?: return SignInResult.Failure //使用credential.id和credential.password进行登录操作 SignInResult.Success(credential.id) } catch(e: GetCredentialCancellationException) { e.printStackTrace() SignInResult.Cancelled } catch(e: NoCredentialException) { e.printStackTrace() SignInResult.NoCredentials } catch(e: GetCredentialException) { e.printStackTrace() SignInResult.Failure } }
-
操作步骤 :
- 确保已经在你的app module 添加 credential-manager 的依赖:
implementation("androidx.credentials:credentials:1.0.0-alpha02")
。 - 参照上面的kotlin代码, 使用
credentialManager
来访问存储在手机中的凭据.
- 确保已经在你的app module 添加 credential-manager 的依赖:
其他建议
- 考虑数据安全:在应用之间共享敏感信息时,应该充分考虑数据的加密存储和传输,避免数据泄露。可以使用 KeyStore 系统来加密保存数据。
- 测试方法:建议使用
adb
工具来进行关联测试:adb shell pm get-app-links com.example.app
. 在没有配置autoVerify="true"
时,系统会调用https://<git-hub-name>.github.io/.well-known/assetlinks.json
去检查应用之间的联系。
遵循以上方案,可有效解决 Android 凭据管理器应用间密码共享的问题。正确的配置不仅能够提高开发效率,也能改善用户的使用体验,提升应用的整体安全级别。