使用自動備份功能備份使用者資料

如果應用程式指定 Android 6.0 (API 級別 23) 以上版本並在其中執行,「應用程式自動備份」功能會自動備份應用程式內的使用者資料。Android 保存應用程式資料的方式是將這些資料上傳到使用者的 Google 雲端硬碟,並透過使用者的 Google 帳戶憑證妥善保護。在搭載 Android 9 以上版本的裝置上,系統會使用裝置的 PIN 碼、解鎖圖案或密碼,對備份進行端對端加密處理。每個應用程式最多可為每位使用者分配 25 MB 的備份資料。儲存備份資料不必付費。您的應用程式可以自訂備份程序,或透過停用備份功能來選擇退出。

如要概略瞭解 Android 備份選項,以及要備份及還原哪些資料,請參閱「資料備份總覽」。

備份的檔案

根據預設,自動備份功能會納入大部分目錄中的檔案,這些目錄是由系統指派給應用程式:

自動備份功能會排除以下項目所傳回目錄中的檔案:getCacheDir()getCodeCacheDir()getNoBackupFilesDir()。儲存在這些位置的檔案僅供暫時使用,因此備份作業會刻意排除這類檔案。

您可以設定應用程式,納入及排除特定檔案。詳情請參閱「納入及排除檔案」一節。

備份位置

備份資料會儲存在使用者 Google 雲端硬碟帳戶的私人資料夾,每個應用程式的資料量上限為 25 MB。儲存的資料不會計入使用者的個人 Google 雲端硬碟配額。系統只會保存最新的備份。進行備份時,會刪除任何先前的備份。使用者或裝置上的其他應用程式無法讀取備份資料。

使用者可以在 Google 雲端硬碟 Android 應用程式中查看已備份的應用程式清單。在 Android 裝置上,使用者可透過雲端硬碟應用程式的導覽匣,依序前往「設定」>「備份及重設」查看這份清單

每個裝置設定生命週期的備份資料都會儲存在不同的資料集,如以下範例所述:

  • 如果使用者擁有兩部裝置,則每部裝置都會有備份資料集。

  • 如果使用者將裝置恢復原廠設定,然後使用相同的帳戶設定裝置,系統會將備份儲存至新的資料集。過時資料集會在閒置一段時間後自動刪除。

備份時間表

系統會在符合下列所有條件時自動執行備份:

  • 使用者在裝置上啟用備份功能。在 Android 9 中,這項設定位於「設定」>「系統」>「備份」
  • 從上次備份到現在已經過了 24 小時。
  • 裝置處於閒置狀態。
  • 裝置已連上 Wi-Fi 網路 (如果裝置使用者未選擇啟用行動數據備份功能)。

在實際運作時,這些條件大致每晚都會發生,但裝置也可能完全不進行備份 (例如從未連上網路的情況)。為節省網路頻寬,除非應用程式資料已變更,上傳作業才會執行。

在自動備份期間,系統會關閉應用程式,以確保該應用程式不再寫入檔案系統。根據預設,備份系統會忽略在前景執行的應用程式,避免使用者體驗不佳。只要將 android:backupInForeground 屬性設為 true,即可覆寫預設行為。

為簡化測試流程,Android 提供手動備份應用程式的工具。詳情請參閱「測試備份與還原」的相關說明。

還原時間表

無論是透過 Play 商店、在裝置設定期間 (系統安裝先前安裝過的應用程式) 或執行 adb 安裝,每次安裝應用程式都會還原資料。還原作業的執行時間會在 APK 安裝完成後,但在應用程式可供使用者啟動之前。

在初始裝置設定精靈中,系統會向使用者顯示可用的備份資料集清單,並詢問要從哪個資料集還原資料。只要選取任何備份資料集,就會成為該裝置的祖系資料集。裝置可以從本身的備份或祖系資料集還原。如果同時提供這兩個來源的備份資料,裝置會優先採用自身的備份。如果使用者未通過裝置設定精靈,則只能從自身備份還原。

為簡化測試流程,Android 提供手動還原應用程式的工具。詳情請參閱「測試備份與還原」的相關說明。

啟用及停用備份

以 Android 6.0 (API 級別 23) 或以上版本為目標的應用程式會自動加入「自動備份」功能。在應用程式資訊清單檔案中,將布林值 android:allowBackup 設為啟用或停用備份。預設值為 true,但建議在資訊清單中明確設定這項屬性,如下列範例所示:

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

如要停用備份功能,請將 android:allowBackup 設為 false。如果應用程式可以透過其他機制重新建立狀態,或者應用程式會處理敏感資訊,則建議停用備份功能。

納入並排除檔案

根據預設,系統會備份絕大多數的應用程式資料。詳情請參閱「備份的檔案」一節。

您可以根據轉移類型,控制備份內容包含哪些資料。 自動備份功能支援將資料備份到 Google 雲端硬碟,以及直接在裝置間轉移資料 (D2D)。設定方法會因 Android 版本和應用程式的 targetSdkVersion 而異。

在 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 只有在透過「設定」或「設定精靈」通知使用者後,才會使用用戶端密鑰加密備份。

如要宣告納入條件,請將 requireFlags 屬性設為備份規則集內 <include> 元素的一或多個指定值:

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) 以上的版本,請使用以下 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>
  <cross-platform-transfer platform="ios">
    ...
    <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"/>
    ...
    <platform-specific-params bundleId="string" teamId="string" contentVersion="string"/>
    ...
  </cross-platform-transfer>
</data-extraction-rules>

設定的各區段 (<cloud-backup><device-transfer><cross-platform-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>

指定要在備份期間排除的檔案或資料夾。以下列舉一些常見的備份檔案:

  • 含有裝置專屬 ID 的檔案,這類 ID 是由伺服器核發或在裝置上產生。舉例來說,每當使用者在新裝置上安裝應用程式時,Firebase 雲端通訊 (FCM) 都必須產生註冊權杖。如果還原的是舊註冊權杖,應用程式可能會產生非預期的行為。

  • 與應用程式偵錯相關的檔案。

  • 導致應用程式超過 25 MB 備份配額的大型檔案。

每個 <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

指定要在備份中納入或排除的檔案或資料夾。注意事項:

  • 這個屬性不支援萬用字元或規則運算式語法。
  • 您可以使用 ./ 參照目前的目錄,但基於安全考量,您無法使用 .. 等符號參照父項目錄。
  • 如果您指定目錄,規則就會套用至該目錄和遞迴子目錄中的所有檔案。

設定跨平台轉移

從 Android 16 QPR2 (API 級別 36.1) 開始,您可以設定自動備份功能,將資料傳輸至非 Android 裝置,或從非 Android 裝置傳輸資料。如要這麼做,請在 <data-extraction-rules> 設定中加入 <cross-platform-transfer> 元素,如適用於 Android 12 以上版本的語法所示。你必須使用必要 platform 屬性指定目標平台。唯一支援的值為 ios

在這個部分中,您可以按照「包含和排除元素的語法」一文所述,使用標準的 <include><exclude> 元素,指定要轉移的資料。

此外,您必須加入 <platform-specific-params> 元素,協助系統將應用程式與目標平台上的對應應用程式配對。這個元素必須具備下列屬性:

  • bundleId:其他平台上的應用程式套件 ID (例如 iOS 應用程式的套件 ID)。
  • teamId:其他平台應用程式的團隊 ID (例如 iOS 應用程式的團隊 ID)。
  • contentVersion:您定義的版本字串,與要匯出的資料格式相關聯。

bundleIdteamId 屬性可用於驗證資料完整性,以及確保應用程式間的配對正確無誤。這些保證可確保資料只會在匯出期間轉移其他平台上的指定應用程式,且這個 Android 應用程式只會在匯入期間該指定應用程式匯入資料。

如要進一步控管資料轉換和移轉程序,除了使用 XML 規則外,您也可以實作自訂 BackupAgent,並使用跨平台移轉 API

iOS 轉移的檔案對應

將檔案轉移到 iOS 時,您在 <include> 規則中指定的 Android domainpath 會對應到特定目錄結構。下表顯示 iOS 上的目的地路徑 (相對於轉移目的地根目錄),並以 Android domain 為依據:

Android domain iOS 裝置上的路徑 (相對於轉移根目錄)
root app/
file app/files/
database app/databases/
sharedpref app/shared_prefs/
external external/files/
device_root device/app/
device_file device/app/files/
device_database device/app/databases/
device_sharedpref device/app/shared_prefs/

舉例來說,如果檔案包含 <include domain="file" path="my_settings.txt"/>,則 iOS 端會提供 app/files/my_settings.txt,相對於傳輸目的地根目錄。

實作 BackupAgent

實作自動備份功能的應用程式不需要實作 BackupAgent。不過,您也可以選擇實作自訂 BackupAgent。一般來說,這樣做的原因有 2 種:

  • 您想收到備份事件的通知,例如 onRestoreFinished()onQuotaExceeded()。即使應用程式並未執行,仍會執行這些回呼方法。

  • 您無法使用 XML 規則明確表示要備份的檔案組合。如果發生這類罕見情況,可以實作 BackupAgent 來覆寫 onFullBackup(FullBackupDataOutput),儲存所需資料。如要保留系統的預設實作方式,請使用 super.onFullBackup() 對父類別呼叫相應的方法。

在預設情況下,如果您實作 BackupAgent,系統會預期應用程式執行鍵/值備份與還原作業。如要改用以檔案為基礎的自動備份功能,請在應用程式資訊清單中將 android:fullBackupOnly 屬性設為 true

在自動備份和還原作業期間,系統會以受限模式啟動應用程式,防止應用程式存取可能導致衝突的檔案,並讓應用程式執行 BackupAgent 中的回呼方法。在這種受限模式下,應用程式的主要活動不會自動啟動,內容供應器未初始化,且建立的是基礎類別 Application 的例項,而非應用程式資訊清單中宣告的任何子類別。

您的 BackupAgent 必須實作抽象方法 onBackup()onRestore(),這兩種方法都用於鍵/值備份。如果不想執行鍵/值備份,只要將這些方法的實作內容留白即可。

詳情請參閱「延長 BackupAgent」。

在 BackupAgent 中處理跨平台轉移

從 Android 16 QPR2 (API 級別 36.1) 開始,BackupAgent 提供多項新 API,可更完善地支援跨平台資料移轉。

新傳輸旗標:

  • FLAG_CROSS_PLATFORM_TRANSFER_IOS:這個標記會新增至提供給 BackupAgenttransportFlags
    • onFullBackup 中,如果目前的備份作業是將資料匯出至 iOS 裝置的一部分,系統就會設定這個標記。
    • 在新的 onRestoreFile 多載中,如果資料是從 iOS 裝置匯入,系統就會設定這個旗標。

onRestoreFile 方法:

推出 onRestoreFile 的新超載,採用單一 FullRestoreDataInput 參數。這個物件提供還原作業的詳細資訊:

  • FullRestoreDataInput.getTransportFlags():傳回目前還原作業的傳輸旗標,可能包括 FLAG_CROSS_PLATFORM_TRANSFER_IOS
  • FullRestoreDataInput.getContentVersion():在跨平台轉移期間,傳回其他平台來源應用程式提供的內容版本字串。如果來源未提供這個值,則為空字串。

新的尺寸估算方法:

  • onEstimateFullBackupBytes():這個方法可讓您提供應用程式預計備份的資料大小。如果應用程式會在備份期間執行大量資料轉換作業或處理大量資料,強烈建議您實作這項功能,因為這樣可以避免預設的系統試運作,進而提升效率。如果應用程式的備份資料量不大且結構簡單,通常不需要使用這個方法。

使用範例:

Kotlin

// In your custom BackupAgent class

override fun onFullBackup(out: FullBackupDataOutput) {
    // Check if this is a cross-platform export to iOS
    if ((out.transportFlags and FLAG_CROSS_PLATFORM_TRANSFER_IOS) != 0) {
        Log.d(TAG, "onFullBackup for iOS transfer")
        // Your custom export logic here
        // Call fullBackupFile() for files to include
    }
}

override fun onRestoreFile(input: FullRestoreDataInput) {
    if ((input.transportFlags and FLAG_CROSS_PLATFORM_TRANSFER_IOS) != 0) {
        val sourceContentVersion = input.contentVersion
        Log.d(TAG, "onRestoreFile from iOS, content version: $sourceContentVersion")
        // Your custom import logic here, using input.data, input.destination, etc.
    }
}

// Optional: Provide an estimate of the backup size
override fun onEstimateFullBackupBytes(): Long {
    return calculateEstimatedBackupSize()
}

Java

// In your custom BackupAgent class

@Override
public void onFullBackup(FullBackupDataOutput out) throws IOException {
    // Check if this is a cross-platform export to iOS
    if ((out.getTransportFlags() & FLAG_CROSS_PLATFORM_TRANSFER_IOS) != 0) {
        Log.d(TAG, "onFullBackup for iOS transfer");
        // Your custom export logic here
        // Call fullBackupFile() for files to include
    }
}

@Override
public void onRestoreFile(FullRestoreDataInput input) {
    if ((input.getTransportFlags() & FLAG_CROSS_PLATFORM_TRANSFER_IOS) != 0) {
        String sourceContentVersion = input.getContentVersion();
        Log.d(TAG, "onRestoreFile from iOS, content version: " + sourceContentVersion);
        // Your custom import logic here, using input.getData(), input.getDestination(), etc.
    }
}

// Optional: Provide an estimate of the backup size
@Override
public long onEstimateFullBackupBytes() {
    return calculateEstimatedBackupSize();
}