Android用のLogin with Amazon SDK APIを使用する(v2.0.2以下)


Android用のLogin with Amazon SDK APIを使用する(v2.0.2以下)

以下の手順は、Android用のLogin with Amazon SDK(バージョン2.0.2以下)のみに適用されます。

古いSDKは既にダウンロードできなくなっていますが、使用を継続している開発者向けに手順を保存しています。

Android Developer Toolsのインストール

Android用のLogin with Amazon SDKを使用して、Android、Fire TV、FireタブレットのアプリにLogin with Amazonを追加できます。Android用のLogin with Amazon SDKと併せてAndroid Studioを使用することをお勧めしますが、EclipseとADTプラグインも使用できます。Android StudioのインストールとAndroid SDKのセットアップの手順については、developer.android.comのAndroid SDKのダウンロードページを参照してください。

Android SDKをインストールしたら、お使いのAndroidにSDK Managerアプリがあることを確認します。Login with Amazon向けの開発には、SDK Managerを使用してAndroid 2.2以上(APIバージョン8)用のSDKプラットフォームをインストールする必要があります。SDK Managerの使用方法の詳細については、developer.android.comのSDKパッケージの追加に関する説明を参照してください。

SDKをインストールしたら、アプリを実行するためのAndroid仮想デバイス(AVD)を設定します。仮想デバイスの設定手順については、developer.android.comの仮想端末の作成と管理を参照してください。

ログインボタンの処理とプロファイルデータの取得

このセクションでは、authorize APIとgetProfile APIを呼び出してユーザーをログインし、そのユーザーのプロファイルデータを取得する方法について説明します。これには、[Login with Amazon] ボタン用にonClickリスナーをアプリのonCreateメソッドに作成することが含まれます。

ソースファイルにLogin with Amazon APIをインポートする

  1. ソースファイルにLogin with Amazon APIをインポートします。

    Login with Amazon APIをインポートするには、ソースファイルに次のimportステートメントを追加します。

    import com.amazon.identity.auth.device.AuthError;
    import com.amazon.identity.auth.device.authorization.api.AmazonAuthorizationManager;
    import com.amazon.identity.auth.device.authorization.api.AuthorizationListener;
    import com.amazon.identity.auth.device.authorization.api.AuthzConstants;
    
  2. AmazonAuthorizationManagerを初期化します。AmazonAuthorizationManager変数を宣言してそのクラスの新しいインスタンスを作成する必要があります。新しいインスタンスの作成に必要なのは、既存のアプリのコンテキストと空のバンドルのみです。AmazonAuthorizationManagerを初期化する場所として最も適しているのは、ActivityonCreateメソッド内です。次に例を示します。

    private AmazonAuthorizationManager mAuthManager;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mAuthManager = new AmazonAuthorizationManager(this, Bundle.EMPTY);
    }
    
  3. AuthorizeListenerを作成します。AuthorizeListenerAuthorizationListenerインターフェイスを実装し、authorize呼び出しの結果を処理します。これには、onSuccessonErroronCancelの3つのメソッドが含まれます。各メソッドはBundleオブジェクトまたはAuthErrorオブジェクトを受け取ります。

    private class AuthorizeListener implements AuthorizationListener{
    
        /* 認可が正常に完了。 */
        @Override
        public void onSuccess(Bundle response) {
        }
        /* アプリの認可中にエラーが発生。 */
        @Override
        public void onError(AuthError ae) {
        }
        /* 完了前に認可がキャンセル。 */
        @Override
        public void onCancel(Bundle cause) {
        }
    }
    
  4. AmazonAuthorizationManager.authorizeを呼び出します。

    [Login with Amazon] ボタンのonClickハンドラーで、authorizeを呼び出してユーザーにログインとアプリの認可を求める画面を表示します。

    このメソッドは、次のいずれかの方法でユーザーを認可するために使用されます。

    1. システムブラウザに切り替えて、ユーザーがログインしてリクエストされた情報に同意できるようにする。

    2. 安全なコンテキストでWebViewに切り替えて、ユーザーがログインしてリクエストされた情報に同意できるようにする。

    2番目の方法の安全なコンテキストは、現状ではAndroidデバイス上のAmazonショッピングアプリで使用できます。Fire OSが実行されているAmazon製のデバイス(Kindle Fire、Fire Phone、Fire TVなど)では、デバイスにAmazonショッピングアプリがインストールされていなくても常にこの方法が適用されます。このため、ユーザーがAmazonショッピングアプリにサインインしている場合は、APIによってサインインのページはスキップされ、ユーザーはシングルサインオンを実行できます。

    アプリの認可時には、スコープと呼ばれるデータセット(1つ以上)に対して認可されます。最初のパラメーターは、Login with Amazonに対してリクエストしているユーザーデータを含むスコープの配列です。ユーザーが初めてアプリにログインするときに、開発者がリクエストして承認を求めているデータの一覧と一緒に提示されます。Login with Amazonで現在サポートしているスコープは次の3つです。profileには、ユーザー名、Eメールアドレス、AmazonアカウントIDが含まれます。profile:user_idには、AmazonアカウントIDのみが含まれます。postal_codeには、ユーザーの郵便番号が含まれます。

    authorizeを呼び出す最も適切な方法は非同期呼び出しです。この場合、UIスレッドをブロックしたり、独自のワーカースレッドを作成したりする必要がありません。authorizeを非同期的に呼び出すには、AuthorizationListenerインターフェイスをサポートするオブジェクトを最後のパラメーターとして渡します。

    private AmazonAuthorizationManager mAuthManager;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mAuthManager = new AmazonAuthorizationManager(this, Bundle.EMPTY);
        // login_with_amazon IDのボタンを検索し
        // クリックハンドラーをセットアップ
        mLoginButton = (Button) findViewById(R.id.login_with_amazon);
        mLoginButton.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                mAuthManager.authorize(
                    new String []{"profile","postal_code"},
                    Bundle.EMPTY, new AuthorizeListener());
            }
        });
    }
    
  5. ProfileListenerを作成します。ProfileListenerAPIListenerインターフェイスを実装するクラスの名前で、getProfile呼び出しの結果を処理します。APIListenerにはonSuccessonErrorの2つのメソッドが含まれます(getProfileの呼び出しをキャンセルする手段がないため、onCancelはサポートされていません)。onSuccessはプロファイルデータを含むBundleオブジェクトを受け取ります。onErrorはエラーの情報を含むAuthErrorオブジェクトを受け取ります。

    private class ProfileListener implements APIListener{
    
        /* getProfileが正常に完了。 */
        @Override
        public void onSuccess(Bundle response) {
        }
        /* プロファイルの取得中にエラーが発生。 */
        @Override
        public void onError(AuthError ae) {
        }
    }
    
  6. onSuccessAuthorizeListenerに対して実装します。onSuccessで、AmazonAuthorizationManager.getProfileを呼び出してユーザープロファイルを受け取ります。getProfileは、authorizeと同じように、非同期リスナーインターフェイスを使用します。getProfileでは、そのインターフェイスがAuthorizationListenerではなくAPIListenerになります。

    /* 認可が正常に完了。 */
    @Override
    public void onSuccess(Bundle response) {
        mAuthManager.getProfile(new ProfileListener());
    }
    
  7. onSuccessProfileListenerに対して実装します。onSuccessには主に2つのタスクがあります。レスポンスBundleからプロファイルデータを取得することと、UIにデータを渡すことです。updateProfileDataはプロファイルの詳細を表示するためにアプリが実装できる仮想関数です。setLoggedInStateはもう1つの仮想関数で、仮想関数で、ユーザーがログイン中であることを示し、ログアウトの手段を提供します。Bundleからプロファイルデータを取得するには、AuthzConstantsクラスによって格納される名前を使用します。onSuccessバンドルでは、BUNDLE_KEY.PROFILEバンドルにプロファイルデータが含まれます。プロファイルバンドル内で、スコープデータがPROFILE_KEY.NAMEPROFILE_KEY.EMAILPROFILE_KEY.USER_IDPROFILE_KEY.POSTAL_CODEの下にインデックス付けされます。PROFILE_KEY.POSTAL_CODEが返されるのは、postal_codeスコープがリクエストされた場合のみです。

    @Override
    public void onSuccess(Bundle response) {
        // バンドルから必要なデータを取得
        Bundle profileBundle = response.getBundle(
            AuthzConstants.BUNDLE_KEY.PROFILE.val);
        String name = profileBundle.getString(
            AuthzConstants.PROFILE_KEY.NAME.val);
        String email = profileBundle.getString(
            AuthzConstants.PROFILE_KEY.EMAIL.val);
        String account = profileBundle.getString(
            AuthzConstants.PROFILE_KEY.USER_ID.val);
        String zipcode = profileBundle.getString(
            AuthzConstants.PROFILE_KEY.POSTAL_CODE.val);
    
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                updateProfileData(name, email, account, zipcode);
            }
        });
    }
    
  8. onErrorProfileListenerに対して実装します。onErrorにはエラーの情報を含むAuthErrorオブジェクトなどが入ります。

    /* プロファイルの取得中にエラーが発生。 */
    @Override
    public void onError(AuthError ae) {
        /* 再試行するか、ユーザーにエラーを通知 */
    }
    
  9. onErrorAuthorizeListenerに対して実装します。

    /* アプリの認可中にエラーが発生。 */
    @Override
    public void onError(AuthError ae) {
       /* ユーザーにエラーを通知 */
    }
    
  10. onCancelAuthorizeListenerに対して実装します。認可プロセスでは、ウェブブラウザ(またはWebView)を使用中のユーザーにログイン画面(場合によっては同意画面も)が表示されます。これに伴い、ユーザーがログインをキャンセルしたり別の画面に移動したりできる環境も整えておきます。ユーザーが明示的にログインプロセスをキャンセルする場合には、onCancelが呼び出されます。onCancelが呼び出される場合は、UIをリセットする必要があります。

    /* 完了前に認可がキャンセル。 */
    @Override
    public void onCancel(Bundle cause) {
       /* UIをready-to-loginの状態にリセット */
    }
    

起動時のユーザーログインの確認

アプリにログインしたユーザーが、アプリをいったん終了した後で再度アプリを起動させた場合、アプリは引き続きデータを取得できます。ユーザーが自動的にログアウトされることはありません。起動時にアプリが認可されていれば、ユーザーにログイン後の状態を表示できます。このセクションではgetTokenを使用して、アプリがまだ認可されているかどうかを確認する方法について説明します。

  1. TokenListenerを作成します。TokenListenerAPIListenerインターフェイスを実装し、getTokenの呼び出しの結果を処理します。APIListenerにはonSuccessonErrorの2つのメソッドが含まれます(getTokenの呼び出しをキャンセルする手段がないため、onCancelはサポートされていません)。onSuccessはトークンデータを含むBundleオブジェクトを受け取ります。onErrorはエラーの情報を含むAuthErrorオブジェクトを受け取ります。

    private class TokenListener implements APIListener{
    
        /* getTokenが正常に完了。 */
        @Override
        public void onSuccess(Bundle response) {
        }
        /* トークンの取得中にエラーが発生。 */
        @Override
        public void onError(AuthError ae) {
        }
    }
    
  2. ActivityonStartメソッドで、getTokenを呼び出して、アプリがまだ認可されているかどうかを確認します。

    getTokenは未処理のアクセストークンを受け取り、AmazonAuthorizationManagerはそれを使用してユーザープロファイルにアクセスします。トークンの値がnullでなければ、アプリはまだ認可されている状態であり、getProfileへの呼び出しが成功します。

    getTokenには、authorizeに対する呼び出しでリクエストした同じスコープが必要です。

    getTokengetProfileと同じ方法で非同期呼び出しをサポートします。したがって、UIスレッドをブロックしたり、独自のワーカースレッドを作成したりする必要がありません。getTokenを非同期的に呼び出すには、APIListenerインターフェイスをサポートするオブジェクトを最後のパラメーターとして渡します。

    @Override
    protected void onStart(){
        super.onStart();
        mAuthManager.getToken(new String []{"profile","postal_code"}, new TokenListener());
    }
    
  3. onSuccessTokenListenerに対して実装します。onSuccessには2つのタスクがあります。Bundleからトークンを取得することと、トークンが有効な場合にgetProfileを呼び出すことです。Bundleからトークンデータを取得するには、AuthzConstantsクラスによって格納される名前を使用します。onSuccessバンドルでは、BUNDLE_KEY.TOKEN値にトークンデータが含まれます。その値がnullでなければ、この例は、前のセクション(手順7、8参照)で宣言したものと同じリスナーを使用してgetProfileを呼び出します。

    /* getTokenが正常に完了。 */
    @Override
    public void onSuccess(Bundle response) {
        final String authzToken =
            response.getString(AuthzConstants.BUNDLE_KEY.TOKEN.val);
        if (!TextUtils.isEmpty(authzToken))
        {
            // プロファイルデータを取得
            mAuthManager.getProfile(new ProfileListener());
        }
    }
    

認可状態の消去とユーザーのログアウト

clearAuthorizationStateメソッドは、AmazonAuthorizationManagerローカルデータストアからユーザーの認可データを消去します。この後でアプリがプロファイルデータを取得するには、ユーザーが再度ログインする必要があります。このメソッドを使用するのは、ユーザーをログアウトする場合、またはアプリのログイン問題をトラブルシューティングする場合です。

  1. ログアウトのメカニズムを実装します。ユーザーがログインに成功した後、ログアウトのメカニズムを提供してユーザーがプロファイルデータと過去の認可済みのスコープを消去できるようにします。ログアウトのメカニズムとして、ハイパーリンクやメニューアイテムを使用できます。この例では、ボタンのonClickメソッドを作成します。
  2. ログアウトハンドラーで、clearAuthorizationStateを呼び出します。clearAuthorizationStateはユーザーの認可データ(アクセストークン、プロファイル)をローカルストアから削除します。clearAuthorizationStateは、成功または失敗を返すAPIListener以外のパラメーターは受け取りません。
  3. 匿名のAPIListenerを宣言します。匿名クラスは、APIListenerを実装する新しいクラスを宣言するための便利な代替クラスです。 
  4. APIListener内にonSuccessを実装します。clearAuthorizationStateに成功すると、UIをアップデートしてユーザーの参照を削除し、ユーザーが再度ログインできるようにログインメカニズムを提供する必要があります。
  5. onErrorAPIListener内に実装します。clearAuthorizationStateがエラーを返した場合は、ユーザーがログアウトを再試行できるようにします。
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    /* 以前のonCreate宣言の省略 */

    // ログアウトIDのボタンを検索してクリックハンドラーをセットアップ
    mLogoutButton = (Button) findViewById(R.id.logout);
    mLogoutButton.setOnClickListener(new OnClickListener() {
        @Override
        public void onClick(View v) {
            mAuthManager.clearAuthorizationState(new APIListener() {
                @Override
                public void onSuccess(Bundle results) {
                    // UIにログアウト状態を設定
                }
                @Override
                public void onError(AuthError authError) {
                    // エラーをログに記録
                }
            });
        }
    });
}

AmazonAuthorizationManagerメソッドを同期的に呼び出す

一部のAmazonAuthorizationManagerFutureオブジェクトを返します。これにより、メソッドを同期的に呼び出すことができるため、パラメーターとしてリスナーを渡す必要がなくなります。Futureを使用する場合は、UIスレッドで使用しないようにします。UIスレッドを5秒以上ブロックする場合は、「ANR」(アプリが応答していません)のメッセージが表示されます。上記の「ログインボタンの処理とプロファイルデータの取得」の例では、AuthorizeListeneronSuccessメソッドがAmazonAuthorizationManagerによって作成されたワーカースレッドとともに呼び出されます。これは、そのスレッドを使用してgetProfileを同期的に呼び出すことが安全であることを意味します。同期呼び出しを行うには、getProfileからの戻り値をFutureオブジェクトに割り当て、そのオブジェクトでgetメソッドを呼び出してメソッドが終了するまで待機します。

Future.getは、SUCCESSERRORCANCELなどのFUTURE_TYPE値が含まれるBundleオブジェクトを返します。メソッドが成功した場合は、同じバンドルにプロファイルデータのPROFILE_KEYの値が返されます。次に例を示します。

/* 認可が正常に完了。 */
@Override
public void onSuccess(Bundle response) {
    Future<Bundle> future = mAuthManager.getProfile(null);
    Bundle result = future.get();
    // 呼び出しが成功したかどうかを確認し、プロファイルを取得
    Object future_type = result.get(AuthzConstants.BUNDLE_KEY.FUTURE.val);
    if (future_type == AuthzConstants.FUTURE_TYPE.SUCCESS)
    {
        String name = result.getString(
                AuthzConstants.PROFILE_KEY.NAME.val);
        String email = result.getString(
                AuthzConstants.PROFILE_KEY.EMAIL.val);
        String account = result.getString(
                AuthzConstants.PROFILE_KEY.USER_ID.val);
        String zipcode = result.getString(
                AuthzConstants.PROFILE_KEY.POSTAL_CODE.val);

        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                updateProfileData(name, email, account, zipcode);
            }
        });
    }
    else if (future_type == AuthzConstants.FUTURE_TYPE.ERROR)
    {
        // エラーオブジェクトを取得
        AuthError authError = AuthError.extractError(result);

        /* authErrorを使用してエラーを診断 */
    }
    else if (future_type == AuthzConstants.FUTURE_TYPE.CANCEL)
    {
        /* ユーザーが認可中にキャンセル */
    }
}