1. Qiita
  2. 投稿
  3. Android

AccountManager で詰まったところのメモ

  • 4
    いいね
  • 0
    コメント

AccountManager実装したときのメモ

AbstractAccountAuthenticator#addAccountが呼ばれるタイミング



アカウントを追加 をクリックした時

AbstractAccountAuthenticator#getAuthTokenが呼ばれるタイミング

Authenticatorを持つ自アプリから AccountManager#getAuthToken を呼び出しても AbstractAccountAuthenticator#getAuthToken は呼ばれない

他アプリから AccountManager#getAuthToken が呼ばれた際に呼ばれる

他アプリ(違うkeystoreでBuild)からAccountManagerへのアクセス

Android5.xでは AccountManager#getAuthToken アカウントへのアクセスリクエスト画面が強制的に表示される
-> 許可をクリック後AuthTokenを取得できる
Android7.xでは AccountManager#getAuthToken 何も表示されず何も取得できない

他アプリ(同じkeystoreでBuild)からAccountManagerへのアクセス

Android5.xでは AccountManager#getAuthToken 何もなくAuthTokenが取得できる
Android7.xでは AccountManager#getAuthToken 何もなくAuthTokenが取得できる

同じauthenticatorを2つのアプリに入れた際の挙動

先にインストールした authenticator が優先される

  • アプリAインストール -> アプリBインストール -> アプリAアンインストール
    • アプリAのアカウントが削除され、アプリBからアカウントへのアクセスができなくなる
  • アプリAインストール -> アプリBインストール -> アプリAアンインストール -> アプリAインストール
    • アプリAのアカウントが削除され、アプリBからアカウントへのアクセスができなくなる
    • アプリBで作成されたアカウントにアプリAはアクセスできる

Permisssion関連

様々なサイトで android.permission.GET_ACCOUNTSAccountManager#getAccountsByType を呼ぶ際などに必要と書かれている。
Permission Requestが必要と思うが android.permission.GET_ACCOUNTS が必要なのはAPI22まででAPI23以降は必要ではない。
そのため以下のように

<uses-permission android:name="android.permission.GET_ACCOUNTS" android:maxSdkVersion="22" />

と書くのが正しい。
https://developer.android.com/reference/android/Manifest.permission.html#GET_ACCOUNTS

if an app shares the signature of the authenticator that manages an account, it does not need "GET_ACCOUNTS" permission to read information about that account. On Android 5.1 and lower, all apps need "GET_ACCOUNTS" permission to read information about any account.

ココらへんのPermission関連はAccountManagerを使用する際に必要とするPermissionにも同じことが言えると思うが調べながら行ったほうが良い。

セキュリティ周り

先にインストールアされたアプリの authenticator が優先されるため、疑似アプリをインストール後、本物をインストールすると、疑似アプリの authenticator が有効になってしまう。
そのため、証明書のチェックを行うと良い。

    private fun isCorrectCertificate(): Boolean {
        val packageNames = accountManager.authenticatorTypes.filter { it.type == accountType }.map { it.packageName }
        if (packageNames.isEmpty()) {
            return true
        }
        val packageInfoList = packageNames.map { packageManager.getPackageInfo(it, PackageManager.GET_SIGNATURES) }
        val md = MessageDigest.getInstance("SHA1")
        return packageInfoList.all {
            md.update(it.signatures.first().toByteArray())
            myHashKey == Base64.encodeToString(md.digest(), Base64.DEFAULT)
        }
    }

こんなんがいるかも。

authenticator.xmlまわりについて

accountType はR.stringを参照するとダメ
-> http://qiita.com/KeithYokoma/items/c1975f616123475e9cbc

label は逆にR.stringを参照しないと表示されなくなる(Android7で確認)

<?xml version="1.0" encoding="utf-8"?>
<account-authenticator xmlns:android="http://schemas.android.com/apk/res/android"
    android:accountType="jp.hoge.hoge.develop"
    android:icon="@mipmap/ic_launcher"
    android:label="hoge"
    android:smallIcon="@mipmap/ic_launcher" />

例えば、 labelhoge を指定した場合

こんな感じになり、この状態でアカウント追加が正常終了すると

アカウントは追加していて、AccountManagerからアクセスできるがアカウント一覧には何も表示されない状況になる。

<?xml version="1.0" encoding="utf-8"?>
<account-authenticator xmlns:android="http://schemas.android.com/apk/res/android"
    android:accountType="jp.hoge.hoge.develop"
    android:icon="@mipmap/ic_launcher"
    android:label="@string/hoge"
    android:smallIcon="@mipmap/ic_launcher" />

きちんとR.stringを参照すると

表示される。
アカウントを隠蔽したい場合に便利かも。