Account Transfer API

ユーザーは、タップ&ゴーを使用して、既存の Android デバイスから新しい Android デバイスに Google アカウントとデータをコピーできます。Account Transfer API を使用すると、ユーザーは、AbstractAccountAuthenticator で実装されて AccountManager で統合されたカスタム アカウントの認証情報もコピーできるようになります。システムは、新しいデバイスで実行されているタップ&ゴー設定ウィザードから Account Transfer API を呼び出します。また、Account Transfer API を呼び出し、ケーブルを使用して Android スマートフォンから Pixel にデータを転送することもできます。

タップ&ゴーの開始画面。 タップ&ゴーのデータソース選択画面。

図 1. Account Transfer API は、新しいデバイスで実行されるタップ&ゴー設定ウィザードから呼び出されます。

カスタム アカウントの移行のサポートを追加するには、Account Transfer API をアプリに統合します。これにより、図 2 に示すように、Google Play 開発者サービスは、既存のデバイス(ソースデバイス)と新しいデバイス(ターゲット デバイス)の間で双方向の暗号化チャネルを確立し、アカウント データを転送できます。転送を完了するうえで、暗号化チャネルは、サードパーティのサーバーへの接続には依存しません。

Account Transfer API をアプリに統合するときは、次の要件を考慮してください。

  • ソースデバイスで Android 4.0.1(API レベル 14)以降を実行している必要があります。
  • ターゲット デバイスで Android 8.0(API レベル 26)以降を実行している必要があります。
  • ソースデバイスとターゲット デバイスの両方で、Google Play 開発者サービス バージョン 11.2.0 以降を実行している必要があります。
  • アプリは、Google Play 開発者サービス SDK バージョン 11.2.0 以降を使用して作成する必要があります。

ソースデバイスからターゲット デバイスへのアカウント転送のイラスト。

図 2. 転送は、Google Play 開発者サービスがソース デバイスとターゲット デバイスの間で確立した暗号化されたチャネルを介して行われます。

Account Transfer API をプロジェクトに追加する

Account Transfer API をプロジェクトで使用するには、まず Google Play 開発者サービス SDK でプロジェクトを設定する必要があります。Google Play 開発者サービス SDK のセットアップの詳しい手順については、Google Play 開発者サービスのセットアップをご覧ください。

Google Account Transfer API を選択的にアプリにコンパイルする場合は、アプリ モジュール ディレクトリ内の build.gradle ファイルの dependencies ブロックに次のビルドルールを追加します。

Groovy

plugins {
  id 'com.android.application'
}
...
dependencies {
    // VERSION_NUMBER must be equal to or higher than 11.2.0.
    implementation 'com.google.android.gms:play-services-auth:<VERSION_NUMBER>'
}

Kotlin

plugins {
    id("com.android.application")
}
...
dependencies {
    // VERSION_NUMBER must be equal to or higher than 11.2.0.
    implementation("com.google.android.gms:play-services-auth:<VERSION_NUMBER>")
}

カスタム アカウント転送のサポートを追加するには、アプリのマニフェストで認証システム サービスの START_ACCOUNT_EXPORT ブロードキャスト レシーバを宣言する必要があります。

<receiver android:name=".MyBroadcastReceiver"  android:exported="true">
    <intent-filter>
        <action android:name="com.google.android.gms.auth.START_ACCOUNT_EXPORT"/>
        ...
    </intent-filter>
</receiver>

OEM システム イメージにアプリがインストールされておらず、OEM システム イメージに配置する予定もない場合は、ソースデバイスで ACTION_START_ACCOUNT_EXPORT ブロードキャストをリッスンするように登録し、前述のようにアカウント データをエクスポートします。

OEM システム イメージにアプリをインストールする場合は、次のブロードキャストにも登録する必要があります。

アカウント データを移行する

ユーザーが既存のデバイスからコンテンツを復元することを選択すると、ACTION_START_ACCOUNT_EXPORT ブロードキャストがソースデバイス上の適切なアカウントに関連付けられたパッケージに送信されます。

アカウント データを送信する

アカウント データを送信するには、ソースデバイスで認証システム サービスを開始し、サービスが ACTION_START_ACCOUNT_EXPORT ブロードキャストを受信した後に sendData() を呼び出します。AccountTransferClient オブジェクトへの参照を取得するには、getAccountTransferClient(Context) または getAccountTransferClient(Activity) を呼び出します。 次のコード スニペットは、ソースデバイスからデータを送信する方法を示しています。

Kotlin

val client: AccountTransferClient = AccountTransfer.getAccountTransferClient(this)
val exportTask: Task<Void> = client.sendData(ACCOUNT_TYPE, transferBytes)
try {
    // Wait for the task to either complete or provide the callback.
    Tasks.await(exportTask, TIMEOUT_API, TIME_UNIT)
} catch (e: Exception) {
    when(e) {
        is ExecutionException, is InterruptedException, is TimeoutException -> {
            client.notifyCompletion(ACCOUNT_TYPE,
                    AuthenticatorTransferCompletionStatus.COMPLETED_FAILURE)
            return
        }
        else -> throw e
    }
}

Java

AccountTransferClient client = AccountTransfer.getAccountTransferClient(this);
Task<Void> exportTask = client.sendData(ACCOUNT_TYPE, transferBytes);
try {
  // Wait for the task to either complete or provide the callback.
  Tasks.await(exportTask, TIMEOUT_API, TIME_UNIT);
} catch (ExecutionException | InterruptedException | TimeoutException e) {
  client.notifyCompletion(ACCOUNT_TYPE,AuthenticatorTransferCompletionStatus.COMPLETED_FAILURE);
  return;
}

ターゲット デバイスの設定ウィザードでアカウント データを受信します。

アカウント データを受信する

このデバイスに同じ認証システムサービスがインストールされており、ACTION_ACCOUNT_IMPORT_DATA_AVAILABLE ブロードキャストをリッスンすることで対象が登録されている場合、ターゲット デバイスは、対応するパッケージに ACTION_ACCOUNT_IMPORT_DATA_AVAILABLE ブロードキャストを送信します。

ACTION_ACCOUNT_IMPORT_DATA_AVAILABLE ブロードキャストを受信したら、サービスを開始し、ターゲット デバイスで retrieveData() を呼び出して、ソースデバイスから送信されたデータを取得します。次のコード スニペットは、対象デバイスでデータを取得する方法を示しています。

Kotlin

val client: AccountTransferClient = AccountTransfer.getAccountTransferClient(this)
val transportTask: Task<Void> = client.retrieveData(ACCOUNT_TYPE)
try {
    val transferBytes: ByteArray = Tasks.await(transferTask, TIMEOUT_API, TIME_UNIT)
    // Add the transferred account(s) to AccountManager to register with the framework.
} catch (e: Exception) {
    when(e) {
        is ExecutionException, is InterruptedException, is TimeoutException -> {
            client.notifyCompletion(ACCOUNT_TYPE,
                    AuthenticatorTransferCompletionStatus.COMPLETED_FAILURE)
            return
        }
        else -> throw e
    }
 }
client.notifyCompletion(ACCOUNT_TYPE, AuthenticatorTransferCompletionStatus.COMPLETED_SUCCESS)

Java

AccountTransferClient client = AccountTransfer.getAccountTransferClient(this);
Task<Void> transferTask = client.retrieveData(ACCOUNT_TYPE);
try {
  byte[] transferBytes = Tasks.await(transferTask, TIMEOUT_API, TIME_UNIT);
  // Add the transferred account(s) to AccountManager to register with the framework.
} catch (ExecutionException | InterruptedException | TimeoutException e) {
  client.notifyCompletion(ACCOUNT_TYPE, AuthenticatorTransferCompletionStatus.COMPLETED_FAILURE);
  return;
}
client.notifyCompletion(ACCOUNT_TYPE, AuthenticatorTransferCompletionStatus.COMPLETED_SUCCESS);

転送を完了する

ターゲット デバイスの認証システム サービスは、必要に応じて、sendData() を呼び出してデータをソースデバイスに戻すこともできます。

ソースデバイスでデータを受信するには、認証システム サービスが ACTION_ACCOUNT_EXPORT_DATA_AVAILABLE ブロードキャストをリッスンする必要があります。同様に、ソースデバイスの認証システム サービスは、これ以降もターゲット デバイスにメッセージを送信できます。

転送が完了すると、認証システム サービスは適切な完了ステータスで notifyCompletion() を呼び出す必要があります。

セキュリティをさらに強化する必要がある場合は、ソースデバイスまたはターゲット デバイスのいずれかにユーザー向けの確認用画像を導入できます。まず、getDeviceMetaData() を呼び出してその結果を調べて、チャレンジを表示できるかどうかを確認します。ターゲット デバイスの認証システム サービスがチャレンジをサポートしている場合は、showUserChallenge() を呼び出してチャレンジを表示します。

転送時に必要な認証システム サービスがターゲット デバイスにインストールされていない場合、転送されたデータは一時的なローカル ストレージに保存されます。アプリを最初にインストールして開くときに、retrieveData() を呼び出して、一時的なローカル ストレージに利用可能なデータがあるかどうかを確認できます。利用可能なデータがある場合、Account Transfer API はそのデータを返します。データがない場合、呼び出しは失敗します。一時的なローカル ストレージにデータがない場合、それ以上データを取得しようとしても失敗する可能性があります。notifyCompletion() は失敗する可能性があるため、呼び出さないでください。

転送されたデータを一時的なローカル ストレージに保存するターゲット デバイスのイラスト。

図 3. 必要な認証システム サービスがターゲット デバイスにインストールされていない場合、転送されたデータは一時的なローカル ストレージに保存されます。

アカウントの移行をテストする

設定ウィザードは、新しいデバイスのセットアップ時に実行されます。デバイスのセットアップと移行をテストするために定期的に出荷時の設定にリセットするのは、面倒で時間がかかります。設定ウィザード フローの一部を実行して、デバイス間でユーザーのアカウントを移行するテストを行うこともできます。

テストを開始する前に、ソースデバイスに少なくとも 1 つのカスタム アカウントを作成してください。また、ターゲット デバイスがカスタム アカウントにログインしていないことも確認します。設定ウィザードの実行時にターゲット デバイスがカスタム アカウントにすでにログインしている場合、AccountManager.addAccountExplicitly() メソッドが呼び出されると、同じアカウントを追加しようとしても失敗します。

テストでは、Android 8.0(API レベル 26)以降を搭載するデバイスをターゲット デバイスとして使用する必要があります。

Android 4.0.1(API レベル 14)以降、Google Play 開発者サービス バージョン 11.2.0 以降を搭載するデバイスをソースデバイスとして使用できます。テスト用の APK を作成するには、Google Play 開発者サービス SDK バージョン 11.2.0 以降が必要です。

設定ウィザードのフローをテストするには、ターゲット デバイスで次のコマンドを実行します。

$ adb shell am start -a android.intent.action.MAIN -n com.google.android.gms/.smartdevice.d2d.ui.TargetActivity

このコマンドにより、アクティビティが起動し、設定ウィザードが表示されて、テストデバイスを別のデバイスとペア設定する準備が整います。デバイスの接続が確立したら、アカウントの移行プロセスを開始できます。