Android 9/10中Encrypted SharedPreferences引发ANR的问题如何解决?
问题根因
你遇到的ANR是Android 9、10系统KeyStore实现的已知问题:cipher.init 内部调用CompletableFuture.get() 会阻塞当前线程,在主线程同步初始化EncryptedSharedPreferences时,KeyStore操作耗时过长就会触发ANR。
可行解决方案
- 优先级最高:将EncryptedSharedPreferences初始化逻辑移到子线程异步执行,禁止在Application.onCreate的主线程中同步调用。
可参考以下Kotlin实现示例:
// IO线程预初始化加密SP private var securedPref: SharedPreferences? = null private val initJob = CoroutineScope(Dispatchers.IO).launch { val masterKey = MasterKey.Builder(context) .setKeyScheme(MasterKey.KeyScheme.AES256_GCM) .build() securedPref = EncryptedSharedPreferences.create( context, prefName, masterKey, EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV, EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM ) } // 对外提供suspend访问方法,调用方需在非主线程执行 suspend fun getSecuredSharedPref(): SharedPreferences { initJob.join() return securedPref!! }
- 升级依赖版本:将AndroidX Security加密库升级到
androidx.security:security-crypto:1.1.0及以上版本,官方在后续版本中调整了KeyStore初始化逻辑,规避了Android 9/10的阻塞问题。 - 临时降级方案:如果暂时无法做异步改造,可将MasterKey的加密方案从AES256_GCM改为AES128_GCM,可大幅降低初始化阻塞时长,代码示例:
val masterKey = MasterKey.Builder(context) .setKeyScheme(MasterKey.KeyScheme.AES128_GCM) .build()
额外注意事项
- 加密SharedPreferences的读写操作本身也有加密计算耗时,所有读写操作也建议放到子线程执行,避免主线程耗时过高触发ANR
- 不要在ContentProvider中初始化加密SP,ContentProvider执行时机早于Application.onCreate,同样运行在主线程,也会触发相同的ANR问题
- 对敏感等级不高的数据可考虑降级使用普通SharedPreferences存储,减少加密SP的使用频次
内容的提问来源于stack exchange,提问作者nilkash
相关产品推荐
相关产品推荐

