Android のアカウントマネージャ (AccountManager) の概説
最近 Android のアカウントマネージャを仕事で触ったので、調べた内容としてアカウントマネージャの概要をまとめておきます。
Web 上を調べると AccountManager
を使う処理の実装方法はいろいろ見つかるのですが、アカウントマネージャの概要を説明しているページはあんまりなくて全体像を掴みにくいと思っています。 そういう情報を探している人の役に立てば幸いです。
公式ドキュメント
アカウントマネージャに関する公式ドキュメントは以下のものぐらいしかなさそうです。 AccountManager
クラスのドキュメントを全て (各メソッドの説明も含めて) 読むと大体理解できると思います。 (下記ドキュメントを見て理解したら本ページの内容を読む必要はありません。)
- AccountManager | Android Developers
- AbstractAccountAuthenticator | Android Developers
- Remembering Users | Android Developers
AccountManager
を使って認証情報を取得する方法 (利用側) : Remembering Your User と Authenticating to OAuth2 ServicesAccountManager
経由でのアカウント追加や認証情報取得のリクエストを処理する方法 (提供側) : Creating a Custom Account Type
アカウントマネージャの概要
アカウントマネージャは、Android のシステムがユーザーのオンラインアカウントを中央管理するための機能です。 Android 端末の 「設定」 にずらずらとアカウントが並ぶと思いますが、これもアカウントマネージャの仕組みで実現されています。
各種オンラインサービスはそれぞれ異なったアカウントの扱い方や認証方式を使うため、アカウントマネージャはアカウント種別ごとに authenticator モジュールを使い分けるようになっています。
使いどころ
複数アプリで認証情報を共有するときに便利です。 (認証情報の提供側、および利用側両方とも。)
また、単一アプリでのみ認証情報を使う場合でも便利に使えると思います。 なぜなら、アカウントマネージャを使うことで認証周りの処理を分離しやすくなり、また、統一された方法で認証トークンを扱えるようになるためです。
用語
- Account Type : Authenticator を特定するための文字列。
- Auth token (認証トークン) : オンラインサービスのユーザー認証に使われるトークン。
- Auth token type : Authenticator 固有の、Auth token 種別。 1 つのアカウントが auth token を複数持つことができる。
- Feature : Authenticator 固有の、アカウントプロパティを特定するトークン。
- Client (クライアント) / Application : アカウントマネージャを使って認証情報を取得するアプリを指す。
- Authenticator : トークンの払い出しなどを行うやつ。 実体は
AbstractAccountAuthenticator
を継承したクラス。- システム上で有効な authenticator (
AbstractAccountAuthenticator
) を持っているアプリを指して Authenticator と言ったりもしてる? (明示的にアプリを表す場合は 「Authenticator アプリ」 と呼ぶのが良さそう。) - クライアントであり、かつ Authenticator であるというようなアプリも存在しうる。
- システム上で有効な authenticator (
Authenticator とクライアントの関係
アカウントマネージャを扱う処理を大別すると、authenticator とクライアントに分かれます。
- Authenticator (や、それに関連する処理) : オンラインサービスのアカウント取得や認証処理を行います。 典型的には、ユーザーに対してログイン画面を表示してユーザー名とパスワードを入力させ、それらのアカウント情報を使ってオンラインサービスから認証情報を取得して、アカウントマネージャに渡します。 普通はそのオンラインサービスの提供者がアプリの中に実装します。
- Authenticator のメソッドはアカウントマネージャから呼ばれます。
- クライアント : アカウントマネージャを通じて、オンラインサービスの認証情報 (アクセストークンなど) を取得し、それを使ってオンラインサービスにリクエストを投げる、というような処理です。
クライアントが AccountManager
のクライアント向けのメソッドを呼ぶと、(一部のメソッドは) 対応する Authenticator のメソッドを呼びます。 そして、典型的には Authenticator のメソッドは AccountManager
の Authenticator 用のメソッドを呼びます。 クライアントも Authenticator も AccountManager
のメソッドを呼ぶという点で混乱しやすいのですが、AccountManager
のメソッドをクライアント用メソッド群と Authenticator 用メソッド群に分けると、理解しやすいと思います。
自社サービスクライアントと他社サービスクライアントについて公式ドキュメント上での区別はありませんが、こういう分け方で考えると理解しやすいと思うので、本ページではこのように表記します。 ちなみに厳密な区別としては、「扱うアカウント種別の authenticator アプリと同じシグネチャを持つアプリ」 が自社サービスクライアント、「異なるシグネチャを持つアプリ」 が他社サービスクライアントです。
AccountManager
のメソッド一覧
アカウントマネージャについて理解するには AccountManager
クラスに生えている全てのメソッドを把握すればいいのですが、ドキュメントそのままだと理解しづらいので、整理して一覧できるようにしておきます。 これらのメソッド一覧に目を通すと、アカウントマネージャについての理解が深まるはずです。
API level 25 のドキュメントを参照しています。
クライアント向け
他社サービスのクライアントが使えるメソッド
Authenticator 一覧を取得したり、アカウント一覧を取得したり (パーミッションがあれば他社サービスのアカウントも全て)、指定のアカウントの認証トークンを取得したり、指定の認証トークンが無効になっていることをアカウントマネージャに伝えたり、ユーザーが指定のアカウントのパスワードを知っていることを確認するよう依頼したり、といったことができます。
getAuthenticatorTypes()
- システムに登録されている Authenticator 一覧を返す。
- パーミッション不要。
addOnAccountsUpdatedListener
- アカウントマネージャが管理するアカウントの変化 (追加や削除など) を検知するリスナ (
OnAccountsUpdateListener
) を追加する。 getAccounts
メソッドで取得可能なアカウントの変化のみ検知できる。 (典型的には、任意のアカウントの変化を検知するにはGET_ACCOUNTS
パーミッションが必要。)
- アカウントマネージャが管理するアカウントの変化 (追加や削除など) を検知するリスナ (
removeOnAccountsUpdatedListener(OnAccountsUpdateListener)
- リスナの削除。
addAccount
- アカウント取得系
confirmCredentials
updateCredentials(Account, String, Bundle, Activity, AccountManagerCallback<Bundle>, Handler)
getPreviousName
- 指定のアカウントの前の名前を返す。
LOGIN_ACCOUNTS_CHANGED_ACTION
ブロードキャストを受け取ったときに、アカウント名が変更されているかどうか検知できるようにするためのメソッドらしい。
- Auth token 取得系 : AccountManager がキャッシュしていたらそれを返し、なければ対応する Authenticator が認証トークンを取得する。
getAuthToken(Account, String, Bundle, boolean, AccountManagerCallback<Bundle>, Handler)
- バックグラウンドの処理向け。
- 指定のアカウントの指定のトークン種別の認証トークンを取得する。 アカウントマネージャがキャッシュしている場合はそれが返される。 キャッシュされていない場合は authenticator がリクエストを処理する。
- Authenticator は、パスワードが使えるのであればそれでサーバーに問い合わせを行う。 それが無理ならユーザーにログイン画面を表示して、ユーザー入力によって認証トークンを取得する。
notifyAuthFailure
に真を渡したならば、そのインテントを開始するステータスバーの通知も表示される。- その場合 (ログインする必要がある場合? それともステータスバーの通知が表示される場合?) には、ユーザーが対応するまで何時間も、何日も、あるいは永遠に待つことになる可能性がある。
notifyAuthFailure
に偽を渡した場合は、アプリケーションがIntent
を開始する責任がある。- API level 22 以下では
USE_CREDENTIALS
パーミッションが必要。
getAuthToken(Account, String, boolean, AccountManagerCallback<Bundle>, Handler)
- API level 14 で Deprecated になってるので
Bundle
パラメータ有り版を呼ぶこと。
- API level 14 で Deprecated になってるので
getAuthToken(Account, String, Bundle, Activity, AccountManagerCallback<Bundle>, Handler)
blockingGetAuthToken
getAuthTokenByFeatures(String, String, String[], Activity, Bundle, Bundle, AccountManagerCallback<Bundle>, Handler)
invalidateAuthToken
hasFeatures
自社アプリ (同じシグネチャを持つアプリ) のみ
removeAccount(Account, Activity, AccountManagerCallback<Bundle>, Handler)
removeAccount(Account, AccountManagerCallback<Boolean>, Handler)
- 上に同じ。 Deprecated。
renameAccount(Account, String, AccountManagerCallback<Account>, Handler)
clearPassword
- アカウントマネージャが保持しているパスワードを削除する。 「ログアウト」 ボタンの処理などで使われることを想定しているらしい。
setPassword
メソッドでも同じことができるけどこっちの方が必要な権限は少ないっぽい。- アカウントの Authenticator と同じシグネチャが必要。
editProperties
Authenticator (または、それに関連する処理) 向け
addAccountExplicitly(Account, String, Bundle)
- アカウントをアカウントマネージャに追加する。
- Authenticator に関連するサインアップ処理向け。
addAccount
メソッドなどのシステムがアカウント追加を検知できるメソッド経由で呼ばれたわけじゃない場合は、自前でnotifyAccountAuthenticated
メソッドを呼ぶべき。
removeAccountExplicitly(Account)
notifyAccountAuthenticated(Account)
- アカウントが認証されたことをシステムに伝える。
- このイベント情報が他のアプリで使われたりするっぽい? (未調査。)
- 呼び出し側はアカウントの Authenticator と同じシグネチャを持つ必要がある。
getPassword
setPassword(Account, String)
getUserData
setUserData(Account, String, String)
peekAuthToken(Account, String)
setAuthToken(Account, String, String)
その他
get(Context)
: インスタンス取得。getAccountsByTypeForPackage
: システム用。newChooseAccountIntent(Account, List<Account>, String[], String, String, String[], Bundle)
- アカウント選択画面を表示するための
Intent
を生成する。
- アカウント選択画面を表示するための
newChooseAccountIntent(Account, ArrayList<Account>, String[], boolean, String, String, String[], Bundle)
- 上の Deprecated 版。
関連ページ
- 『Android アプリのセキュア設計・セキュアコーディングガイド』2016年9月1日版 (JSSEC) : セキュリティ周りのことはこれが一番良いはず。 説明もわかりやすい。
- AccountManagerを利用する : 利用側についてわかりやすくまとまっている。
- AccountManagerでアカウントを管理する : 提供側の実装方法がわかりやすくまとまっている。
- Android におけるアカウント管理 : 提供側の実装方法がわかりやすくまとまってる。
- authenticator.xml の accountType の文字列を strings.xml に入れてはいけない : 厳しい。
- Differences of AccountManager from API 22 to 24 : Kyobashi.dex #4 における shogo さんの発表資料。 最近の Android のバージョンごとの差異の説明。 複数アプリに同じ account type の authenticator を持たせるとどうなるのか、といった話も出てきて非常に参考になる。