You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

同sharedUserId下EncryptedSharedPreferences失效,如何让双应用各用独立实例?

解决同sharedUserId下EncryptedSharedPreferences密钥冲突的方案

核心思路

同android:sharedUserId的应用会共享系统默认密钥库,导致EncryptedSharedPreferences的Master Key互相覆盖冲突。要让两款应用独立使用加密存储,关键是让它们的Master Key完全隔离,同时保留sharedUserId用于数据交互。

方案1:为Free/Pro指定独立的Master Key别名

EncryptedSharedPreferences默认使用固定别名生成Master Key,同sharedUserId下会产生冲突。为两款应用分别设置唯一的Master Key别名即可解决:

  • Free版代码示例:
// 生成Free专属的Master Key别名
val freeMasterKeyAlias = MasterKeys.getOrCreate(MasterKeys.AES256_GCM_SPEC, "free_app_unique_master_key")
// 创建Free版的加密SharedPreferences
val freeEncryptedPrefs = EncryptedSharedPreferences.create(
    "free_secure_prefs",
    freeMasterKeyAlias,
    context,
    EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
    EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
)
  • Pro版代码示例:
// 生成Pro专属的Master Key别名
val proMasterKeyAlias = MasterKeys.getOrCreate(MasterKeys.AES256_GCM_SPEC, "pro_app_unique_master_key")
// 创建Pro版的加密SharedPreferences
val proEncryptedPrefs = EncryptedSharedPreferences.create(
    "pro_secure_prefs",
    proMasterKeyAlias,
    context,
    EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
    EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
)

这个方法最简单有效,两款应用的Master Key会在共享密钥库中以不同别名存储,互不干扰。

方案2:自定义密钥库存储路径(备选)

如果别名方案仍有冲突,可以彻底隔离密钥库文件:
为Free和Pro分别指定不同的密钥库存储路径(比如各自应用的私有文件目录),然后基于自定义KeyStore创建Master Key。示例逻辑:

// Free版自定义KeyStore加载
val freeKeyStoreFile = File(context.filesDir, "free_keystore.bks")
val freeKeyStore = KeyStore.getInstance("BKS")
freeKeyStore.load(FileInputStream(freeKeyStoreFile), "free_keystore_password".toCharArray())
// 基于自定义KeyStore生成Master Key并创建EncryptedSharedPreferences
// 后续逻辑类似方案1,只是使用自定义KeyStore来管理密钥

Pro版同理使用pro_keystore.bks作为密钥库文件,完全隔离存储。

方案3:迁移时精准读取Free版加密数据

在Pro版执行迁移操作时,必须使用Free版的Master Key别名和SharedPreferences名称来读取数据:

// Pro版中获取Free应用的上下文
val freeContext = context.createPackageContext("com.yourpackage.free", Context.CONTEXT_IGNORE_SECURITY)
// 使用Free版的Master Key别名读取加密配置
val freeMasterKeyAlias = MasterKeys.getOrCreate(MasterKeys.AES256_GCM_SPEC, "free_app_unique_master_key")
val freeEncryptedPrefs = EncryptedSharedPreferences.create(
    "free_secure_prefs",
    freeMasterKeyAlias,
    freeContext,
    EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
    EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
)
// 读取并迁移密码
val userPassword = freeEncryptedPrefs.getString("saved_password", null)
// 写入Pro版的加密存储
val proMasterKeyAlias = MasterKeys.getOrCreate(MasterKeys.AES256_GCM_SPEC, "pro_app_unique_master_key")
val proEncryptedPrefs = EncryptedSharedPreferences.create(
    "pro_secure_prefs",
    proMasterKeyAlias,
    context,
    EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
    EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
)
proEncryptedPrefs.edit().putString("saved_password", userPassword).apply()

注意事项

  • 确保两款应用的android:sharedUserId保持一致,才能正常进行跨应用数据读取。
  • 已经发布的Free版用户,需要确保迁移逻辑能兼容旧版本的加密存储(如果之前用的是默认别名,迁移时要先尝试默认别名读取,再切换到新别名)。

内容的提问来源于stack exchange,提问作者almisoft

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.09 16:18:17