Android 离线应用的备份边界:恢复体验与隐私如何兼得
“应用完全离线,所以数据只在本机”并不总是成立。面向 Android 6.0 及以上版本的应用通常默认参与 Auto Backup;系统可能把应用私有目录中的文件上传到用户的云端备份,也可能在换机时执行设备到设备迁移。应用没有联网权限,也不能自动推出“永远不会离开设备”。
这不是要求所有应用关闭备份。正确目标是恢复用户真正关心的进度与设置,同时排除凭据、设备标识、缓存和无法安全迁移的数据。
先按语义分类,不要按目录猜测
建立备份规则前,先为每类数据回答“新设备恢复后是否仍然有效”:
| 数据 | 常见策略 | 原因 |
|---|---|---|
| 游戏进度、用户创建内容 | 备份 | 难以重建,用户价值高 |
| 主题、难度、无障碍偏好 | 备份 | 恢复后仍有效 |
| 缓存、缩略图、临时导出 | 排除 | 可以重建,只浪费配额 |
| 登录令牌、会话密钥 | 排除 | 恢复到另一设备可能不安全或已失效 |
| FCM token、设备 ID | 排除 | 与原设备绑定,恢复后会造成错误行为 |
| 外部文件 URI | 通常排除 | 新设备上的 URI 可能失效或指向其他内容 |
Android 官方给 Auto Backup 的文件配额是每个应用 25 MB。即使数据不敏感,把可重新下载的资源放进去也会挤占真正重要的内容。
同时配置新旧两套规则
以 API 31 及以上为目标的应用,在 Android 12 及以上设备使用 data-extraction-rules。但为了覆盖 Android 11 及更早设备,仍需提供旧格式的 fullBackupContent:
<application
android:allowBackup="true"
android:fullBackupContent="@xml/backup_rules"
android:dataExtractionRules="@xml/data_extraction_rules" />
新格式可以分别决定云备份和设备迁移包含什么:
<?xml version="1.0" encoding="utf-8"?>
<data-extraction-rules>
<cloud-backup disableIfNoEncryptionCapabilities="true">
<include domain="file"
path="datastore/user_settings.preferences_pb" />
<include domain="database" path="progress.db" />
</cloud-backup>
<device-transfer>
<include domain="file"
path="datastore/user_settings.preferences_pb" />
<include domain="database" path="progress.db" />
</device-transfer>
</data-extraction-rules>
一旦使用 <include>,默认全选会变成白名单模式。这个特性比列举所有敏感文件更稳健:未来新增文件不会在没有审查的情况下自动进入备份。旧格式也应表达同一份策略,避免不同系统版本得到相反结果。
把敏感设置拆到独立文件
如果一个 DataStore 同时保存主题颜色和认证材料,XML 只能把整个文件纳入或排除。更好的结构是把可迁移设置与敏感本地状态放进不同 DataStore,再分别制定规则。Room 数据库也一样:用户进度与可重建缓存不应混在一个无法拆分的数据库中。
noBackupFilesDir 适合明确不允许备份的文件,缓存目录则天然不进入 Auto Backup。存储位置本身就是隐私设计的一部分,不应等发布前才用一大串排除规则补救。
云备份与换机迁移不是同一威胁模型
<cloud-backup> 数据会进入远端备份服务,<device-transfer> 用于设备间迁移。某些大型本地资源不适合占用云配额,但在两台设备直接传输时仍然有价值;有些凭据则两种方式都不应该迁移。
是否允许无加密能力时进行云备份,可以用 disableIfNoEncryptionCapabilities 约束。它不能替代数据分类:有加密不代表所有令牌都适合在另一台设备恢复。
恢复代码必须面对版本差异
备份数据可能由较旧版本创建,却在新版本安装时恢复。Room migration、DataStore schema 和业务默认值都要支持这种顺序。恢复过程还应满足幂等性:系统重复触发或应用首次启动再次初始化时,不应覆盖刚恢复的数据。
恢复后重新生成设备相关值,验证账号会话是否仍然有效,并把缺失的缓存视为正常情况。不要让应用依赖“备份一定成功”;设备可能没有登录 Google 账号、没有满足网络条件,或用户关闭了备份。
用真实卸载与恢复验证规则
仅查看 XML 无法证明规则正确。官方测试流程使用 bmgr 触发备份,再卸载、重装并恢复应用。最小检查包括:
adb shell bmgr enable true
adb shell bmgr backupnow com.example.app
测试设备需要配置可用的备份 transport。完整测试应准备有意义的设置和进度,执行备份、清除应用、重新安装,然后逐项核对:应保留的数据是否存在,应排除的 token 与设备 ID 是否重新生成,数据库能否迁移,应用在没有缓存时能否启动。
测试矩阵至少覆盖当前系统与一个 Android 11 或更早版本,因为两套 XML 规则可能漂移。每次改变 DataStore 文件名、Room 数据库名或存储目录时,都应重新执行恢复测试。
隐私政策要描述系统备份
如果应用声明“不上传数据”,还应解释 Android 系统可能根据用户设备设置执行加密云备份或设备迁移,以及开发者是否能直接访问这些备份。措辞要区分应用主动上传、操作系统备份和用户手动导出,避免把三种数据流混成一句模糊承诺。
离线应用的隐私优势来自更少的主动数据流,但系统级备份仍然是一条真实路径。用白名单规则选择高价值数据、拆分敏感存储、兼容新旧 XML,并把卸载恢复纳入持续测试,才能同时获得可信的隐私边界和不丢进度的换机体验。