[Android] 独自バックアップ、今どきどう作る?backupAgent実装メモ

スポンサーリンク

導入:端末移行で設定が消えると、だいたい炎上する

アプリの設定やログイン状態、ちょっとしたフラグ。
端末移行・再インストール後にこれが消えると、ユーザー体験が一気に悪化します。

「バックアップされてる前提で設計してたのに…」
「復元されると思ったら全然されてない…」

Androidにはバックアップの仕組みがいくつかありますが、今回は android:backupAgent を使って独自バックアップを実装する話です。

さらに、開発中に「本当に動いてる?」を確認するために、adbでバックアップ/リストアを叩く手順も載せます。

先に結論(3行)です。

  • backupAgentは「バックアップ対象を明示して管理したい」時に効く
  • BackupAgentHelperを使うとSharedPreferences/ファイルを最短でバックアップできる
  • 動作確認はadbで「バックアップ → 消す → リストア」のループが最速

まず整理:android:backupAgentで何ができる?

android:backupAgent は、アプリのバックアップ/リストア時に呼ばれるエントリポイントです。
標準の自動バックアップに任せるのではなく、アプリ側で

  • 何をバックアップするか
  • どのキーで保存するか
  • 復元時にどう扱うか

を明示的にコントロールできます。

ただし、バックアップはOS・端末・ユーザー設定に左右されます。
「必ずバックアップされる」前提で設計するのは危険です。

設計:何をバックアップ対象にするか

ここが一番大事です。バックアップは便利ですが、全部入れると事故ります。

バックアップ候補(よくある)

  • ユーザーの設定値(ON/OFF、テーマ、言語など)
  • アプリ内の軽量な状態(チュートリアル既読など)
  • ログイン状態に紐づく「再ログインを助ける」情報(※扱い注意)

基本的に入れない方がいいもの

  • 巨大データ(キャッシュ、画像、ログの塊)
  • 再取得可能なデータ(サーバから復元できるもの)
  • 端末固有の情報に依存するもの

バックアップ設計のコツは、「復元されたら嬉しいが、復元されなくても壊れない」に寄せることです。

前提:Manifest設定

まず Manifest でバックアップを有効化し、backupAgent を指定します。

<application
    android:allowBackup="true"
    android:backupAgent=".backup.MyBackupAgent"
    android:fullBackupContent="@xml/backup_rules"
    android:restoreAnyVersion="false">

    <!-- 省略 -->

</application>

ここでのポイント:

  • allowBackup が false だと当然動きません
  • backupAgent で自前のエージェントを指定
  • fullBackupContent は自動バックアップの対象制御(後述)

サンプル実装:BackupAgentHelperでSharedPreferencesをバックアップ

まず最短で動く構成です。

バックアップ対象:SharedPreferences

例として、”settings_prefs” という SharedPreferences をバックアップします。

package com.example.app.backup

import android.app.backup.BackupAgentHelper
import android.app.backup.SharedPreferencesBackupHelper

class MyBackupAgent : BackupAgentHelper() {

    override fun onCreate() {
        // どのデータをバックアップするかを登録する
        val prefsHelper = SharedPreferencesBackupHelper(
            this,
            "settings_prefs" // バックアップしたいSharedPreferences名
        )

        // "prefs" はバックアップキー(識別子)
        addHelper("prefs", prefsHelper)
    }
}

これだけで、SharedPreferencesの中身がバックアップ対象になります。

サンプル実装:ファイルをバックアップする

SharedPreferencesだけでなく、内部ファイルも対象にできます。

import android.app.backup.BackupAgentHelper
import android.app.backup.FileBackupHelper

class MyBackupAgent : BackupAgentHelper() {

    override fun onCreate() {
        val prefsHelper = SharedPreferencesBackupHelper(this, "settings_prefs")
        addHelper("prefs", prefsHelper)

        // files/ 配下の特定ファイルをバックアップ
        val filesHelper = FileBackupHelper(this, "user_cache.json")
        addHelper("files", filesHelper)
    }
}

ファイルを入れる時は「復元後に古い/不整合が起きないか」を必ず確認してください。
特にバージョンアップでフォーマットが変わると事故ります。

自動バックアップとの関係:fullBackupContent / dataExtractionRules

バックアップ周りは複数の仕組みが混在します。

  • backupAgent(Key/ValueやHelperでのバックアップ)
  • 自動バックアップ(フルバックアップ)

「何が対象になるか」を曖昧にすると、想定外のデータが入ったり、逆に必要なものが入らなかったりします。

実務では、バックアップ対象を明示して管理するのが安全です。

DataStoreをバックアップしたい場合の考え方

DataStoreは内部的にはファイルです。
なので「DataStoreをバックアップする」=「DataStoreファイルをバックアップする」になります。

ただ、DataStoreは移行や破損回避のために内部構造が変わることもあります。
運用としては次のどちらかに寄せると安全です。

  • バックアップ対象は「アプリの設定」だけに限定する(DataStore全体を丸ごとにしない)
  • 復元後に読み込み失敗しても初期値で立ち上がる設計にする

開発中の動作確認:adbでバックアップ/リストアを回す

ここが実務で一番ありがたい部分です。
「バックアップは端末任せでいつ発動するか分からない」ので、検証がしづらい。
だから adb で叩いて確認します。

前提

  • USBデバッグ有効
  • 対象端末が adb で見えている

1) バックアップを実行する(bmgr)

バックアップマネージャの操作は bmgr を使います。

adb shell bmgr backupnow <あなたのパッケージ名>

例:

adb shell bmgr backupnow com.example.app

2) バックアップ状態を確認する

adb shell bmgr list transports
adb shell bmgr status

端末や環境によってバックアップトランスポートが変わるので、ここで状況を把握します。

3) アプリデータを消す(復元テスト用)

本当に復元できているかを見るには、いったんアプリデータを消して復元します。

adb shell pm clear com.example.app

4) リストアを実行する

adb shell bmgr restore <あなたのパッケージ名>

例:

adb shell bmgr restore com.example.app

この後アプリを起動して、SharedPreferencesの値が戻っているか確認します。

よくあるハマりポイント

① allowBackup が false

基本中の基本ですが、これで詰まる人がいます。
「セキュリティのためにfalseにしていた」のを忘れがちです。

② バックアップ対象のPrefs名が違う

SharedPreferencesBackupHelper に渡す名前は、実際に保存している prefs 名と一致している必要があります。

③ 復元後にアプリが起動しなくなる

復元で古いデータが入った結果、データフォーマットが合わず例外が出るケースです。

バックアップ対象は最小限にして、復元後に壊れても初期値で立ち上がる設計が強いです。

④ 端末や設定でバックアップが無効

バックアップはユーザー設定や端末制限の影響を受けます。
「必ず復元される」前提で設計すると破綻します。

デバッグ/確認チェックリスト

  • Manifestで allowBackup と backupAgent が正しく設定されている
  • バックアップ対象を最小限にしている
  • SharedPreferences名・ファイル名が一致している
  • adbで backupnow → pm clear → restore の順で確認した
  • 復元データが壊れても初期値で起動できる

よくある質問(Q&A)

Q. login token もバックアップしていい?

推奨しません。セキュリティ上の理由だけでなく、端末が変わると無効になる設計も多いです。
「復元されたら嬉しい」より「復元されなくても困らない」に寄せた方が運用が安定します。

Q. SharedPreferencesを全部バックアップしていい?

できますが、やりすぎると復元後の整合性が崩れます。
「必要最小限のキーだけ」に寄せる方が安全です。

Q. DataStoreはどう扱えばいい?

DataStoreはファイルなのでバックアップは可能ですが、丸ごと復元はリスクもあります。
設定だけを抜き出すか、復元失敗しても初期値で復旧できる作りが強いです。

まとめ:独自バックアップは「対象の絞り込み」がすべて

  • backupAgentでバックアップ対象を明示できる
  • BackupAgentHelperで最短実装ができる
  • adbで backupnow → clear → restore のループが最速

迷ったら:バックアップ対象を減らす。
増やすのは後からでもできますが、増やしすぎの事故は戻すのが大変です。

コメント

タイトルとURLをコピーしました