
在 android 多用户场景中,需让一个计数器变量在所有用户配置文件间共享且仅限本应用读写——内部存储(internal storage)是满足安全性、隔离性与跨用户一致性的最优解。
Android 系统为每个应用分配独立的内部存储目录(Context.getFilesDir() 或 Context.getCacheDir()),该目录具有严格的沙盒权限:仅本应用进程(相同 UID)可访问,无需声明任何存储权限,且其他应用(包括同一设备上的其他用户配置文件中的同名应用)默认无法读写。关键在于:内部存储路径本身不随用户切换而隔离——当系统启用多用户时,getFilesDir() 返回的路径在所有用户下均指向同一物理位置(如 /data/data/
以下是一个安全、简洁的实现示例:
class CrossUserCounter(private val context: Context) {
private companion object {
const val COUNTER_FILE = "cross_user_counter.dat"
const val MODE_PRIVATE = Context.MODE_PRIVATE
}
fun increment(): Long {
val file = context.getFileStreamPath(COUNTER_FILE)
val current = readCounter(file)
val next = current + 1
writeCounter(file, next)
return next
}
fun get(): Long = readCounter(context.getFileStreamPath(COUNTER_FILE))
private fun readCounter(file: File): Long {
return try {
if (file.exists()) {
file.bufferedReader().use { it.readLine()?.toLongOrNull() ?: 0L }
} else {
0L
}
} catch (e: Exception) {
0L // 降级处理,避免崩溃
}
}
private fun writeCounter(file: File, value: Long) {
try {
file.bufferedWriter().use { writer ->
writer.write(value.toString())
}
} catch (e: IOException) {
// 记录错误日志,但不抛出异常
Log.e("CrossUserCounter", "Failed to write counter", e)
}
}
}✅ 优势说明:
- 安全性强:Linux UID 机制确保仅本应用可访问,无需 android.permission.WRITE_EXTERNAL_STORAGE 等危险权限;
- 跨用户有效:内部存储路径对所有用户配置文件统一,变量自然共享;
- 生命周期清晰:卸载应用时自动清除,无残留风险;
- 兼容性好:API Level 1+ 全支持,不依赖 Settings.Global(全局可见、无权限控制)或 SharedPreferences(用户隔离)。
⚠️ 注意事项:
- 避免将敏感逻辑或密钥硬编码在文件名或路径中;
- 若需并发更新(如多个进程同时调用 increment()),应引入文件锁(如 FileChannel.lock())或改用 AtomicFile(推荐)保障原子性;
- 不要误用外部存储(如 getExternalFilesDir())——其路径虽也跨用户,但权限宽松,可能被其他应用(尤其已 root)访问;
- SqlDelight 底层依赖 SQLite 数据库,若数据库存于内部存储(默认行为),则同样具备跨用户与应用私有特性;若误配至外部存储或使用 ContentProvider 暴露,则丧失隔离性。
综上,内部存储不是“妥协方案”,而是 Android 官方推荐的、面向应用私有数据的首选持久化通道。合理利用 Context.getFilesDir(),即可优雅解决多用户环境下的跨配置文件状态同步问题。










