Esegui il backup dei dati utente con il backup automatico

Il backup automatico per le app esegue automaticamente il backup dei dati di un utente dalle app che hanno come target e vengono eseguite su Android 6.0 (livello API 23) o versioni successive. Android conserva i dati dell'app caricandoli su Google Drive dell'utente, dove sono protetti dalle credenziali dell'Account Google dell'utente. Il backup è protetto con crittografia end-to-end sui dispositivi con Android 9 o versioni successive utilizzando il PIN, la sequenza o la password del dispositivo. Ogni app può allocare fino a 25 MB di dati di backup per utente dell'app. Non è previsto alcun addebito per l'archiviazione dei dati di backup. La tua app può personalizzare la procedura di backup o disattivare i backup disattivandoli.

Per una panoramica delle opzioni di backup di Android e indicazioni su quali dati sottoporre a backup e ripristino, consulta la panoramica del backup dei dati.

File di cui viene eseguito il backup

Per impostazione predefinita, il backup automatico include i file nella maggior parte delle directory assegnate alla tua app dal sistema:

Il backup automatico esclude i file nelle directory restituite da getCacheDir(), getCodeCacheDir() e getNoBackupFilesDir(). I file salvati in queste posizioni sono necessari solo temporaneamente e sono intenzionalmente esclusi dalle operazioni di backup.

Puoi configurare l'app in modo da includere ed escludere determinati file. Per ulteriori informazioni, consulta la sezione Includi ed escludi file.

Località di backup

I dati di backup vengono archiviati in una cartella privata nell'account Google Drive dell'utente, con un limite di 25 MB per app. I dati salvati non vengono conteggiati ai fini della quota personale di Google Drive dell'utente. Viene memorizzato solo il backup più recente. Quando viene eseguito un backup, quello precedente viene eliminato. I dati di backup non possono essere letti dall'utente o da altre app sul dispositivo.

Gli utenti possono visualizzare un elenco di app di cui è stato eseguito il backup nell'app Google Drive per Android. Su un dispositivo Android, gli utenti possono trovare questo elenco nel riquadro di navigazione a scomparsa dell'app Drive in Impostazioni > Backup e ripristino.

I backup di ogni ciclo di vita della configurazione del dispositivo vengono archiviati in set di dati separati, come descritto nei seguenti esempi:

  • Se l'utente possiede due dispositivi, esiste un set di dati di backup per ogni dispositivo.

  • Se l'utente ripristina i dati di fabbrica di un dispositivo e poi lo configura con lo stesso account, il backup viene archiviato in un nuovo set di dati. I set di dati obsoleti vengono eliminati automaticamente dopo un periodo di inattività.

Pianificazione backup

I backup vengono eseguiti automaticamente quando sono soddisfatte tutte le seguenti condizioni:

  • L'utente ha attivato il backup sul dispositivo. In Android 9, questa impostazione si trova in Impostazioni > Sistema > Backup.
  • Sono trascorse almeno 24 ore dall'ultimo backup.
  • Il dispositivo è inattivo.
  • Il dispositivo è connesso a una rete Wi-Fi (se l'utente del dispositivo non ha attivato i backup dei dati mobili).

In pratica, queste condizioni si verificano all'incirca ogni notte, ma un dispositivo potrebbe non eseguire mai il backup (ad esempio, se non si connette mai a una rete). Per risparmiare larghezza di banda della rete, il caricamento avviene solo se i dati dell'app sono stati modificati.

Durante il backup automatico, il sistema arresta l'app per assicurarsi che non scriva più nel file system. Per impostazione predefinita, il sistema di backup ignora le app in esecuzione in primo piano per evitare un'esperienza utente scadente. Puoi eseguire l'override del comportamento predefinito impostando l'attributo android:backupInForeground su true.

Per semplificare i test, Android include strumenti che ti consentono di avviare manualmente un backup della tua app. Per ulteriori informazioni, consulta Esegui il test di backup e ripristino.

Ripristina pianificazione

I dati vengono ripristinati ogni volta che l'app viene installata, dal Play Store, durante la configurazione del dispositivo (quando il sistema installa le app installate in precedenza) o eseguendo l'installazione di adb. L'operazione di ripristino avviene dopo l'installazione dell'APK, ma prima che l'app sia disponibile per essere avviata dall'utente.

Durante la configurazione guidata iniziale del dispositivo, all'utente viene mostrato un elenco di set di dati di backup disponibili e gli viene chiesto da quale set di dati ripristinare i dati. Il set di dati di backup selezionato diventa il set di dati ancestrale per il dispositivo. Il dispositivo può eseguire il ripristino dai propri backup o dal set di dati ancestrale. Se sono disponibili backup da entrambe le origini, il dispositivo dà la priorità al proprio backup. Se l'utente non ha seguito la configurazione guidata del dispositivo, quest'ultimo può eseguire il ripristino solo dai propri backup.

Per semplificare i test, Android include strumenti che ti consentono di avviare manualmente un ripristino della tua app. Per saperne di più, consulta Testare il backup e il ripristino.

Attiva e disattiva il backup

Le app che hanno come target Android 6.0 (livello API 23) o versioni successive partecipano automaticamente al backup automatico. Nel file manifest dell'app, imposta il valore booleano android:allowBackup per attivare o disattivare il backup. Il valore predefinito è true, ma ti consigliamo di impostare esplicitamente l'attributo nel manifest, come mostrato nell'esempio seguente:

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

Puoi disattivare i backup impostando android:allowBackup su false. Potresti voler eseguire questa operazione se la tua app può ricreare il proprio stato tramite un altro meccanismo o se gestisce informazioni sensibili.

Includi ed escludi file

Per impostazione predefinita, il sistema esegue il backup di quasi tutti i dati delle app. Per saperne di più, consulta la sezione relativa ai file di cui viene eseguito il backup.

Puoi controllare quali dati vengono inclusi nel backup in base al tipo di trasferimento. Il backup automatico supporta i backup sul cloud su Google Drive e i trasferimenti diretti da dispositivo a dispositivo (D2D). I metodi di configurazione variano in base alla versione di Android e al valore targetSdkVersion della tua app.

Controlla il backup su Android 11 e versioni precedenti

Segui i passaggi descritti in questa sezione per controllare quali file vengono sottoposti a backup sui dispositivi con Android 11 (livello API 30) o versioni precedenti.

  1. Nel file AndroidManifest.xml, aggiungi l'attributo android:fullBackupContent all'elemento <application>, come mostrato nell'esempio seguente. Questo attributo rimanda a un file XML che contiene le regole di backup.

    <application ...
        android:fullBackupContent="@xml/backup_rules">
    </application>
    
  2. Crea un file XML denominato @xml/backup_rules nella directory res/xml/. In questo file, aggiungi regole con gli elementi <include> e <exclude>. L'esempio seguente esegue il backup di tutte le preferenze condivise, ad eccezione di 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>
    

Definisci le condizioni del dispositivo richieste per il backup

Se l'app salva informazioni sensibili sul dispositivo, puoi specificare le condizioni in base alle quali i dati dell'app vengono inclusi nel backup dell'utente. Puoi aggiungere le seguenti condizioni in Android 9 (livello API 28) o versioni successive:

Se hai eseguito l'upgrade dei tuoi dispositivi di sviluppo ad Android 9, devi disattivare e poi riattivare il backup dei dati dopo l'upgrade. Questo perché Android cripta i backup con un secret lato client solo dopo aver informato gli utenti nelle Impostazioni o nella configurazione guidata.

Per dichiarare le condizioni di inclusione, imposta l'attributo requireFlags su uno o più valori scelti negli elementi <include> all'interno del tuo insieme di regole di backup:

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>

Se la tua app implementa un sistema di backup di coppie chiave-valore o se implementi BackupAgent autonomamente, puoi anche applicare questi requisiti condizionali alla logica di backup eseguendo un confronto bit per bit tra un insieme di flag di trasporto di un oggetto BackupDataOutput e i flag FLAG_CLIENT_SIDE_ENCRYPTION_ENABLED o FLAG_DEVICE_TO_DEVICE_TRANSFER dell'agente di backup personalizzato.

Il seguente snippet di codice mostra un esempio di utilizzo di questo metodo:

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.
}

Controlla il backup su Android 12 o versioni successive

Se la tua app ha come target Android 12 (livello API 31) o versioni successive, segui i passaggi descritti in questa sezione per controllare di quali file viene eseguito il backup sui dispositivi con Android 12 o versioni successive.

  1. Nel file AndroidManifest.xml, aggiungi l'attributo android:dataExtractionRules all'elemento <application>, come mostrato nell'esempio seguente. Questo attributo rimanda a un file XML che contiene le regole di backup.

    <application ...
        android:dataExtractionRules="backup_rules.xml">
    </application>
    
  2. Crea un file XML denominato backup_rules.xml nella directory res/xml/. In questo file, aggiungi regole con gli elementi <include> e <exclude>. L'esempio seguente esegue il backup di tutte le preferenze condivise, ad eccezione di 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>
    

Sintassi di configurazione XML

La sintassi XML del file di configurazione varia a seconda della versione di Android su cui l'app è destinata e viene eseguita.

Android 11 o versioni precedenti

Utilizza la seguente sintassi XML per il file di configurazione che controlla il backup per i dispositivi con Android 11 o versioni precedenti.

<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 o versioni successive

Se la tua app ha come target Android 12 (livello API 31) o versioni successive, utilizza la seguente sintassi XML per il file di configurazione che controlla il backup per i dispositivi con Android 12 o versioni successive.

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

Ogni sezione della configurazione (<cloud-backup>, <device-transfer>, <cross-platform-transfer>) contiene regole che si applicano solo a quel tipo di trasferimento. Questa separazione ti consente, ad esempio, di escludere un file o una directory dai backup di Google Drive, pur continuando a trasferirli durante i trasferimenti da dispositivo a dispositivo (D2D) o multipiattaforma. Questa opzione è utile se hai file troppo grandi per il backup sul cloud, ma che possono essere trasferiti tra dispositivi senza problemi.

Se non esistono regole per una determinata modalità di backup, ad esempio se manca la sezione <device-transfer>, questa modalità è completamente abilitata per tutti i contenuti, ad eccezione delle directory no-backup e cache, come descritto nella sezione File di cui viene eseguito il backup.

La tua app può impostare il flag disableIfNoEncryptionCapabilities nella sezione <cloud-backup> per assicurarsi che il backup venga eseguito solo se può essere criptato, ad esempio quando l'utente ha una schermata di blocco. L'impostazione di questo vincolo impedisce l'invio dei backup al cloud se il dispositivo dell'utente non supporta la crittografia, ma poiché i trasferimenti D2D non vengono inviati al server, continuano a funzionare anche sui dispositivi che non supportano la crittografia.

Sintassi per gli elementi di inclusione ed esclusione

All'interno dei tag <full-backup-content>, <cloud-backup> e <device-transfer> (a seconda della versione di Android del dispositivo e del targetSDKVersion della tua app), puoi definire gli elementi <include> e <exclude>:

<include>

Specifica un file o una cartella di cui eseguire il backup. Per impostazione predefinita, il backup automatico include quasi tutti i file dell'app. Se specifichi un elemento <include>, il sistema non include più file per impostazione predefinita ed esegue il backup solo dei file specificati. Per includere più file, utilizza più elementi <include>.

Su Android 11 e versioni precedenti, questo elemento può contenere anche l'attributo requireFlags, che viene descritto in maggiore dettaglio nella sezione su come definire i requisiti condizionali per il backup.

I file nelle directory restituite da getCacheDir(), getCodeCacheDir() o getNoBackupFilesDir() vengono sempre esclusi anche se provi a includerli.

<exclude>

Specifica un file o una cartella da escludere durante il backup. Ecco alcuni file che in genere vengono esclusi dal backup:

  • File con identificatori specifici del dispositivo, emessi da un server o generati sul dispositivo. Ad esempio, Firebase Cloud Messaging (FCM) deve generare un token di registrazione ogni volta che un utente installa la tua app su un nuovo dispositivo. Se il token di registrazione precedente viene ripristinato, l'app potrebbe comportarsi in modo imprevisto.

  • File relativi al debug dell'app.

  • File di grandi dimensioni che fanno superare all'app la quota di backup di 25 MB.

Ogni elemento <include> e <exclude> deve includere i seguenti due attributi:

domain

Specifica la località della risorsa. I valori validi per questo attributo includono:

  • root: la directory del file system in cui sono archiviati tutti i file privati appartenenti a questa app.
  • file: directory restituite da getFilesDir().
  • database: directory restituite da getDatabasePath(). I database creati con SQLiteOpenHelper vengono archiviati qui.
  • sharedpref: la directory in cui sono archiviati i file SharedPreferences.
  • external: la directory restituita da getExternalFilesDir().
  • device_root: come root, ma per lo spazio di archiviazione protetto dal dispositivo.
  • device_file: come file, ma per lo spazio di archiviazione protetto dal dispositivo.
  • device_database: come database, ma per lo spazio di archiviazione protetto dal dispositivo.
  • device_sharedpref: come sharedpref, ma per lo spazio di archiviazione protetto dal dispositivo.
path

Specifica un file o una cartella da includere o escludere dal backup. Tieni presente quanto segue:

  • Questo attributo non supporta la sintassi dei caratteri jolly o delle espressioni regolari.
  • Puoi fare riferimento alla directory corrente utilizzando ./, ma non puoi fare riferimento alla directory principale, ad esempio utilizzando .., per motivi di sicurezza.
  • Se specifichi una directory, la regola si applica a tutti i file nella directory e nelle sottodirectory ricorsive.

Configura i trasferimenti multipiattaforma

A partire da Android 16 QPR2 (livello API 36.1), puoi configurare il backup automatico per i trasferimenti di dati da e verso dispositivi non Android. Per farlo, aggiungi l'elemento <cross-platform-transfer> all'interno della configurazione <data-extraction-rules>, come mostrato nella sintassi di Android 12 o versioni successive. Devi specificare la piattaforma di destinazione utilizzando l'attributo obbligatorio platform. L'unico valore supportato è ios.

All'interno di questa sezione, puoi utilizzare gli elementi standard <include> e <exclude> come descritto in Sintassi per gli elementi di inclusione ed esclusione per specificare i dati da trasferire.

Inoltre, devi includere l'elemento <platform-specific-params> per aiutare il sistema ad abbinare la tua app a quella corrispondente sulla piattaforma di destinazione. Questo elemento ha i seguenti attributi obbligatori:

  • bundleId: l'ID pacchetto dell'app sull'altra piattaforma (ad es. l'ID pacchetto dell'app per iOS).
  • teamId: l'ID team dell'app sull'altra piattaforma (ad es. l'ID team della tua app per iOS).
  • contentVersion: una stringa di versione definita da te, associata al formato dei dati esportati.

Gli attributi bundleId e teamId vengono utilizzati per verificare l'integrità dei dati e la corretta corrispondenza tra app. Garantiscono che i dati vengano trasferiti solo all'app specificata sull'altra piattaforma durante un'esportazione e che questa app per Android importi i dati solo da quell'app specifica durante un'importazione.

Per un controllo più granulare sul processo di trasformazione e trasferimento dei dati oltre a quello fornito dalle regole XML, puoi implementare un BackupAgent personalizzato e utilizzare le API di trasferimento multipiattaforma.

Mappatura dei file per i trasferimenti su iOS

Quando trasferisci file su iOS, i valori domain e path di Android che specifichi nelle regole <include> vengono mappati a una struttura di directory specifica. La tabella seguente mostra i percorsi di destinazione su iOS relativi alla directory principale della destinazione del trasferimento, in base alla domain di Android:

Android domain Percorso su iOS (relativo alla radice del trasferimento)
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/

Ad esempio, un file incluso con <include domain="file" path="my_settings.txt"/> sarà disponibile sul lato iOS in app/files/my_settings.txt rispetto alla directory principale della destinazione del trasferimento.

Implementa BackupAgent

Le app che implementano il backup automatico non devono implementare un BackupAgent. Tuttavia, se vuoi, puoi implementare un BackupAgent personalizzato. In genere, i motivi per farlo sono due:

  • Vuoi ricevere notifiche di eventi di backup, come onRestoreFinished() e onQuotaExceeded(). Questi metodi di callback vengono eseguiti anche se l'app non è in esecuzione.

  • Non puoi esprimere facilmente l'insieme di file di cui vuoi eseguire il backup con le regole XML. In questi rari casi, puoi implementare un BackupAgent che esegue l'override di onFullBackup(FullBackupDataOutput) per archiviare ciò che vuoi. Per mantenere l'implementazione predefinita del sistema, chiama il metodo corrispondente sulla superclasse con super.onFullBackup().

Se implementi un BackupAgent, per impostazione predefinita il sistema si aspetta che la tua app esegua il backup e il ripristino di coppie chiave-valore. Per utilizzare invece il backup automatico basato su file, imposta l'attributo android:fullBackupOnly su true nel manifest dell'app.

Durante le operazioni di backup automatico e ripristino, il sistema avvia l'app in una modalità con restrizioni per impedire all'app di accedere a file che potrebbero causare conflitti e consentire all'app di eseguire metodi di callback nel suo BackupAgent. In questa modalità con restrizioni, l'attività principale dell'app non viene avviata automaticamente, i suoi provider di contenuti non vengono inizializzati e viene creata un'istanza della classe base Application anziché di qualsiasi sottoclasse dichiarata nel manifest dell'app.

La classe BackupAgent deve implementare i metodi astratti onBackup() e onRestore(), che vengono utilizzati per il backup di coppie chiave-valore. Se non vuoi eseguire il backup di coppie chiave-valore, puoi lasciare vuota l'implementazione di questi metodi.

Per saperne di più, consulta Estendi BackupAgent.

Gestisci i trasferimenti multipiattaforma in BackupAgent

A partire da Android 16 QPR2 (livello API 36.1), sono disponibili diverse nuove API in BackupAgent per supportare meglio i trasferimenti di dati multipiattaforma.

Nuovo flag di trasporto:

  • FLAG_CROSS_PLATFORM_TRANSFER_IOS: questo flag viene aggiunto alla transportFlags fornita al tuo BackupAgent.
    • In onFullBackup, questo flag viene impostato se l'operazione di backup corrente fa parte di un'esportazione di dati su un dispositivo iOS.
    • Nel nuovo overload onRestoreFile, questo flag viene impostato se i dati vengono importati da un dispositivo iOS.

Nuovo metodo onRestoreFile:

Viene introdotto un nuovo overload di onRestoreFile, che accetta un singolo parametro FullRestoreDataInput. Questo oggetto fornisce ulteriori informazioni sull'operazione di ripristino:

  • FullRestoreDataInput.getTransportFlags(): restituisce i flag di trasporto per l'operazione di ripristino corrente, che possono includere FLAG_CROSS_PLATFORM_TRANSFER_IOS.
  • FullRestoreDataInput.getContentVersion(): restituisce la stringa della versione dei contenuti fornita dall'applicazione di origine sull'altra piattaforma durante un trasferimento multipiattaforma. Questo valore è una stringa vuota se non viene fornito dall'origine.

Nuovo metodo di stima delle dimensioni:

  • onEstimateFullBackupBytes(): questo metodo ti consente di fornire una dimensione stimata dei dati di cui la tua app intende eseguire il backup. L'implementazione è vivamente consigliata se l'app esegue trasformazioni di dati significative durante il backup o gestisce un volume elevato di dati, in quanto può migliorare l'efficienza evitando il dry run predefinito del sistema. Per le app con backup piccoli e semplici, questo metodo in genere non è necessario.

Esempio di utilizzo:

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();
}