AccountManagerを利用する
AccountManagerとは
AccountManager
とは、Androidにおいて様々なWebサービスのアカウントを管理するための仕組みのことです。
アプリはAccountManager
を利用することで以下のような様々なことができるようになります。
- アカウント情報の取得
- アカウントの編集
- アカウントのトークン取得
それぞれの操作は<uses-permission>
による制限がかけられています。
呼び出す機能に応じてに応じて必要な<uses-permission>
が変わってくるため、必要な機能を十分に検討し、適切な<uses-permission>
を設定する必要があります。
また、どの機能を利用する場合でもそのサービスに対応したアカウント管理アプリがインストールされていなければAccountManager
を経由してアカウント情報を管理することはできません。
アカウント情報の取得
AccountManager
からアカウント情報を取得する方法はいくつかあります。
ほとんどの方法でGET_ACCOUNTS
パーミッションが必要です。
<uses-permission android:name="android.permission.GET_ACCOUNTS"/>
アカウント情報は基本的にAccount
クラスで管理されます。
このクラスはname
とtype
の2つの値を持っており、name
はアカウント名、type
はそのアカウントが属するサービスの種類となります。
例として、Googleのアカウントの場合、name
はuser@gmail.com、type
はcom.google
が格納されています。
すべてのアカウント情報を取得
すべてのアカウント情報を取得するにはAccountManager#getAccounts()
を使用します。
通常のアプリでは利用するサービス種別が決まっているため、この方法を使うことはあまりないでしょう。
取得できるアカウント情報はAccount
クラスの配列となっています。
AccountManager manager = AccountManager.get(context); Account[] accountArray = manager.getAccounts();
サービス種別を指定してアカウント情報を取得
サービス種別を指定してアカウント情報を指定するにはAccountManager#getAccountsByType()
を使用します。
この時指定するtype
はAccount#type
と同じもので、サービスごとに決められた文字列です。
例として、Googleのアカウントであれば以下のように取得します。
AccountManager manager = AccountManager.get(context);
Account[] accountArray = manager.getAccountsByType("com.google");
特定の機能を持ったアカウント情報を取得
あるサービス種別のアカウントのうち、さらに特定の機能を持ったアカウントのみを取得したい場合、AccountManager#getAccountsByTypeAndFeatures()
を使用します。
このメソッドは、「Gmailを利用することができるGoogleユーザ」といったような指定に使います。
https://developers.google.com/gmail/android/
また、このメソッドのみAccount
クラスの配列ではなくAccountManagerFuture
を返しますが、このAccountManagerFuture
はメインスレッドで扱ってはいけないため、コールバックを設定できるようになっています。
// Get the account list, and pick the first one final String ACCOUNT_TYPE_GOOGLE = "com.google"; final String[] FEATURES_MAIL = { "service_mail" }; AccountManager.get(this).getAccountsByTypeAndFeatures(ACCOUNT_TYPE_GOOGLE, FEATURES_MAIL, new AccountManagerCallback() { @Override public void run(AccountManagerFuture future) { Account[] accounts = null; try { accounts = future.getResult(); if (accounts != null && accounts.length > 0) { String selectedAccount = accounts[0].name; queryLabels(selectedAccount); } ru } catch (OperationCanceledException oce) { // TODO: handle exception } catch (IOException ioe) { // TODO: handle exception } catch (AuthenticatorException ae) { // TODO: handle exception } } }, null /* handler */);
アカウント選択ダイアログの表示
API level 14以降では登録済みアカウントから選択、または新しいアカウントを追加させるダイアログを表示させることができます。
このメソッドの実行には権限が必要ありませんが、アカウントの選択ダイアログはOS標準のUIとなり、選択結果もonActivityResult
で受ける形になります。
@Override public void onClick(View v) { Intent intent = AccountManager.get(this).newChooseAccountIntent(null, null, new String[] { "com.google" }, false, null, null, null, null); startActivityForResult(intent, REQUEST_CODE); } @Override protected void onActivityResult(final int requestCode, final int resultCode, final Intent data) { super.onActivityResult(requestCode, resultCode, data); { if (requestCode == REQUEST_CODE && resultCode == Activity.RESULT_OK) Toast.makeText(this, data.getStringExtra(AccountManager.KEY_ACCOUNT_NAME), Toast.LENGTH_SHORT).show(); } }
アカウントの編集
AccountManager
ではアカウントの追加、削除などを行うことができます。
そのいずれの方法でもMANAGE_ACCOUNTS
パーミッションが必要です。
以下では、アカウント編集に関する代表的なメソッドを紹介します。
<uses-permission android:name="android.permission.MANAGE_ACCOUNTS"/>
アカウントの追加
サービス種別を指定してアカウントの追加を行うには、AccountManager#addAccount()
を利用します。
通常、このメソッドを実行するとサービス種別に対応したアカウントの登録画面が表示され、そこでアカウント情報を入力してログインし、アカウントを追加する形になります。
従って、このメソッドでもコールバックを利用して結果を受け取る方法を使います。
ログインに成功した場合、KEY_ACCOUNT_NAME
とKEY_ACCOUNT_TYPE
を受け取ることができます。
ここで第二引数に指定した"mail"はauthTokenType
という引数で、後にトークンを取得する際に重要になります。
AccountManager manager = AccountManager.get(this); manager.addAccount("com.google", "mail", null, null, activity, new AccountManagerCallback<Bundle>() { @Override public void run(AccountManagerFuture<Bundle> future) { try { Bundle bundle = future.getResult(); String accountName = bundle.getString(AccountManager.KEY_ACCOUNT_NAME); } catch (OperationCanceledException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } catch (AuthenticatorException e) { e.printStackTrace(); } } }, null);
アカウントの削除
アカウント情報を指定して削除を行うには、AccountManager#removeAccount()
を利用します。
このメソッドでは削除の成功可否booleanをコールバックで受け取ります。
一般的にアカウント情報を指定するためにはgetAccountsByType
を利用するため、GET_ACCOUNTS
パーミッションが必要ですが、name
とtype
が最初からわかっている場合、Account
を直接指定することができます。
実際に下記の例ではAccount
を直接生成していますが、このような場合はMANAGE_ACCOUNTS
パーミッションのみで動作します。
AccountManager manager = AccountManager.get(this); manager.removeAccount(new Account("user@gmail.com","com.google"), new AccountManagerCallback<Boolean>() { @Override public void run(AccountManagerFuture<Boolean> future) { try { boolean result = future.getResult(); } catch (OperationCanceledException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } catch (AuthenticatorException e) { e.printStackTrace(); } } }, null);
アカウントの無効化
AccountManager
ではアカウントのユーザIDとパスワードを保存している場合があり、トークン期限が切れた場合でもこれらの情報でトークンの再取得を行っています。
何らかの理由でこの再取得を無効化したい場合、AccountManager#clearPassword()
を利用して保存されているパスワードをリセットすることができます。
このメソッドもアカウントを直接指定する場合にはMANAGE_ACCOUNTS
パーミッションのみで動作します。
AccountManager manager = AccountManager.get(this); manager.clearPassword(new Account("user@gmail.com","com.google"));
トークンの取得
AccountManager
では、指定したアカウントからサービスに接続するためのトークンを取得することができます。
この仕組により、AccountManager
で管理されているアカウントでWebサービスを利用する場合、同一端末でのログインは初回のみで良いことになります。
トークンの取得にはUSE_CREDENTIALS
パーミッションが必要です。
また、アカウントを直接指定した場合でもGET_ACCOUNTS
が必要な場合があるようなのでこちらもあったほうが良いでしょう。
<uses-permission android:name="android.permission.GET_ACCOUNTS"/> <uses-permission android:name="android.permission.USE_CREDENTIALS"/>
トークンを取得するメソッドはいくつかありますが、下記では最も単純なgetAuthToken()
を例にあげます。
このメソッドを最初に実行したとき、アプリがアカウントにアクセスすることを承認するかどうかをユーザに確認する画面が表示されます。
この承認画面により、AccountManager
ではユーザが許可しない限りはトークンを取得できないという仕組みになっているのです。
また、第二引数のauthTokenType
は取得するトークンの種別を定義するもので、必ず指定する必要があります。
通常、このauthTokenType
はAccountManager#addAccount()
で指定するauthTokenType
と同じものになります。
AccountManager manager = AccountManager.get(this); manager.getAuthToken(new Account("user@gmail.com", "com.google"), "mail", null, this, new AccountManagerCallback<Bundle>() { @Override public void run(AccountManagerFuture<Bundle> future) { Bundle bundle = null; try { bundle = future.getResult(); String accountName = bundle.getString(AccountManager.KEY_ACCOUNT_NAME); String accountType = bundle.getString(AccountManager.KEY_ACCOUNT_TYPE); String authToken = bundle.getString(AccountManager.KEY_AUTHTOKEN); Toast.makeText(MyActivity.this,authToken,Toast.LENGTH_SHORT).show(); } catch (OperationCanceledException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } catch (AuthenticatorException e) { e.printStackTrace(); } } }, null);
注意点
AccountManager
を安全に使う上で、気をつけなければいけないことがあります。
以下はセキュリティの確保のために最低限注意しなければならない事柄です。
取得したトークン情報を永続化しない
AccountManager#getAuthToken()
で取得したトークンを保存してはいけません。
必要にった時にAccountManager#getAuthToken()
で取得しなおして下さい。
AccountManager
では有効期限内のトークンをキャッシュしているため、通常はトークン再取得に時間はかかりません。
取得したトークン情報を他のアプリに共有しない
AccountManager#getAuthToken()
で取得したトークンを他のアプリと共有してはいけません。
承認画面でユーザが確認できるのは AccountManager#getAuthToken()
を実行したアプリのみです。
他のアプリでトークンを使わせることはユーザを裏切ることになります。
取得したトークンが使えない場合、トークンを無効化する
取得したトークンでAPIアクセスに失敗する場合、トークンが無効になっている場合があります。
このような場合でも有効期限が切れるまではAccountManager
でキャッシュされてしまうため、アプリで検知した場合はAccountManager
に無効なトークンであることを通知する必要があります。
AccountManager#invalidateAuthToken()
を実行することで、指定したトークンのキャッシュを無効にできます。
AccountManager#invalidateAuthToken()
実行後にAccountManager#getAuthToken()
を実行した場合、AccountManager
は新しいトークンを取得して返します。
AccountManager manager = AccountManager.get(this); manager.invalidateAuthToken("com.google",TOKEN);