使用自动备份备份用户数据

面向应用的自动备份 会自动备份目标平台为 Android 6.0(API 级别 23)或更高版本并在其上运行的应用的用户数据。Android 通过将应用数据上传到用户的 Google 云端硬盘来保留应用数据,并在 Google 账号凭据的保护下安全地存储数据。在运行 Android 9 或更高版本的设备上,备份使用设备的 PIN、图案或密码进行端到端加密。每个应用的用户可以分配最多 25MB 的备份数据。存储备份数据不收费。您的应用可以通过停用备份来自定义备份过程或选择退出。

如需了解 Android 的备份选项以及有关备份和恢复哪些数据的指南,请参阅数据备份概览

备份的文件

默认情况下,自动备份包含系统分配给应用的大部分目录中的文件

自动备份会排除 getCacheDir()getCodeCacheDir()getNoBackupFilesDir() 返回的目录中的文件。这些位置中保存的文件仅是临时需要,因此特意从备份操作中排除。

您可以配置应用以包含和排除特定文件。如需了解详情,请参阅包含和排除文件部分。

备份位置

备份数据存储在用户 Google 云端硬盘账号的一个私有文件夹中,每个应用的限制为 25MB。保存的数据不计入用户的个人 Google 云端硬盘配额。仅存储最近一次备份。进行备份时,会删除所有以前的备份。用户或设备上的其他应用无法读取备份数据。

用户可以在 Google 云端硬盘 Android 应用中看到已备份的应用列表。在 Android 设备上,用户可以在云端硬盘应用的导航抽屉中找到此列表,路径为 设置 > 备份和重置

每个设备设置生命周期的备份存储在不同的数据集中,如以下示例所述

  • 如果用户拥有两台设备,则每台设备都有一个备份数据集。

  • 如果用户对设备进行恢复出厂设置,然后使用同一账号设置设备,则备份会存储在一个新的数据集中。废弃的数据集会在一段时间不活动后自动删除。

备份计划

满足所有以下条件时,备份会自动发生

  • 用户已在设备上启用备份。在 Android 9 中,此设置位于 设置 > 系统 > 备份
  • 距离上次备份至少已过去 24 小时。
  • 设备处于空闲状态。
  • 设备连接到 Wi-Fi 网络(如果设备用户尚未选择使用移动数据备份)。

实际上,这些条件大约每天晚上都会出现,但设备可能永远不会备份(例如,如果它从未连接到网络)。为了节省网络带宽,只有当应用数据发生变化时才会进行上传。

在自动备份期间,系统会关闭应用以确保它不再写入文件系统。默认情况下,备份系统会忽略在前台运行的应用,以避免糟糕的用户体验。您可以通过将 android:backupInForeground 属性设置为 true 来覆盖默认行为。

为了简化测试,Android 提供了允许您手动启动应用备份的工具。如需了解详情,请参阅测试备份和恢复

恢复计划

无论是从 Play 商店安装应用、在设备设置期间(系统安装之前安装的应用),还是通过运行 adb install 安装应用,数据都会在应用安装时恢复。恢复操作发生在 APK 安装之后,但在应用可供用户启动之前。

在初始设备设置向导中,系统会向用户显示可用备份数据集的列表,并询问要从中恢复哪个数据集的数据。选择的任何备份数据集都会成为该设备的祖先数据集。设备可以从自己的备份或祖先数据集中恢复。如果两个来源的备份都可用,设备会优先使用自己的备份。如果用户未完成设备设置向导,则设备只能从自己的备份中恢复。

为了简化测试,Android 提供了允许您手动启动应用恢复的工具。如需了解详情,请参阅测试备份和恢复

启用和停用备份

目标平台为 Android 6.0(API 级别 23)或更高版本的应用会自动参与自动备份。在应用清单文件中,将布尔值 android:allowBackup 设置为 true 或 false,以启用或停用备份。默认值为 true,但我们建议在清单中明确设置该属性,如以下示例所示

<manifest ... >
    ...
    <application android:allowBackup="true" ... >
        ...
    </application>
</manifest>

您可以通过将 android:allowBackup 设置为 false 来停用备份。如果您的应用可以通过其他机制重新创建其状态,或者您的应用处理敏感信息,您可能需要这样做。

包含和排除文件

默认情况下,系统会备份几乎所有应用数据。如需了解更多信息,请参阅有关备份的文件的部分。

本部分介绍如何定义自定义 XML 规则来控制备份内容。如果您的应用目标平台是 Android 12(API 级别 31)或更高版本,您必须按照本节所述指定另一组 XML 备份规则,以支持针对运行这些 Android 版本的设备引入的备份恢复变更

控制 Android 11 及更低版本上的备份

按照本部分中的步骤,控制在运行 Android 11(API 级别 30)或更低版本的设备上备份哪些文件。

  1. 在您的 AndroidManifest.xml 文件中,将 android:fullBackupContent 属性添加到 <application> 元素,如以下示例所示。此属性指向包含备份规则的 XML 文件。

    <application ...
     android:fullBackupContent="@xml/backup_rules">
    </application>
  2. res/xml/ 目录中创建一个名为 @xml/backup_rules 的 XML 文件。在此文件中,使用 <include><exclude> 元素添加规则。以下示例备份所有共享偏好设置,但 device.xml 除外

    <?xml version="1.0" encoding="utf-8"?>
    <full-backup-content>
     <include domain="sharedpref" path="."/>
     <exclude domain="sharedpref" path="device.xml"/>
    </full-backup-content>

定义备份所需的设备条件

如果您的应用在设备上保存敏感信息,您可以指定将应用数据包含在用户备份中的条件。您可以在 Android 9(API 级别 28)或更高版本中添加以下条件

如果您已将开发设备升级到 Android 9,则需要在升级后停用并重新启用数据备份。这是因为 Android 仅在“设置”或设置向导中告知用户后,才会使用客户端密钥对备份进行加密。

要声明包含条件,请在备份规则集中的 <include> 元素中将 requireFlags 属性设置为选定的值或多个值

backup_rules.xml

<?xml version="1.0" encoding="utf-8"?>
<full-backup-content>
    <!-- App data isn't included in user's backup
         unless client-side encryption is enabled. -->
    <include domain="file" path="."
             requireFlags="clientSideEncryption" />
</full-backup-content>

如果您的应用实现了键值对备份系统,或者您自己实现了 BackupAgent,您还可以通过对 BackupDataOutput 对象的传输标志集与您的自定义备份代理的 FLAG_CLIENT_SIDE_ENCRYPTION_ENABLEDFLAG_DEVICE_TO_DEVICE_TRANSFER 标志进行按位比较,将这些条件要求应用于您的备份逻辑。

以下代码段显示了此方法的使用示例

Kotlin

class CustomBackupAgent : BackupAgent() {
    override fun onBackup(oldState: ParcelFileDescriptor?,
            data: BackupDataOutput?, newState: ParcelFileDescriptor?) {
        if (data != null) {
            if ((data.transportFlags and
                    FLAG_CLIENT_SIDE_ENCRYPTION_ENABLED) != 0) {
                // Client-side backup encryption is enabled.
            }

            if ((data.transportFlags and FLAG_DEVICE_TO_DEVICE_TRANSFER) != 0) {
                // Local device-to-device transfer is enabled.
            }
        }
    }

    // Implementation of onRestore() here.
}

Java

public class CustomBackupAgent extends BackupAgent {
    @Override
    public void onBackup(ParcelFileDescriptor oldState, BackupDataOutput data,
            ParcelFileDescriptor newState) throws IOException {
        if ((data.getTransportFlags() &
                FLAG_CLIENT_SIDE_ENCRYPTION_ENABLED) != 0) {
            // Client-side backup encryption is enabled.
        }

        if ((data.getTransportFlags() &
                FLAG_DEVICE_TO_DEVICE_TRANSFER) != 0) {
            // Local device-to-device transfer is enabled.
        }
    }

    // Implementation of onRestore() here.
}

控制 Android 12 或更高版本上的备份

如果您的应用目标平台是 Android 12(API 级别 31)或更高版本,请按照本节中的步骤控制在运行 Android 12 或更高版本的设备上备份哪些文件。

  1. 在您的 AndroidManifest.xml 文件中,将 android:dataExtractionRules 属性添加到 <application> 元素,如以下示例所示。此属性指向包含备份规则的 XML 文件。

    <application ...
     android:dataExtractionRules="backup_rules.xml">
    </application>
  2. res/xml/ 目录中创建一个名为 backup_rules.xml 的 XML 文件。在此文件中,使用 <include><exclude> 元素添加规则。以下示例备份所有共享偏好设置,但 device.xml 除外

    <?xml version="1.0" encoding="utf-8"?>
    <data-extraction-rules>
     <cloud-backup [disableIfNoEncryptionCapabilities="true|false"]>
       <include domain="sharedpref" path="."/>
       <exclude domain="sharedpref" path="device.xml"/>
     </cloud-backup>
    </data-extraction-rules>

XML 配置语法

配置文件的 XML 语法因您的应用目标平台和运行所在的 Android 版本而异。

Android 11 或更低版本

对于控制运行 Android 11 或更低版本的设备备份的配置文件,请使用以下 XML 语法。

<full-backup-content>
    <include domain=["file" | "database" | "sharedpref" | "external" |
                     "root" | "device_file" | "device_database" |
                     "device_sharedpref" | "device_root" ] path="string"
    requireFlags=["clientSideEncryption" | "deviceToDeviceTransfer"] />
    <exclude domain=["file" | "database" | "sharedpref" | "external" |
                     "root" | "device_file" | "device_database" |
                     "device_sharedpref" | "device_root" ] path="string" />
</full-backup-content>

Android 12 或更高版本

如果您的应用目标平台是 Android 12(API 级别 31)或更高版本,对于控制运行 Android 12 或更高版本的设备备份的配置文件,请使用以下 XML 语法。

<data-extraction-rules>
  <cloud-backup [disableIfNoEncryptionCapabilities="true|false"]>
    ...
    <include domain=["file" | "database" | "sharedpref" | "external" |
                     "root" | "device_file" | "device_database" |
                     "device_sharedpref" | "device_root" ] path="string"/>
    ...
    <exclude domain=["file" | "database" | "sharedpref" | "external" |
                     "root" | "device_file" | "device_database" |
                     "device_sharedpref" | "device_root" ] path="string"/>
    ...
  </cloud-backup>
  <device-transfer>
    ...
    <include domain=["file" | "database" | "sharedpref" | "external" |
                     "root" | "device_file" | "device_database" |
                     "device_sharedpref" | "device_root" ] path="string"/>
    ...
    <exclude domain=["file" | "database" | "sharedpref" | "external" |
                     "root" | "device_file" | "device_database" |
                     "device_sharedpref" | "device_root" ] path="string"/>
    ...
  </device-transfer>
</data-extraction-rules>

配置的每个部分(<cloud-backup><device-transfer>)包含仅适用于该传输类型的规则。这种分离允许您例如将文件或目录从 Google 云端硬盘备份中排除,但在设备到设备 (D2D) 传输期间仍然传输它。这对于您有一些文件太大而无法备份到云端但可以在设备之间轻松传输的情况非常有用。

如果特定备份模式没有规则,例如缺少 <device-transfer> 部分,则该模式会完全启用所有内容,但备份的文件部分所述的 no-backupcache 目录除外。

您的应用可以在 <cloud-backup> 部分设置 disableIfNoEncryptionCapabilities 标志,以确保只有在可以加密时才进行备份,例如当用户设置了锁屏时。设置此约束会阻止在用户设备不支持加密的情况下将备份发送到云端,但由于 D2D 传输不会发送到服务器,因此即使在不支持加密的设备上它们也会继续运行。

包含和排除元素的语法

<full-backup-content><cloud-backup><device-transfer> 标签内(取决于设备的 Android 版本和应用的 targetSDKVersion),您可以定义 <include><exclude> 元素

<include>

指定要备份的文件或文件夹。默认情况下,自动备份包含几乎所有应用文件。如果您指定 <include> 元素,系统将不再默认包含任何文件,而是仅备份指定的文件。要包含多个文件,请使用多个 <include> 元素。

Android 11 及更低版本上,此元素还可以包含 requireFlags 属性,有关如何定义备份的条件要求的部分对此进行了更详细的讨论。

即使您尝试包含它们,getCacheDir()getCodeCacheDir()getNoBackupFilesDir() 返回的目录中的文件始终被排除。

<exclude>

指定在备份期间排除的文件或文件夹。以下是通常从备份中排除的一些文件

  • 具有设备特定标识符的文件,这些标识符由服务器颁发或在设备上生成。例如,每当用户在新设备上安装您的应用时,Firebase Cloud Messaging (FCM) 都需要生成一个注册令牌。如果旧的注册令牌被恢复,应用可能会出现意外行为。

  • 与应用调试相关的文件。

  • 导致应用超出 25MB 备份配额的大文件。

每个 <include><exclude> 元素必须包含以下两个属性

domain

指定资源的位置。此属性的有效值包括以下内容

  • root:文件系统上存储此应用所有私有文件的目录。
  • file:由 getFilesDir() 返回的目录。
  • database:由 getDatabasePath() 返回的目录。使用 SQLiteOpenHelper 创建的数据库存储在此处。
  • sharedpref:存储 SharedPreferences 的目录。
  • external:由 getExternalFilesDir() 返回的目录。
  • device_root:与 root 类似,但用于设备保护存储。
  • device_file:与 file 类似,但用于设备保护存储。
  • device_database:与 database 类似,但用于设备保护存储。
  • device_sharedpref:与 sharedpref 类似,但用于设备保护存储。
path

指定要包含或排除在备份中的文件或文件夹。请注意以下几点

  • 此属性不支持通配符或正则表达式语法。
  • 您可以使用 ./ 引用当前目录,但出于安全原因,您无法引用父目录,例如使用 ..
  • 如果您指定一个目录,则规则适用于该目录及其所有子目录中的所有文件。

实现 BackupAgent

实现自动备份的应用不需要实现 BackupAgent。但是,您可以选择实现自定义的 BackupAgent。通常,这样做的原因有两个

  • 您想要接收备份事件的通知,例如 onRestoreFinished()onQuotaExceeded(long, long)。即使应用未运行,也会执行这些回调方法。

  • 您无法轻易地使用 XML 规则表达您想要备份的文件集。在这种极少数情况下,您可以实现一个覆盖 onFullBackup(FullBackupDataOutput)BackupAgent 来存储您想要的内容。要保留系统的默认实现,请使用 super.onFullBackup() 在超类上调用相应的方法。

如果您实现 BackupAgent,系统默认会期望您的应用执行键值对备份和恢复。要改为使用基于文件的自动备份,请在应用的清单中将 android:fullBackupOnly 属性设置为 true

在自动备份和恢复操作期间,系统会以受限模式启动应用,以防止应用访问可能导致冲突的文件,并允许应用在其 BackupAgent 中执行回调方法。在此受限模式下,应用的主 activity 不会自动启动,其内容提供方不会初始化,并且将实例化基类 Application,而不是应用清单中声明的任何子类。

您的 BackupAgent 必须实现抽象方法 onBackup()onRestore(),这些方法用于键值对备份。如果您不想执行键值对备份,可以保留这些方法的空白实现。

如需了解更多信息,请参阅扩展 BackupAgent