スタブ認証システムを作成する

同期アダプター フレームワークは、アカウントに関連付けられたデバイス ストレージと、ログイン アクセスが必要なサーバー ストレージの間で、同期アダプターによってデータが転送されることを前提にしています。このため、同期アダプター フレームワークでは、認証システムと呼ばれるコンポーネントを同期アダプターの一部として用意する必要があります。このコンポーネントは、Android アカウントと認証フレームワークに接続され、ログイン情報などのユーザー認証情報を処理するための標準インターフェースを提供します。

アプリでアカウントを使用していない場合でも、認証システム コンポーネントを用意する必要があります。アカウントまたはサーバー ログイン情報を使用しない場合、認証システムで処理される情報は無視されるため、スタブメソッドの実装を含む認証システム コンポーネントを使用できます。また、同期アダプター フレームワークが認証システムのメソッドを呼び出すことを可能にする、バインドされた Service も用意する必要があります。

このレッスンでは、同期アダプター フレームワークの要件を満たすスタブ認証システムのすべての要素を定義する方法について説明します。ユーザー アカウントを処理する本物の認証システムを用意する必要がある場合は、AbstractAccountAuthenticator リファレンス ドキュメントをご覧ください。

スタブ認証システム コンポーネントを追加する

スタブ認証システム コンポーネントをアプリに追加するには、AbstractAccountAuthenticator を拡張するクラスを作成した後、null を返すかまたは例外をスローして、必要なメソッドをスタブ化します。

次のスニペットは、スタブ認証システムクラスの例を示しています。

Kotlin

    /*
     * Implement AbstractAccountAuthenticator and stub out all
     * of its methods
     */
    class Authenticator(context: Context) // Simple constructor
        : AbstractAccountAuthenticator(context) {

        // Editing properties is not supported
        override fun editProperties(r: AccountAuthenticatorResponse, s: String): Bundle {
            throw UnsupportedOperationException()
        }

        // Don't add additional accounts
        @Throws(NetworkErrorException::class)
        override fun addAccount(
                r: AccountAuthenticatorResponse,
                s: String,
                s2: String,
                strings: Array<String>,
                bundle: Bundle
        ): Bundle?  = null

        // Ignore attempts to confirm credentials
        @Throws(NetworkErrorException::class)
        override fun confirmCredentials(
                r: AccountAuthenticatorResponse,
                account: Account,
                bundle: Bundle
        ): Bundle?  = null

        // Getting an authentication token is not supported
        @Throws(NetworkErrorException::class)
        override fun getAuthToken(
                r: AccountAuthenticatorResponse,
                account: Account,
                s: String,
                bundle: Bundle
        ): Bundle {
            throw UnsupportedOperationException()
        }

        // Getting a label for the auth token is not supported
        override fun getAuthTokenLabel(s: String): String {
            throw UnsupportedOperationException()
        }

        // Updating user credentials is not supported
        @Throws(NetworkErrorException::class)
        override fun updateCredentials(
                r: AccountAuthenticatorResponse,
                account: Account,
                s: String,
                bundle: Bundle
        ): Bundle {
            throw UnsupportedOperationException()
        }

        // Checking features for the account is not supported
        @Throws(NetworkErrorException::class)
        override fun hasFeatures(
                r: AccountAuthenticatorResponse,
                account: Account,
                strings: Array<String>
        ): Bundle {
            throw UnsupportedOperationException()
        }
    }
    

Java

    /*
     * Implement AbstractAccountAuthenticator and stub out all
     * of its methods
     */
    public class Authenticator extends AbstractAccountAuthenticator {
        // Simple constructor
        public Authenticator(Context context) {
            super(context);
        }
        // Editing properties is not supported
        @Override
        public Bundle editProperties(
                AccountAuthenticatorResponse r, String s) {
            throw new UnsupportedOperationException();
        }
        // Don't add additional accounts
        @Override
        public Bundle addAccount(
                AccountAuthenticatorResponse r,
                String s,
                String s2,
                String[] strings,
                Bundle bundle) throws NetworkErrorException {
            return null;
        }
        // Ignore attempts to confirm credentials
        @Override
        public Bundle confirmCredentials(
                AccountAuthenticatorResponse r,
                Account account,
                Bundle bundle) throws NetworkErrorException {
            return null;
        }
        // Getting an authentication token is not supported
        @Override
        public Bundle getAuthToken(
                AccountAuthenticatorResponse r,
                Account account,
                String s,
                Bundle bundle) throws NetworkErrorException {
            throw new UnsupportedOperationException();
        }
        // Getting a label for the auth token is not supported
        @Override
        public String getAuthTokenLabel(String s) {
            throw new UnsupportedOperationException();
        }
        // Updating user credentials is not supported
        @Override
        public Bundle updateCredentials(
                AccountAuthenticatorResponse r,
                Account account,
                String s, Bundle bundle) throws NetworkErrorException {
            throw new UnsupportedOperationException();
        }
        // Checking features for the account is not supported
        @Override
        public Bundle hasFeatures(
            AccountAuthenticatorResponse r,
            Account account, String[] strings) throws NetworkErrorException {
            throw new UnsupportedOperationException();
        }
    }
    

認証システムをフレームワークにバインドする

同期アダプター フレームワークが認証システムにアクセスできるようにするには、バインドされたサービスを作成する必要があります。このサービスは、フレームワークが認証システムを呼び出して、認証システムとフレームワークの間でデータをやり取りできるようにする Android バインダー オブジェクトを提供します。

この Service は、フレームワークで認証システムへのアクセスが必要になったときに初めて開始されるため、このサービスを使用して認証システムをインスタンス化することもできます。これを行うには、サービスの Service.onCreate() メソッドで認証システム コンストラクタを呼び出します。

次のスニペットは、バインドされた Service を定義する方法を示しています。

Kotlin

    /**
    * A bound Service that instantiates the authenticator
    * when started.
    */
    class AuthenticatorService : Service() {

        // Instance field that stores the authenticator object
        private lateinit var mAuthenticator: Authenticator

        override fun onCreate() {
            // Create a new authenticator object
            mAuthenticator = Authenticator(this)
        }

        /*
         * When the system binds to this Service to make the RPC call
         * return the authenticator's IBinder.
         */
        override fun onBind(intent: Intent?): IBinder = mAuthenticator.iBinder
    }
    

Java

    /**
     * A bound Service that instantiates the authenticator
     * when started.
     */
    public class AuthenticatorService extends Service {
        ...
        // Instance field that stores the authenticator object
        private Authenticator mAuthenticator;
        @Override
        public void onCreate() {
            // Create a new authenticator object
            mAuthenticator = new Authenticator(this);
        }
        /*
         * When the system binds to this Service to make the RPC call
         * return the authenticator's IBinder.
         */
        @Override
        public IBinder onBind(Intent intent) {
            return mAuthenticator.getIBinder();
        }
    }
    

認証システム メタデータ ファイルを追加する

認証システム コンポーネントを同期アダプター フレームワークとアカウント フレームワークに接続するには、コンポーネントを記述したメタデータをそれらのフレームワークに提供する必要があります。このメタデータでは、同期アダプター用に作成したアカウント タイプと、アカウント タイプをユーザーに表示したい場合にシステムによって示されるユーザー インターフェース要素が宣言されます。このメタデータは、アプリ プロジェクトの /res/xml/ ディレクトリに格納されている XML ファイルで宣言します。 ファイルには任意の名前を指定できますが、一般的な名前は authenticator.xml です。

この XML ファイルには、以下の属性を持つ単一の <account-authenticator> 要素が含まれます。

android:accountType
同期アダプター フレームワークでは、同期アダプターごとに、ドメイン名の形式を持つアカウント タイプが必要です。フレームワークでは、アカウント タイプは同期アダプターの内部 ID の一部として使用されます。ログインが必要なサーバーの場合、アカウント タイプとユーザー アカウントはログイン認証情報の一部としてサーバーに送信されます。

ログインが不要なサーバーについても、アカウント タイプを指定する必要があります。値については、制御するドメイン名を使用します。この値はフレームワークにより同期アダプターを管理するために使用されますが、サーバーには送信されません。

android:icon
アイコンを含むドローアブル リソースのポインタ。res/xml/syncadapter.xml で属性 android:userVisible="true" を指定して同期アダプターが表示されるようにするには、このアイコン リソースを指定する必要があります。この値は、システムの設定アプリの [アカウント] セクションに表示されます。
android:smallIcon
小さいバージョンのアイコンを含むドローアブル リソースのポインタ。このリソースは、画面サイズに応じて、システムの設定アプリの [アカウント] セクションで android:icon の代わりに使用されることがあります。
android:label
ユーザーに対するアカウント タイプを特定するローカライズ可能な文字列。res/xml/syncadapter.xml で属性 android:userVisible="true" を指定して同期アダプターが表示されるようにするには、この文字列を指定する必要があります。システムの設定アプリの [アカウント] セクションで、認証システムに定義したアイコンの横に表示されます。

次のスニペットは、前に作成した認証システムの XML ファイルを示しています。

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

マニフェストで認証システムを宣言する

前のステップでは、認証システムを同期アダプター フレームワークにリンクする、バインドされた Service を作成しました。システムに対してこのサービスを特定するには、次の <service> 要素を <application> の子要素として追加し、アプリ マニフェストで宣言します。

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

<intent-filter> 要素は、認証システムを実行するために送信されたインテント アクション android.accounts.AccountAuthenticator によってトリガーされるフィルタを設定します。フィルタがトリガーされると、システムによって AuthenticatorService が開始されます。これは、認証システムをラップするために指定した、バインドされた Service です。

<meta-data> 要素は、認証システムのメタデータを宣言します。android:name 属性は、メタデータを認証フレームワークにリンクします。android:resource 要素は、前に作成した認証システム メタデータ ファイルの名前を指定します。

認証システムに加えて、同期アダプターにはコンテンツ プロバイダが必要です。アプリでコンテンツ プロバイダをまだ使用していない場合は、次のレッスンに進んで、スタブ コンテンツ プロバイダの作成方法を学習してください。すでに使用している場合は、同期アダプターを作成するレッスンに進んでください。