Android のアプリ切り替え

OAuth 2.0 を実装すると、OAuth ベースの を設定できるようになります。 を使うと、Android ユーザーは、デベロッパーの認証システムに登録されているアカウントを、自分の Google アカウントに簡単にリンクできます。App Flip以降のセクションでは、Android での Cloud-to-cloud 統合用に App Flip を設計して実装する方法について説明します。

設計ガイドライン

このセクションでは、App Flip のアカウント リンクの同意画面の設計要件と推奨事項について説明します。Google がアプリを呼び出すと、アプリはユーザーに同意画面を表示します。

要件

  1. 「リンクすると、Google はデバイスを操作する権限を取得します。」などの Google 認証ステートメントが必要です。
  2. ユーザーのアカウントが Google にリンクされることを伝える必要があります。Google Home や Google アシスタントなどの特定の Google サービスにリンクされるのではないことを伝える必要があります。
  3. 同意画面に明確な行動を促すフレーズを記載し、リンク アクションには「同意してリンク」という文言を使用する必要があります。これは、アカウントをリンクするために Google と共有する必要があるデータをユーザーが理解する必要があるためです。
  4. ユーザーがリンクしないことを選択した場合、ユーザーが戻ったり、拒否したり、キャンセルしたりする方法を提供する必要があります。キャンセル アクションには「キャンセル」という文言を使用します。
  5. このワークフローを実装する必要があります。つまり、[同意してリンク] をクリックした後、リンクが成功したことを表示し、ユーザーを Google Home アプリに自動的にリダイレクトする必要があります。これで、ユーザーの Google Home アプリに、リンクされたデバイスとアクションが表示されます。[キャンセル] をクリックしたら、ユーザーを Google Home アプリにリダイレクトする必要があります。

推奨事項

次のことをおすすめします。

  1. Google のプライバシー ポリシーを表示します。同意画面に Google のプライバシー ポリシーへのリンクを含めます。

  2. 共有されるデータ。明確で簡潔な表現を使用して、Google がユーザーのどのデータを必要としているか、またその理由をユーザーに伝えます。

  3. リンクを解除できること。ユーザーがリンクを解除できる仕組み(プラットフォームのアカウント設定への URL など)を提供します。または、ユーザーがリンクされたアカウントを管理できる Google アカウントへのリンクを含めることもできます。

  4. ユーザー アカウントを変更する機能。ユーザーがアカウントを切り替える方法を提案します。これは、ユーザーが複数のアカウントを持っている場合に特に便利です。

    • ユーザーがアカウントを切り替えるために同意画面を閉じる必要がある場合は、回復可能なエラーを Google に送信して、ユーザーが OAuth リンクとインプリシット フローを使用して目的のアカウントにログインできるようにします。
  5. ロゴを含めます。同意画面に会社のロゴを表示します。スタイル ガイドラインに沿ってロゴを配置します。Google のロゴも表示する場合は、ロゴと商標をご覧ください。

この図は、ユーザーの同意画面を設計する際に従うべき個々の要件と推奨事項を説明する吹き出しが付いた同意画面の例を示しています。
図 1: アカウント リンクの同意画面の設計ガイドライン。

OAuth ベースの App Flip を設定する

以下のセクションでは、OAuth ベースのアプリ切り替えの前提条件と、アプリ切り替えプロジェクトを Google Home Developer Console で設定する方法について説明します。

Cloud-to-cloud 統合を作成して OAuth 2.0 サーバーを設定する

App Flip を構成する前に、次のことを行う必要があります。

Developer Console でアプリ切り替えを設定する

次のセクションでは、Developer Console でアプリ切り替えを構成する方法を説明します。

  1. [Account Linking](アカウントのリンク)のすべての必須(*)項目に入力します。(アプリ切り替えがサポートされていない場合は、通常の OAuth がフォールバックとして使用されます)。
  2. Cloud フルフィルメント URL の URL を指定します。クラウド フルフィルメント URL は、スマートホーム インテントの処理に使用されます。[ローカル フルフィルメント] をオンにします。
  3. [アプリ切り替え (optional)] で、[Android アプリ] をオンにします。
  4. 次の各項目を入力します。
    • アプリケーション ID。アプリケーション ID は、アプリに設定する一意の ID です。
    • [App signature](アプリ署名)。Android アプリは、インストールする前に公開鍵証明書で署名しておく必要があります。アプリ署名の取得について詳しくは、クライアントの認証をご覧ください。
    • [Authorization intent](認証インテント)。ここには、インテントのアクションを指定する文字列を入力します。
  5. クライアントを設定したい場合は、スコープを追加し、[Scopes(s) (optional)](スコープ(省略可))で [Add scope](スコープを追加)をクリックします。
  6. クライアントで必要な場合は、[Google が HTTP 基本認証ヘッダーを介してクライアント ID とシークレットを送信する] を選択します。

次のセクションでは、Android アプリに App Flip を実装します。

ネイティブ アプリに App Flip を実装する

App Flip を実装するには、Google からのディープリンクを許可するようにアプリのユーザー認可コードを変更する必要があります。

OAuth ベースのアプリ切り替えリンク(アプリ切り替え)は、Android アプリを Google アカウントのリンクフローに挿入します。従来のアカウント リンクフローでは、ユーザーがブラウザで認証情報を入力する必要があります。アプリ切り替えを使用すると、ユーザーのログインが Android アプリに延期されるため、既存の認可を活用できます。ユーザーがアプリにログインしている場合、アカウントをリンクするために認証情報を再入力する必要はありません。Android アプリにアプリ切り替えを実装するために必要なコード変更は最小限です。

このドキュメントでは、アプリ切り替えをサポートするように Android アプリを変更する方法について説明します。

サンプルを試す

アプリ切り替え リンクのサンプルアプリは、Android でのアプリ切り替え 互換のアカウント リンク統合を示しています。このアプリを使用すると、Google モバイルアプリから受信したアプリ切り替えインテントへの応答方法を確認できます。

サンプルアプリは、Android 用 App Flip テストツールと統合するように事前構成されています。このツールを使用すると、Google とのアカウント リンクを構成する前に、Android アプリとアプリ切り替えの統合を検証できます。このアプリは、アプリ切り替えが有効になっているときに Google モバイルアプリによってトリガーされるインテントをシミュレートします。

仕組み

アプリ切り替えの統合を行うには、次の手順が必要です。

  1. Google アプリは、パッケージ名を使用して、アプリがデバイスにインストールされているかどうかを確認します。
  2. Google アプリは、パッケージ署名チェックを使用して、インストールされているアプリが正しいアプリであることを確認します。
  3. Google アプリは、アプリで指定されたアクティビティを開始するインテントを構築します。このインテントには、リンクに必要な追加データが含まれています。また、Android フレームワークを介してこのインテントを解決することで、アプリがアプリ切り替えをサポートしているかどうかも確認します。
  4. アプリは、リクエストが Google アプリから送信されていることを検証します。そのために、アプリはパッケージ署名と提供されたクライアント ID を確認します。
  5. アプリが OAuth 2.0 サーバーに認可コードをリクエストします。このフローの最後に、認可コードまたはエラーが Google アプリに返されます。
  6. Google アプリは結果を取得し、アカウントのリンクを続行します。認可コードが提供されると、ブラウザベースの OAuth リンクフローと同じように、サーバー間でトークン交換が行われます。

アプリ切り替えをサポートするように Android アプリを変更する

アプリ切り替えをサポートするには、Android アプリのコードを次のように変更します。

  1. [アプリ切り替えインテント] フィールドに入力した値と一致するアクション文字列を含む <intent-filter> を AndroidManifest.xml ファイルに追加します。

    <activity android:name="AuthActivity">
      <!-- Handle the app flip intent -->
      <intent-filter>
        <action android:name="INTENT_ACTION_FROM_CONSOLE"/>
        <category android:name="android.intent.category.DEFAULT"/>
      </intent-filter>
    </activity>
    
  2. 呼び出し元アプリの署名を検証します。

    ユーザーがアカウントのリンクに使用する可能性のある Google アプリのパッケージ名と署名を一致させる必要があります。たとえば、Google Home アプリと Google 検索アプリにリンクするには、それらのパッケージ名と署名を追加します。

    • Package name: com.google.android.apps.chromecast.app
    • 元の SHA-256 リネージ証明書: 3D:7A:12:23:01:9A:A3:9D:9E:A0:E3:43:6A:B7:C0:89:6B:FB:4F:B6:79:F4:DE:5F:E7:C2:3F:32:6C:8F:99:4A
    • ローテーションされた Play アプリ署名の SHA-256 証明書: 5A:AD:2B:EE:6D:B9:5D:17:E0:5A:08:D7:D1:E6:4C:10:A1:51:18:79:15:44:83:91:6B:6A:E6:C7:FD:9C:B0:C6

    と

    • Package name: com.google.android.googlequicksearchbox
    • 署名: F0:FD:6C:5B:41:0F:25:CB:25:C3:B5:33:46:C8:97:2F:AE:30:F8:EE:74:11:DF:91:04:80:AD:6B:2D:60:DB:83

    スマートホームのリンク リクエストは、Google Home app (GHA) によって直接開始されます。アプリで呼び出し元を制限しており、以前は Google 検索アプリのみを許可していた場合は、アプリ切り替えが引き続き成功するように、com.google.android.apps.chromecast.app とその SHA-256 証明書を許可リストに追加する必要があります。

    private fun verifyFingerprint(
        expectedPackage: String,
        expectedFingerprints: List<String>
    ): Boolean {
        val callingPackage = callingActivity?.packageName ?: return false
        if (callingPackage != expectedPackage) return false
        return expectedFingerprints.any { hex ->
            val sha256Bytes =
                hex.split(":").map { it.toInt(16).toByte() }.toByteArray()
            packageManager.hasSigningCertificate(
                callingPackage,
                sha256Bytes,
                PackageManager.CERT_INPUT_SHA256
            )
        }
    }
    
  3. インテント パラメータからクライアント ID を抽出し、クライアント ID が想定値と一致することを確認します。

    private const val EXPECTED_CLIENT = "<client-id-from-actions-console>"
    private const val EXPECTED_PACKAGE = "com.google.android.apps.chromecast.app"
    // Original lineage certificate (3D:7A...) and active rotated
    // Play App Signing certificate (5A:AD...)
    private val EXPECTED_FINGERPRINTS = listOf(
        "3D:7A:12:23:01:9A:A3:9D:9E:A0:E3:43:6A:B7:C0:89:6B:FB:4F:B6:79:F4:DE:5F:E7:C2:3F:32:6C:8F:99:4A",
        "5A:AD:2B:EE:6D:B9:5D:17:E0:5A:08:D7:D1:E6:4C:10:A1:51:18:79:15:44:83:91:6B:6A:E6:C7:FD:9C:B0:C6"
    )
    ...
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
    
        val clientId = intent.getStringExtra("CLIENT_ID")
    
        if (clientId == EXPECTED_CLIENT &&
            verifyFingerprint(EXPECTED_PACKAGE, EXPECTED_FINGERPRINTS)) {
    
            // ...authorize the user...
        }
    }
    
  4. 認可が成功したら、結果の認可コードを Google に返します。

    // Successful result
    val data = Intent().apply {
        putExtra("AUTHORIZATION_CODE", authCode)
    }
    setResult(Activity.RESULT_OK, data)
    finish()
    
  5. エラーが発生した場合は、代わりにエラー結果を返します。

    // Error result
    val error = Intent().apply {
        putExtra("ERROR_TYPE", 1)
        putExtra("ERROR_CODE", 1)
        putExtra("ERROR_DESCRIPTION", "Invalid Request")
    }
    setResult(-2, error)
    finish()
    

起動インテントの内容

アプリを起動する Android のインテントには次のフィールドがあります。

  • CLIENT_ID(String): アプリに登録されている Google client_id。
  • SCOPE(String[]): リクエストされたスコープのリスト。
  • REDIRECT_URI(String): リダイレクト URL。

レスポンス データの内容

Google アプリに返されるデータは、setResult() を呼び出すことでアプリに設定されます。このデータには次のものが含まれます。

  • AUTHORIZATION_CODE(String): 認証コードの値。
  • resultCode(int): プロセスの成功または失敗を通知します。次のいずれかの値を取ります。
    • Activity.RESULT_OK: 成功を示します。認証コードが返されます。
    • Activity.RESULT_CANCELLED: 回復可能なエラー。ユーザーがプロセスをキャンセルしたことを示します。この場合、Google アプリは、認可 URL を使用してアカウントのリンクを再度試みます。
    • -2: エラーが発生したことを示します。さまざまな種類のエラーについて、以下で説明します。
  • ERROR_TYPE(int): エラーのタイプ。次のいずれかの値を取ります。
    • 1: 回復可能なエラー。Google アプリは、認証 URL を使用してアカウントのリンクを試みます。
    • 2: 修復不可能なエラー。Google アプリがアカウントのリンクを中止します。
    • 3: リクエスト パラメータが無効であるか、不明です。
  • ERROR_CODE(int): エラーの性質を表す整数。各エラーコードの意味については、エラーコードの表をご覧ください。
  • ERROR_DESCRIPTION(String、省略可): エラーを説明する、人が読める形式のステータス メッセージ。

resultCode == Activity.RESULT_OK の場合、AUTHORIZATION_CODE の値が必要です。それ以外の場合、AUTHORIZATION_CODE の値は空にする必要があります。resultCode == -2 の場合、ERROR_TYPE 値が入力されることが想定されます。

エラーコードの表

次の表に、さまざまなエラーコードと、それぞれが回復可能なエラーか修復不可能なエラーかを示します。

エラーコード 意味 回復できる 回収不可
1 INVALID_REQUEST ✔
2 NO_INTERNET_CONNECTION ✔
3 OFFLINE_MODE_ACTIVE ✔
4 CONNECTION_TIMEOUT ✔
5 INTERNAL_ERROR ✔
6 AUTHENTICATION_SERVICE_UNAVAILABLE ✔
8 CLIENT_VERIFICATION_FAILED ✔
9 INVALID_CLIENT ✔
10 INVALID_APP_ID ✔
11 INVALID_REQUEST ✔
12 AUTHENTICATION_SERVICE_UNKNOWN_ERROR ✔
13 AUTHENTICATION_DENIED_BY_USER ✔
14 CANCELLED_BY_USER ✔
15 FAILURE_OTHER ✔
16 USER_AUTHENTICATION_FAILED ✔

すべてのエラーコードについて、適切なフォールバックがトリガーされるように、setResult を介してエラー結果を返す必要があります。

デバイスで App Flip をテストする

Cloud-to-cloud 統合を作成し、コンソールとアプリでアプリ切り替えを設定したら、モバイル デバイスでアプリ切り替えをテストできます。Google Home アプリを使用してアプリ切り替えをテストできます。

Google Home アプリから App Flip をテストする手順は次のとおりです。

  1. Developer Console に移動して、プロジェクトを選択します。
  2. [Cloud-to-cloud] > [Test] に移動します。
  3. Home アプリからアカウントのリンクフローをトリガーします。
    1. Google Home app (GHA) を開きます。
    2. [+] ボタンをクリックします。
    3. [デバイスのセットアップ] をクリックします。
    4. [セットアップ済みデバイスのリンク] をクリックします。
    5. プロバイダのリストから、Cloud-to-cloud 統合を選択します。リストの先頭に「[test]」が付きます。リストから [test] 統合を選択する場合、アプリを開く必要があります。
    6. アプリが起動したことを確認し、承認フローのテストを開始します。