“应用完全离线,所以数据只在本机”并不总是成立。面向 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,并把卸载恢复纳入持续测试,才能同时获得可信的隐私边界和不丢进度的换机体验。