カスタム アカウント タイプを作成する

これまで、Google が定義したアカウントとユーザーを使用する Google API へのアクセスについて説明してきました。ただし、独自のオンライン サービスをお持ちの場合、そこには Google アカウントや Google ユーザーはありません。では、どうすればよいでしょうか?ユーザーのデバイスに新しいアカウント タイプをインストールするのは比較的簡単です。このレッスンでは、組み込みのアカウントと同じように機能するカスタム アカウント タイプの作成方法を説明します。

カスタム アカウントのコードを実装する

最初に必要なのは、ユーザーから認証情報を取得する方法です。これは、名前とパスワードを要求するダイアログ ボックスと同じくらい簡単です。または、ワンタイム パスワードや生体認証スキャンのような、もっと変わった手順の場合もあります。どちらにせよ、次のようなコードを実装する必要があります。

  1. ユーザーから認証情報を収集する
  2. サーバーで認証情報を認証する
  3. デバイスに認証情報を保存する

通常、これら 3 つの要件はすべて 1 つのアクティビティで処理できます。これを認証システム アクティビティと呼ぶことにします。

認証システム アクティビティは AccountManager システムとやり取りする必要があるため、通常のアクティビティにはない要件があります。Android フレームワークに用意されている基本クラス AccountAuthenticatorActivity を拡張すると、独自のカスタム認証システムを簡単に作成できます。

認証システム アクティビティの最初の 2 つの要件である、認証情報の収集と認証は、すべて作成者に委ねられています(方法が 1 つしかなければ、「カスタム」アカウント タイプを作成する必要はありません)。3 つ目の要件には、標準的で簡単な実装があります。

Kotlin

    Account(username, your_account_type).also { account ->
        accountManager.addAccountExplicitly(account, password, null)
    }
    

Java

    final Account account = new Account(username, your_account_type);
    accountManager.addAccountExplicitly(account, password, null);
    

セキュリティにご注意!

AccountManager は暗号化サービスでもキーチェーンでもないことを理解することが重要です。アカウントの認証情報は、渡されたままの平文で保存されます。ほとんどのデバイスでは、ルートのみがアクセスできるデータベースに保存されるため、特に問題はありません。しかし、ユーザーにルート権限のあるデバイスでは、adb でデバイスにアクセスできれば誰でも認証情報を読み取ることができます。

このことを念頭に置いて、ユーザーの実際のパスワードを AccountManager.addAccountExplicitly() に渡さないでください。代わりに、攻撃者による使用が制限される暗号技術的に安全なトークンを保存する必要があります。ユーザーの認証情報が重要なものを保護している場合は、同様のことを注意深く検討する必要があります。

注意事項: セキュリティ コードについては、勝手に試すことは避けてください。カスタム アカウントのコードを実装する前に、セキュリティの専門家に相談してください。

セキュリティに関する免責事項が片付いたので、本題に戻りましょう。 カスタム アカウントのコードの中身は実装済みなので、あとはつなぎ合わせるだけです。

AbstractAccountAuthenticator を拡張する

AccountManager がカスタム アカウントのコードで機能するためには、AccountManager が想定するインターフェースを実装するクラスが必要です。このクラスが認証システムクラスです。

認証システムクラスを作成する最も簡単な方法は、AbstractAccountAuthenticator を拡張してその抽象メソッドを実装する方法です。前のレッスンを終えた方は、AbstractAccountAuthenticator の抽象メソッドをご存じのはずです。前のレッスンで呼び出したメソッドの反対で、アカウント情報と認証トークンを取得します。

認証システムクラスを適切に実装するには、いくつかの別個のコードが必要です。まず、AbstractAccountAuthenticator の 7 つの抽象メソッドをオーバーライドする必要があります。次に、"android.accounts.AccountAuthenticator"インテント フィルタをアプリ マニフェストに追加します(次のセクションで説明します)。最後に、カスタム アカウント タイプの名前と、このタイプのアカウントの横に表示されるアイコンを定義する、2 つの XML リソースを指定します。

認証システムクラスと XML ファイルの実装手順の詳細は、AbstractAccountAuthenticator のドキュメントをご覧ください。SampleSyncAdapter サンプルアプリの実装例もあります。

SampleSyncAdapter のコードを読むと、いくつかのメソッドがバンドルでインテントを返していることがわかります。これは、カスタム認証アクティビティの起動に使用されるのと同じインテントです。認証システム アクティビティに特別な初期化パラメータが必要な場合は、Intent.putExtra() を使用してインテントに設定できます。

認証システム サービスを作成する

認証システムクラスを作成したので、それを動作させる場所が必要になります。 アカウント認証システムは、複数のアプリから利用でき、バックグラウンドで動作する必要があります。したがって、Service の中で実行する必要があります。これを認証システム サービスと呼ぶことにします。

認証システム サービスは非常に簡単です。onCreate() で認証システムクラスのインスタンスを作成し、onBind()getIBinder() を呼び出すだけです。SampleSyncAdapter に、認証システム サービスの良い例があります。

必ず、マニフェスト ファイルに <service> タグを追加して、AccountAuthenticator インテントのインテント フィルタを追加し、アカウント認証システムを宣言してください。

    <service ...>
       <intent-filter>
          <action android:name="android.accounts.AccountAuthenticator" />
       </intent-filter>
       <meta-data android:name="android.accounts.AccountAuthenticator"
                 android:resource="@xml/authenticator" />
    </service>
    

サービスを配布する

これで完了です。作成したアカウント タイプが、「Google」や「法人」などの有名なアカウント タイプと同じように、システムに認識されるようになりました。[アカウントと同期] 設定ページを使用してアカウントを追加できます。作成したカスタムタイプのアカウントを要求するアプリは、他のアカウント タイプと同じように、列挙および認証できるようになります。

もちろん、これはすべて、作成したアカウント サービスが実際にデバイスにインストールされていることを前提としています。1 つのアプリのみがこのサービスにアクセスする場合、このような大げさなことはせず、アプリにこのサービスをバンドルするだけです。しかし、作成したアカウント サービスを複数のアプリで使用する場合は、もっと複雑になります。作成したサービスをすべてのアプリにバンドルし、ユーザーのデバイスに複数のコピーを保存してストレージ容量を圧迫する必要はありません。

1 つの解決方法は、このサービスを 1 つの小さくて特別な APK に入れることです。アプリは、カスタム アカウント タイプを使用するときに、カスタム アカウント サービスが利用可能かどうかをデバイスで確認できます。利用できない場合は、サービスをダウンロードするようにユーザーを Google Play に誘導できます。これは、最初は難しいことに思えるかもしれませんが、カスタム アカウントを使用するすべてのアプリに認証情報を再入力する方法に比べれば、すっきりとして簡単です。