Alexa搭載モバイル製品の認可



概要

Alexa Voice Serviceにアクセスするには、Alexa搭載のAndroidまたはiOSアプリでLogin with Amazon(LWA)のアクセストークンを取得する必要があります。このアクセストークンを、リクエストのたびにAlexa Voice Serviceに送信します。このドキュメントでは、LWA SDKを使用してアクセストークンを取得する方法を説明します。

この方法を使うケース

シナリオ: AlexaをAndroidまたはiOSに追加しようとしています。認可して、ユーザーアカウントに関連付ける必要のあるスマートスピーカーなどのヘッドレス端末はありません。

Login with Amazon SDKを使用する

下のタブを使用して、オペレーティングシステムを選択してください。

AndroidアプリでLWAを使用するには、下の指示に従います。

  • Amazon開発者ポータルでモバイルアプリを登録し、アプリのAPIキーを生成します。アカウントを作成してアプリを登録する方法については、「AVSスタートガイド」を参照してください。
  • Android用Login with Amazonに移動し、ステップ1、4、および5を実行します。
  • 次に、以下のステップを実行して、AVSで使用するLWAアクセストークンを取得します。
  1. LWAをAndroidプロジェクトに追加します。「Login with Amazonプロジェクトを作成する」のLogin with Amazonライブラリをインストールするを参照してください。

  2. LWA APIをソースファイルにインポートします。LWA APIをインポートするには、以下のimport文をソースファイルに追加します。

    import com.amazon.identity.auth.device.AuthError;
    import com.amazon.identity.auth.device.api.Listener;
    import com.amazon.identity.auth.device.api.authorization.AuthCancellation;
    import com.amazon.identity.auth.device.api.authorization.AuthorizationManager;
    import com.amazon.identity.auth.device.api.authorization.AuthorizeListener;
    import com.amazon.identity.auth.device.api.authorization.AuthorizeRequest;
    import com.amazon.identity.auth.device.api.authorization.AuthorizeResult;
    import com.amazon.identity.auth.device.api.authorization.Scope;
    import com.amazon.identity.auth.device.api.authorization.ScopeFactory;
    import com.amazon.identity.auth.device.api.workflow.RequestContext;
    
  3. RequestContextを初期化します。

    RequestContextメンバー変数を宣言し、クラスの新しいインスタンスを作成する必要があります。インスタンスを作成するには、現在のアプリケーションコンテキストをstaticなファクトリーメソッドに渡します。RequestContextは、アクティビティのonCreateメソッド内で初期化することをお勧めします。例:

    private RequestContext mRequestContext;
    
    @Override
    protected void onCreate(Bundle savedInstance) {
        super.onCreate(savedInstance);
        mRequestContext = RequestContext.create(this);
    }
    
  4. AuthorizeListenerImplを作成します。

    AuthorizeListenerImpl は、AuthorizeListener抽象クラスを拡張し、authorize呼び出しの結果を処理します。次の3つのメソッドが含まれます: onSuccessonError、およびonCancelonSuccessメソッドに渡されるAuthorizeResultオブジェクトには、アクセストークンが含まれます。

    private class AuthorizeListenerImpl extends AuthorizeListener {
    
        /* Authorization was completed successfully. */
        @Override
        public void onSuccess(final AuthorizeResult authorizeResult) {
        }
    
        /* There was an error during the attempt to authorize the application. */
        @Override
        public void onError(final AuthError authError) {
        }
    
        /* Authorization was cancelled before it could be completed. */
        @Override
        public void onCancel(final AuthCancellation authCancellation) {
        }
    }
    
  5. AuthorizeListenerImplのインスタンスを作成し、登録します。

    AuthorizeListenerImplのインスタンスを作成し、RequestContextインスタンスに登録します。AuthorizeManager.authorizeの呼び出しが行われると、RequestContextインスタンスは、authorizeリクエストの結果を使用してAuthorizeListenerで適切なコールバックメソッドを呼び出します。AuthorizeListenerImplインスタンスは、onCreateメソッド内に登録することをお勧めします。

    @Override
    protected void onCreate(Bundle savedInstance) {
        super.onCreate(savedInstance);
        mRequestContext = RequestContext.create(this);
        mRequestContext.registerListener(new AuthorizeListenerImpl());
    }
    
  6. onResumeメソッドをオーバーライドします。

    アクティビティ内のonResumeメソッドをオーバーライドします。RequestContextインスタンス上で、onResumeメソッドだけでなく、super.onResume()も呼び出します。これにより、RequestContextに対して、AuthorizeManager.authorize呼び出しからのコールバックの準備ができた場合にアプリが再開されると、AuthorizeListenerを呼び出すよう通知されます。

    @Override
    protected void onResume() {
        super.onResume();
        mRequestContext.onResume();
    }
    
  7. AuthorizeManager.authorizeを呼び出します。

    Login with AmazonボタンのonClickハンドラーで、authorizeを呼び出し、ユーザーにログインしてアプリケーションを認可するよう求めます。このメソッドは、以下のいずれかの方法でユーザーを認可します。

    • システムブラウザに切り替え、ユーザーにサインインしてリクエストされた情報を承諾するよう求める。

    • セキュアなコンテキストでのウェブ表示に切り替え、ユーザーにサインインしてリクエストされた情報を承諾するよう求める。


    2つ目に記述されているセキュアなコンテキストは、現在、Android端末上のAmazonショッピングアプリとして利用できます。Fire OSを実行しているAmazon端末(KindleタブレットやFire TV端末など)は、端末上にAmazonショッピングアプリがなくても、常にこのオプションを使用します。このため、ユーザーがすでにAmazonショッピングアプリにサインインしていれば、シングルサインオン(SSO)機能により、このAPIはサインインページをスキップします。

    アプリケーションが認可されると、スコープと呼ばれる1つ以上のデータセットに対して認可されます。1つ目のパラメーターは、LWAからリクエストしているユーザーデータの範囲となるスコープの配列です。アプリに最初にログインすると、ユーザーに対してリクエストしているデータのリストが提示され、承認を求められます。AVSで使用するLWAでは、現在alexa:allスコープがサポートされています。

    認可の呼び出しは非同期で行われ、呼び出しの結果を使用してAuthorizeListenerImplインスタンスが呼び出されます。

    private RequestContext mRequestContext;
    private static final String PRODUCT_ID = "INSERT YOUR PRODUCT ID FROM AMAZON DEVELOPER CONSOLE";
    private static final String PRODUCT_DSN = "INSERT UNIQUE DSN FOR YOUR DEVICE";
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mRequestContext = RequestContext.create(this);
        mRequestContext.registerListener(new AuthorizeListenerImpl());
    
        // Find the button with the login_with_amazon ID
        // and set up a click handler
        mLoginButton = (Button) findViewById(R.id.login_with_amazon);
        mLoginButton.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                final JSONObject scopeData = new JSONObject();
                final JSONObject productInstanceAttributes = new JSONObject();
    
                try {
                    productInstanceAttributes.put("deviceSerialNumber", PRODUCT_DSN);
                    scopeData.put("productInstanceAttributes", productInstanceAttributes);
                    scopeData.put("productID", PRODUCT_ID);
    
                    AuthorizationManager.authorize(new AuthorizeRequest.Builder(mRequestContext)
                        .addScope(ScopeFactory.scopeNamed("alexa:all", scopeData))
                        .forGrantType(AuthorizeRequest.GrantType.ACCESS_TOKEN)
    		                .shouldReturnUserData(false)
                        .build());
                } catch (JSONException e) {
                    // handle exception here
                }
            }
        });
    }
    
  8. TokenListenerを作成します。

    Listener<AuthorizeResult, AuthError>インターフェースを実装します。リスナーがgetToken呼び出しの結果を処理します。リスナーには、onSuccessonErrorの2つのメソッドが含まれます(getTokenをキャンセルできないため、onCancelはサポートされません)。onSuccess は、トークンデータとAuthorizeResultオブジェクトを受信します。一方、onErrorは、エラー情報とAuthErrorオブジェクトを受信します。

    public class TokenListener implements Listener<AuthorizeResult, AuthError> {
        /* getToken completed successfully. */
        @Override
        public void onSuccess(AuthorizeResult authorizeResult) {
        }
    
        /* There was an error during the attempt to get the token. */
        @Override
        public void onError(AuthError authError) {
        }
    }
    
  9. AuthorizeListeneronSuccessを実装します。

    onSuccessで、AmazonAuthorizationManager.getTokenを呼び出してアクセストークンを取り出します。getTokenは、authorize同様、非同期のlistenerインターフェースを使用します。getTokenの場合、インターフェースはListener<AuthorizeResult, AuthError>であり、AuthorizationListenerではありません。

    @Override
    public void onSuccess(Bundle response) {
        AuthorizationManager.getToken(this, new Scope[] { ScopeFactory.scopeNamed("alexa:all") }, new TokenListener());
    }
    
  10. TokenListeneronSuccessを実装します。

    onSuccess には、以下の2つのタスクがあります。

    • バンドルからアクセストークンを取り出す。
    • UIをログイン状態(ユーザーがログインしていることを示し、ログアウトする手段を提供する)に設定する。
    /* getToken completed successfully. */
    @Override
    public void onSuccess(AuthorizeResult authorizeResult) {
        String accessToken = authorizeResult.getAccessToken();
    }
    
  11. アクティビティのonStartメソッドで、getTokenを呼び出し、アプリケーションがまだ認可されているかを確認します。

    • getToken は、未加工のアクセストークンを取り出します。このアクセストークンは、AVSへのリクエストを行う際に使用できます。
    • getToken には、authorizeの呼び出しでリクエストしたのと同じスコープが必要です。
    private static final Scope ALEXA_ALL_SCOPE = ScopeFactory.scopeNamed("alexa:all");
    
    @Override
    protected void onStart(){
        super.onStart();
        AuthorizationManager.getToken(this, new Scope[] { ALEXA_ALL_SCOPE }, new TokenListener());
    }
    
  12. これで、AVSへのリクエスト時に使用できるアクセストークンが取得できました。

iOSアプリでLWAを使用するには、下の指示に従います。

  • Amazon開発者ポータルでモバイルアプリを登録し、アプリのAPIキーを生成します。アカウントを作成してアプリを登録する方法については、「AVSスタートガイド」を参照してください。
  • iOS用Login with Amazonに移動し、ステップ1、4、および5を実行します。
  • 次に、以下のステップを実行して、AVSで使用するLWAアクセストークンを取得します。
  1. LWAをiOSプロジェクトに追加します。「Login with Amazonプロジェクトを作成する」のLogin with Amazonライブラリをインストールするを参照してください。
  2. LWA APIをソースファイルにインポートします。

    LWA APIをインポートするには、以下の#import文をソースファイルに追加します。

    #import <LoginWithAmazon/LoginWithAmazon.h>
    
  3. onLoginButtonClickedauthorize:withHandler:を呼び出します。

    アプリにLogin with Amazonボタンを追加するステップを実行した場合、onLoginButtonClicked:メソッドをLogin with Amazonボタンにリンクする必要があります。このメソッド内で、authorize:withHandler:を呼び出し、ユーザーにログインしてアプリケーションを認可するプロンプトを提示します。

    このメソッドを使うと、ユーザーは、以下のいずれかの方法でサインインし、リクエストされた情報を承諾することができます。

    1. セキュアなコンテキストでのウェブ表示に切り替える(端末にAmazon ショッピングアプリがインストールされている場合)
    2. Safari View Controllerに切り替える(iOS 9以上)
    3. システムブラウザに切り替える(iOS 8以下)

    1つ目に記述されているセキュアなコンテキストは、端末にAmazonショッピングアプリがインストールされているときに利用できます。ユーザーがすでにAmazonショッピングアプリにサインインしていれば、シングルサインオン(SSO)機能により、このAPIはサインインページをスキップします。

    authorize:withHandler:への最初のパラメーターは、アプリケーションがどのスコープの認可をリクエストしているかを示すAMZNAuthorizeRequestオブジェクトです。スコープは、Login with Amazonからリクエストしているユーザーデータの範囲です。アプリに最初にログインすると、ユーザーに対してリクエストしているデータのリストが提示され、承認を求められます。

    authorize:withHandler:への2つ目のパラメーターは、AMZNAuthorizationRequestHandlerです。これについては、次のステップで説明します。

  4. AMZNAuthorizationRequestHandlerブロックオブジェクトを作成します。

    AMZNAuthorizationRequestHandler は、authorize:withHandler:呼び出しの結果を処理します。objective-cブロックの詳細については、developer.apple.comブロックの使用を参照してください。

    AMZNAuthorizationRequestHandlerの最初のパラメーターはAMZNAuthorizeResultオブジェクトです。ユーザーが正常に認可されたら、AMZNAuthorizeResultには、ユーザーのプロファイルデータにアクセスするために使用できるアクセストークンと、ユーザーのプロファイルデータを含むAMZNUserオブジェクトが含まれます。

    AMZNAuthorizationRequestHandlerの2つ目のパラメーターは、userDidCancelと呼ばれるブール値です。このパラメーターには、ユーザーが以下を実行した場合にtrueがセットされます。

    1. ログインと認可の途中でSafari View Controllerを閉じた場合(iOS 9以上)
    2. Amazonショッピングアプリ内でウェブ表示を閉じた場合
    3. ログインをキャンセルし、認可を拒否した場合

    AMZNAuthorizationRequestHandlerの3つ目のパラメーターは、SDKまたは認可サーバーが原因でログインと認可が失敗した場合のエラーの詳細を含むNSErrorオブジェクトです。

    NSString *productId = @"INSERT YOUR PRODUCT ID FROM AMAZON DEVELOPER CONSOLE";
    NSString *productDsn = @"INSERT UNIQUE DSN FOR YOUR DEVICE";    
    
    - (IBAction) onLogInButtonClicked:(id)sender {
        NSDictionary *scopeData = @{@"productID": productId,
                                    @"productInstanceAttributes": @{@"deviceSerialNumber": productDsn}};
    
        id<AMZNScope> alexaAllScope = [AMZNScopeFactory scopeWithName:@"alexa:all" data:scopeData];
    
        AMZNAuthorizeRequest *request = [[AMZNAuthorizeRequest alloc] init];
        request.scopes = @[alexaAllScope];
        request.grantType = AMZNAuthorizationGrantTypeToken;
    
        //Make an Authorize call to the LWA SDK.
        AMZNAuthorizationManager *authManager = [AMZNAuthorizationManager sharedManager];
        [authManager authorize:request withHandler:^(AMZNAuthorizeResult *result, BOOL userDidCancel, NSError *error) {
            if (error) {
                // Notify the user that authorization failed
                [[[UIAlertView alloc] initWithTitle:@"" message:[NSString stringWithFormat:@"User authorization failed due to an error: %@", error.localizedDescription] delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil] show];
            } else if (userDidCancel) {
                // Notify the user that the authorization was cancelled
                [[[UIAlertView alloc] initWithTitle:@"" message:@"Authorization was cancelled prior to completion. To continue, you will need to try logging in again." delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil] show];
            } else {
                // Fetch the access token and return to controller
                self.token = result.token;
                [self userSuccessfullySignedIn];
    
            }
        }];
    }
    
  5. 起動時にユーザーのログイン状態を確認します。

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

    1. AMZNAuthorizeRequestオブジェクトを作成し、アプリケーションで認可をリクエストしているユーザーデータを示すスコープを指定します。詳細については、ステップ3を参照してください。
    2. AMZNAuthorizeRequest.interactiveStrategyAMZNInteractiveStrategyNeverに設定します。AMZNAuthorizeRequest は、ユーザーにログインを求める戦略を複数サポートします。

      • AMZNInteractiveStrategyAuto (デフォルト): SDKは、ローカルに保存された以前のauthorize:withHandler:応答からの認可グラントを探します。利用可能で、有効かつ必要なスコープをすべて含むものが見つかったら、SDKはAMZNAuthorizationRequestHandlerを介して正常応答を返し、ユーザーにログインを求めません。それ以外の場合、ユーザーにログインを求めます。
      • AMZNInteractiveStrategyAlways: SDKは、アプリの使用が以前に認可されていたかどうかに関係なく、常にユーザーにログインを求めます。ログインプロンプトを提示したら、SDKはローカルのキャッシュ内にあるアプリの認可グラントをすべて削除します。
      • AMZNInteractiveStrategyNever: SDKは、ローカルに保存された以前のauthorize:withHandler応答からの認可グラントを探します。利用可能で、有効かつ必要なスコープをすべて含むものが見つかったら、SDKは、アクセストークンとユーザープロファイルデータを含むAMZNAuthorizeResultオブジェクトを返します。それ以外の場合、AMZNAuthorizationRequestHandlerを介してNSErrorオブジェクトを返します。
    // Build an authorize request.
    AMZNAuthorizeRequest *request = [[AMZNAuthorizeRequest alloc] init];
    request.scopes = @[alexaAllScope];
    request.grantType = AMZNAuthorizationGrantTypeToken;
    
    request.interactiveStrategy = AMZNInteractiveStrategyNever;
    
    [AMZNAuthorizationManager sharedManager] authorize:request
    withHandler:^(AMZNAuthorizeResult *result BOOL
    userDidCancel NSError *error) {
       if (error) {
            // Error from the SDK, indicating the user was not previously authorized to your app for the requested scopes.
       } else {
            // Fetch the access token and return to controller
            self.token = result.token;
            [self userSuccessfullySignedIn];
       }
    }];
    
  6. UIApplicationDelegateプロトコルを処理するプロジェクト内のクラスに、application:openURL:sourceApplication:annotation:を実装します。

    デフォルトでは、プロジェクト内のAppDelegateクラスです。アプリがAmazonログインページを提示し、ユーザーがログインを完了したら、あらかじめ登録したURLスキームを使用してアプリにリダイレクトされます。リダイレクトは、application:openURL:sourceApplication:annotation:application:openURL:sourceApplication:annotation:に渡され、URLが正常に処理された場合はYESを返します。

    handleOpenURL:sourceApplication:は、LWAのリダイレクトURLを処理するSDKライブラリの関数です。handleOpenURL:sourceApplication:YESを返した場合、URLが処理されたことを示します。

    - (BOOL)application:(UIApplication *)application
       openURL:(NSURL *)url
       sourceApplication:(NSString *)sourceApplication
       annotation:(id)annotation
    {
        // Pass on the url to the SDK to parse authorization code from the url.
    
        BOOL isValidRedirectSignInURL =
          [AIMobileLib handleOpenURL:url sourceApplication:sourceApplication];
        if(!isValidRedirectSignInURL)
            return NO;
    
        // App may also want to handle url
        return YES;
    }
    
  7. これで、AVSへのリクエスト時に使用できるアクセストークンが取得できました。

リソース