2010年5月31日月曜日

Android Android 2.2 データバックアップ

これを書いた 2010/5/31 にはなかった Registering for Android Backup Service という項が追加されていたので、追記しました。 2011/1/1


Android - Froyo - Data Backup

Android 2.2 からアプリケーションのデータのバックアップができるようになりました。
これまでは、アプリケーションのデータベースなどに保存されていたデータは、アプリケーションをアインストールすると削除されていました(アップデート時は保持される)。そのため、再インストール時(一度アインストールしてから、再びインストール)や、別の端末に切り替えたとき、そのデータを移行することができませんでした。
Froyo からはそれができるようになります。




元の記事はこちら↓
http://developer.android.com/intl/ja/sdk/android-2.2.html#api


Android 2.2 から、プラットフォームは 一般的なバックアップサービスを提供するようになりました。
これにより、ユーザーがデバイスを切り替えたり、アプリケーションを再インストールしたときに、ユーザーのデータを維持できるように、アプリケーションはユーザのデータをバックアップしリストアできるようになりました。
Backup Manager はアプリケーションのデータを、クラウド内のバックアップストレージ領域へ/から転送する動作を処理します。
Backup Manager は任意のデータからファイルまで、どんなタイプのデータも保存でき、バックアップと復元操作を管理します。
より詳しい情報は Data Backup を参照してください。




Data Backup

元の記事はこちら↓
ttp://developer.android.com/guide/topics/data/backup.html

Android's backup serveice によって、アプリケーションのデータをリモートの "cloud" ストレージにコピーすることができます。この "cloud" ストレージは、アプリケーションデータや設定情報のリストアポイントを提供するためのものです。
もし、ユーザーがファクトリーリセットをしたり、新しい Android デバイスに切り替えた場合、システムはアプリケーションのインストール時に、自動的にユーザーのバックアップデータをリストアします。
この方法によって、ユーザーはそのアプリケーションの以前のデータや設定情報を再生成する必要がなくなります。
このプロセスはユーザーに完全に透明で、アプリケーションの機能やユーザーエクスペリエンスに影響をあたえることはありません。


backup service が提供されている Android搭載デバイスは、アプリケーションのバックアップデータを保存するためのクラウドストレージ領域と、データをストレージ領域に届けデバイスに戻すためのバックアップ転送を提供します。
バックアップ操作の間、Android's Backup Manager はアプリケーションからバックアップデータを要求し、それをバックアップ転送を使ってクラウドストレージへ届けます。
リストア操作の間は、Backup Manager はバックアップ転送からバックアップデータを受け取り、それをアプリケーションに返します。そのため、アプリケーションはデバイスにデータをリストアできます。
backup service はデータ同期用にデザインされていません。
(デバイスへのリストア処理時以外は、バックアップデータへのアクセス権はありません)


バックアップに使われるクラウドストレージは必ずしも全ての Android 搭載デバイス上で同じである必要はありません。クラウドストレージとバックアップ転送は複数のデバイスとサービスプロバイダーの間で異なることがあります。
保存されたバックアップデータは、そのアプケーションに対して透明ですが、そのアプリケーションのデータは他のアプリケーションから読めないことが保証されています。


注意:クラウドストレージと転送サービスはデバイス間で異なることがあるので、Android はバックアップされるデータのセキュリティについて保障しません。あなたは、ユーザー名やパスワードのような機密データを保存する場合、バックアップの使用について慎重になる必要があります。



The Basics

アプリケーションのバックアップをするためには、backup agent を実装する必要があります。

Backup Manager から呼ばれる backup agent はユーザーがバックアップしたいデータを提供します。また、アプリケーションが再インストールされたときに、バックアップデータをリストアするためにも呼ばれます。Backup Manager はクラウドストレージでの全てのユーザーデータトランザクションを処理します。一方、backup agent はデバイス上での全てのユーザーデータトランザクションを処理します。

backup agent を実装するには

 1. AndroidManifest.xml の android:backupAgent 属性で
  backup agent を宣言する

 2. backup agent を定義する(方法は次のいずれか)

  a. BackupAgent を拡張する   
    BackupAgent クラスは、アプリケーションが BackupManager と
    通信するための中心的インタフェースを提供します。もし、
    このクラスを直接拡張したいなら、データのバックアップと
    リストアを処理するための onBackup()onRestore()
    オーバーライドしなければなりません。

  b. BackupAgentHelper を拡張する   
    BackupAgentHelper クラスは BackupAgent クラスの便利な
    ラッパーを提供します。これにより、書くべきコード量が
    最小化できます。 BackupAgentHelper 内で、特定のタイプの
    データを自動でバックアップ・リストアするために、1つ以上の
    "helper" オブジェクトを使う必要があります。
    この場合、onBackup() と onRestore() を実装する必要は
    ありません。

  Android で現在提供されている backup helper は、SharedPreferencesinternal storage の完全なファイルをバックアップ・リストアします。



Declaring the Backup Agent in Your Manifest

まず、backup agent のクラス名を決めます。
次に、AndroidManifest.xml の <application> タグ内の android:backupAgent 属性でそのクラスを宣言します。

例えば、

<manifest ... >
<application android:label="MyApplication"
android:backupAgent="MyBackupAgent">
<activity ... >
...
</activity>
</application>
</manifest>


これ以外に関係ある属性として、android:restoreAnyVersion があります。
この属性は boolean値をとり、バックアップデータを生成したときのアプリケーションのバーションと、現在のバーションの比較に関係なくアプリケーションのデータをリストアしたいかどうかを表します。(デフォルトは "false")より詳しい情報は Checking the Restore Data Version を見てください。

注: backup service とその API は API Level 8 (Android 2.2) もしくはそれ以上で走っているデバイス上でのみ使用可能なため、"android:minSdkVerions" 属性は 8 に設定すべきです。しかし、もしアプリケーションで適切な後方互換性を実装するなら、古いデバイスとの互換性を維持しながら、API Level 8 以上のデバイスに対してこの機能をサポートすることができます。


Registering for Android Backup Service

Android 2.2 以上が走っているデバイスに対して、Google は Android Backup Service を使った backup 転送を提供します。

Android Backup Service を使った backup をアプリケーションで行うために、Backup Service Key を受信するためのサービスにアプリケーションを登録しなければなりません。受け取った Backup Service Key はアプリケーションの Android manifest で定義します。

Backup Service Key を取得するには、Android Backup Service に登録します。登録すると、Backup Service Key が提供されるので、適切な <meta-data> XML コードとともに Android manifest の <application< エレメント内に定義します。


<application android:label="MyApplication"
android:backupAgent="MyBackupAgent">
...
<meta-data android:name="com.google.android.backup.api_key"
android:value="INSERT YOUR API KEY HERE" />
</application>


android:name には "com.google.android.backup.api_key" を指定し、android:value には Android Backup Service 登録で受け取った Backup Service Key を指定します。

注意: Android Backup Service によって提供される backup 転送は、backup をサポートする全ての Android 搭載デバイスで使用できることを保証しません。いくつかのデバイスは異なる転送を使ったバックアップをサポートし、いくつかのデバイスはバックアップ自体をサポートしないでしょう。デバイスがどの転送を使っているのかアプケーションから知る方法はありません。アプリケーションがバックアップを実装するなら、常に Backup Service Key を含むことで、デバイスが Android Backup Service 転送を使う場合にバックアップを実行することができます。デバイスが Android Backup Service を使わない場合は、Backup Service Key 用の <meta-data> エレメントは無視されます。


Extending BackupAgent

 一般的ではないので、後回し
 いずれ書きます。。。




Extending BackupAgentHelper

BackupAgentHelper の実装では、1つ以上の backup helpers を使う必要があります。
backup helper は BackupAgentHelper が特定のタイプのデータをバックアップ・リストアするために召喚する専用のコンポーネントです。
現在のフレームワークでは次の2つが提供されています。

 ・SharedPreferencesBackupHelper
    SharedPreferences のファイルをバックアップする

 ・FileBackupHelper
    internal storage のファイルをバックアップする


BackupAgentHelper には複数の helper を持たせることができますが、各データタイプに対して helper が1つあれば十分です。つまり、もし複数の SharedPreferences ファイルを持っていても、必要な SharedPreferencesBackupHelper は1つだけです。


BackupAgentHelper に追加したい各 helper に対して、 onCreate() で以下の処理が必要です。

  1. 必要な helper クラスのインスタンスを作成し、クラスの
   コンストラクタで、バックアップしたい適切なファイルを指定する


  2. addHelper() を呼んで、 helper を BackupAgentHelper に
   追加する



例1 Backing up SharedPreferences

こんな感じ


public class MyPrefsBackupAgent extends BackupAgentHelper {
// The name of the SharedPreferences file
static final String PREFS = "user_preferences";

// A key to uniquely identify the set of backup data
static final String PREFS_BACKUP_KEY = "prefs";

// Allocate a helper and add it to the backup agent
public void onCreate() {
SharedPreferencesBackupHelper helper = new SharedPreferencesBackupHelper(this, PREFS);
addHelper(PREFS_BACKUP_KEY, helper);
}
}


ここで、 "user_preferences" が SharedPreferences ファイルの名前です。
これで全体の backup agent は完成です。
Backup Manager が onBackup() や onRestore() を読んだとき、BackupAgentHelper はバックアップ・リストア処理を行うために backup helpers を呼びます。

注: SharedPreferences はスレッドセーフなので、backup agent と 他のアクティビティの間で安全に shared preferences の読み・書きができます。


例2 Backing up other files

FileBackupHelper のインスタンスを作成する場合、アプリケーションの internal storage に保存されている1個以上のファイル名を含める必要があります。
(internal storage は、getFilesDir() で指定されたディレクトリで、openFileOutput() でファイルが書き込まれる場所と同じです。)

こんな感じ


public class MyFileBackupAgent extends BackupAgentHelper {

// The name of the file in internal storage
static final String TOP_SCORES = "scores";
static final String PLAYER_STATS = "stats";

// A key to uniquely identify the set of backup data
static final String FILES_BACKUP_KEY = "myfiles";

// Allocate a helper and add it to the backup agent
public void onCreate() {
FileBackupHelper helper = new FileBackupHelper(this, TOP_SCORES, PLAYER_STATS);
addHelper(FILES_BACKUP_KEY, helper);
}
}


ここで、"scores" と "stats" は internal storage 内のファイル名です。

FileBackupHelper は アプケーションの internal storage 保存されたファイルをバックアップ&リストアするのに必要な全コードを含みます。

しかし、internal storage のファイルへの書き込み/読み出しはスレッドセーフではありません
backup agent はアクティビティと同時に読み/書きしないことを保証するために、読み/書きを実行するごとに同期された状態を使わなければなりません。
例えば、あるファイルを読み/書きするアクティビティでは、同期された状態のために intrinsic lock として使うオブジェクトが必要です。

こんな感じで定義

// Object for intrinsic lock
static final Object[] sDataLock = new Object[0];


Interesting Fact:
長さ 0 の配列は、通常のオブジェクトよりも軽い、なので intrinsic lock に最適!

そして、ファイルを読み/書きする毎にこの lock を使って同期された状態を生成します。

例えば、こんな感じ

try {
synchronized (MyActivity.sDataLock) {
File dataFile = new File(getFilesDir(), TOP_SCORES);
RandomAccessFile raFile = new RandomAccessFile(dataFile, "rw");
raFile.writeInt(score);
}
} catch (IOException e) {
Log.e(TAG, "Unable to write to file");
}


同じ lock を使って、読み込み状態も同期します。

そして、 BackupAgentHelper で、同じ intrinsic lock を使ってバックアップとリストア操作を同期させるために onBackup() と onRestore() を Override しなければなりません。

例えば、こんな感じ

@Override
public void onBackup(ParcelFileDescriptor oldState, BackupDataOutput data,
ParcelFileDescriptor newState) throws IOException {
// Hold the lock while the FileBackupHelper performs backup
synchronized (MyActivity.sDataLock) {
super.onBackup(oldState, data, newState);
}
}

@Override
public void onRestore(BackupDataInput data, int appVersionCode,
ParcelFileDescriptor newState) throws IOException {
// Hold the lock while the FileBackupHelper restores the file
synchronized (MyActivity.sDataLock) {
super.onRestore(data, appVersionCode, newState);
}
}


サンプルプロジェクトはこちら
http://developer.android.com/resources/samples/BackupRestore/index.html




Checking the Restore Data Version

Backup Manager がデータをクラウドストレージに保存した時、自動的にアプリケーションのバージョン(AndroidManifest.xml の android:versionCode 属性の値)も一緒に保存されます。
データをリストアするために backup agent を呼ぶ前に、Backup Manager は、インストールされているアプリケーションの android:versionCode を見に行き、リストアされるデータセットに記録されているバージョン値と比較します。
もし、記録されているバージョン値がデバイス上のアプリケーションのバージョンよりも新しい場合、ユーザーはアプリケーションをダウングレードしていることになります。この場合、Backup Manager はリストア操作を中止し、onRestore() を呼びません。なぜなら、リストアセットは古いバージョンには無意味と考えられるためです。

android:restoreAnyVersion 属性を設定することで、この振舞を override することができます。
この属性は "true" もしくは "false" を取り、リストアセットのバージョンにかかわらずアプリケーションのデータをリストアするかどうかを示します。
デフォルトの値は "false " です。もし、この属性を "true" に設定した場合、Backup Manager は android:versionCode の値を無視し、いつでも onRestore() を呼びます。そうすると、onRestore() でバージョンの違いをマニュアル的にチェックすることができ、バージョン競合の場合にデータ互換性を保つために必要な処理を行うことができます。

リストア操作のときに異なるバージョンを扱う手助けとして、onResotre() の第2引数で、リストアデータにセットされたバージョンコードを取得することができます。
onRestore (BackupDataInput data, int appVersionCode, ParcelFileDescriptor newState)

アプリケーションの現在のバージョンは PackageInfo.versionCode で取得できる。
こんな感じ

@Override
public void onRestore (onRestore(BackupDataInput data, int appVersionCode, ParcelFileDescriptor newState) {
super.onRestore(data, appVersionCode, newState);

PackageInfo info;
try {
String name = getPackageName();
info = getPackageManager().getPackageInfo(name,0);
} catch (NameNotFoundException nnfe) {
info = null;
}

if (info != null) {
if (appVersionCode != info.versionCode) {
....
}
else
....
}
}
}


注意:android:restoreAnyVersion 設定を "true" にした場合の特定の結果について理解してください。もし、バックアップをサポートしているアプリケーションの各バージョンにデータフォーマットの変動がある場合を onResore() 内で適切に扱わない場合、、デバイス上のデータは、現在インストールされているバージョンと非互換の形式で保存されます。




Requesting Backup

バックアップ操作は dataChanged() を呼ぶことでいつでも要求できます。このメソッドは Backup Manager に backup agent を使ってデータをバックアップしたいことを知らせます。そうすると、Backup Manager は呼び出しが可能になった時点で、backup agent の onBackup() を呼び出します。 典型的に、データが変化した毎にバックアップを要求すべきです。(例えば、ユーザーがバックアップしておきたいアプリケーションの設定を変更したときなど)
もし、複数回連続して dataChanged() を呼び出すと、Backup Manager が agent からバックアップを1回要求する前に、agent はまだ onBackup() を1回だけ受け取ります。

Note: アプリケーションを開発している間は、 bmgr tool を使うことで、バックアップを要求することができ、すぐにバックアップを開始することができます。




Requesting Restore

通常のライフサイクルでは、リストア操作要求する必要はありません。システムが自動的にバックアップデータをチェックして、アプリケーションのインストール時にリストアを実行します。しかし、もし必要ならば requestRestore() を呼ぶことで、マニュアル的にリストア操作を要求することができます。この場合、 Backup Manager は onRestore() 実装を呼び、バックアップデータの現在のセットからデータを渡します。




Developing and Testing Your Backup Agent

backup agent の 開発とテスト :

 Backup Agent をテストするには、bmgr toolを使って、次の手順を行ないます。

 1. アプリケーションを適切な Android system image にインストールする

  ・ エミュレータを使う場合は Android 2.2 (API Level 8)
    以上のAVDを作成する

  ・ デバイスを使う場合は、Android 2.2 以上が走っていて、
    かつビルトインの Android Market がインストールされている
    デバイスが必要


 2. バックアップを有効にする

  ・ エミュレータを使う場合、SDK tools/ 内の adb コマンドを使う

  ・ デバイスを使う場合、設定(Setting) → プライバシー(Privacy) で
    データのバックアップ(Back up my data) と 自動復元
    (Automatic restore) を有効にする

< adb shell bmgr enable true


 3. アプリケーションを起動して、いくつかのデータを初期化する

  データの変化時に dataChanged() メソッドを呼ぶなど適切に
  バックアップ処理が実装されている場合は、Backup Manager
  キューにバックアップリクエストが追加される。
  テストを目的として次のコマンドでリクエストを生成することができる


< adb shell bmgr backup your.package.name


 4. バックアップ処理を初期化する

  Backup Manager にキュー内の全てのバックアップリクエストを処理させる


< adb shell bmgr run


 5. アプリケーションをアンインストールする


< adb uninstall your.package.name


 6. アプリケーションを再インストールする

backup agent が成功していれば、step 4 で初期化したデータがリストアされる

1 件のコメント:

  1. 詳しく教えてくれてありがとうございます。
    Androidデバイスのデータバックアップについて、Coolmuster Android助手ができます。
    ご参照リンク:http://www.coolmuster.jp/android-assistant/
    ここで一緒に共有します。

    返信削除