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

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

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

备份的文件

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

自动备份不包括由getCacheDir()getCodeCacheDir()getNoBackupFilesDir()返回的目录中的文件。这些位置保存的文件仅在临时需要,并且有意从备份操作中排除。

您可以配置您的应用以包含和排除特定文件。有关更多信息,请参阅包含和排除文件部分。

备份位置

备份数据存储在用户 Google Drive 帐户中的私有文件夹中,每个应用最多 25 MB。保存的数据不计入用户的个人 Google Drive 配额。仅存储最新的备份。创建备份时,任何以前的备份都将被删除。备份数据无法被用户或设备上的其他应用读取。

用户可以在 Google Drive Android 应用中查看已备份应用的列表。在 Android 设备上,用户可以在 Drive 应用的导航抽屉中找到此列表,位于设置 > 备份和重置下。

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

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

  • 如果用户将设备恢复出厂设置,然后使用同一帐户设置设备,则备份将存储在新数据集中。过时的数据集在一段时间不活动后会自动删除。

备份计划

当满足以下所有条件时,备份将自动执行

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

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

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

为了简化测试,Android 包含了一些工具,允许您手动启动应用的备份。有关更多信息,请参阅测试备份和恢复

恢复计划

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

在初始设备设置向导中,系统会向用户显示可用备份数据集的列表,并询问要从中恢复数据的哪个数据集。所选的任何备份数据集都将成为设备的祖先数据集。设备可以从其自己的备份或祖先数据集中恢复。如果两种来源的备份都可用,则设备会优先考虑其自己的备份。如果用户没有执行设备设置向导,则设备只能从其自己的备份中恢复。

为了简化测试,Android 包含了一些工具,允许您手动启动应用的恢复。有关更多信息,请参阅测试备份和恢复

启用和禁用备份

面向 Android 6.0(API 级别 23)或更高版本的应用会自动参与自动备份。在您的应用清单文件中,设置布尔值android:allowBackup 以启用或禁用备份。默认值为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 版本而有所不同。

Android 11 或更低版本

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

<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)或更高版本为目标,请使用以下配置文件的 XML 语法。控制 Android 12 或更高版本设备的备份

<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 Drive 备份中排除文件或目录,同时在设备到设备 (D2D) 传输期间仍然传输它。如果您有一些文件太大而无法备份到云端,但可以在设备之间无问题地传输,这将非常有用。

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

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

include 和 exclude 元素的语法

<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) 需要在用户在新的设备上安装您的应用时每次生成注册令牌。如果恢复了旧的注册令牌,应用可能会出现意外行为。

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

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

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

domain

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

  • root:文件系统上存储此应用的所有私有文件的目录。
  • filegetFilesDir() 返回的目录。
  • databasegetDatabasePath() 返回的目录。使用 SQLiteOpenHelper 创建的数据库存储在此处。
  • sharedpref:存储SharedPreferences的目录。
  • externalgetExternalFilesDir() 返回的目录。
  • 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 中执行回调方法。在此受限模式下,应用的主活动不会自动启动,其内容提供程序不会初始化,并且会实例化基类 Application,而不是应用的 清单中声明的任何子类。

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

有关更多信息,请参阅扩展 BackupAgent