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アクセストークンを取得します。
-
LWAをAndroidプロジェクトに追加します。「Login with Amazonプロジェクトを作成する」のLogin with Amazonライブラリをインストールするを参照してください。
-
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;
-
RequestContext
を初期化します。RequestContext
メンバー変数を宣言し、クラスの新しいインスタンスを作成する必要があります。インスタンスを作成するには、現在のアプリケーションコンテキストをstaticなファクトリーメソッドに渡します。RequestContext
は、アクティビティのonCreate
メソッド内で初期化することをお勧めします。例:private RequestContext mRequestContext; @Override protected void onCreate(Bundle savedInstance) { super.onCreate(savedInstance); mRequestContext = RequestContext.create(this); }
-
AuthorizeListenerImpl
を作成します。AuthorizeListenerImpl
は、AuthorizeListener
抽象クラスを拡張し、authorize呼び出しの結果を処理します。次の3つのメソッドが含まれます:onSuccess
、onError
、およびonCancel
。onSuccess
メソッドに渡される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) { } }
-
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()); }
-
onResume
メソッドをオーバーライドします。アクティビティ内の
onResume
メソッドをオーバーライドします。RequestContext
インスタンス上で、onResume
メソッドだけでなく、super.onResume()
も呼び出します。これにより、RequestContext
に対して、AuthorizeManager.authorize
呼び出しからのコールバックの準備ができた場合にアプリが再開されると、AuthorizeListener
を呼び出すよう通知されます。@Override protected void onResume() { super.onResume(); mRequestContext.onResume(); }
-
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 } } }); }
-
TokenListener
を作成します。Listener<AuthorizeResult, AuthError>
インターフェースを実装します。リスナーがgetToken
呼び出しの結果を処理します。リスナーには、onSuccess
とonError
の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) { } }
-
AuthorizeListener
のonSuccess
を実装します。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()); }
-
TokenListener
のonSuccess
を実装します。onSuccess
には、以下の2つのタスクがあります。- バンドルからアクセストークンを取り出す。
- UIをログイン状態(ユーザーがログインしていることを示し、ログアウトする手段を提供する)に設定する。
/* getToken completed successfully. */ @Override public void onSuccess(AuthorizeResult authorizeResult) { String accessToken = authorizeResult.getAccessToken(); }
-
アクティビティの
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()); }
-
これで、AVSへのリクエスト時に使用できるアクセストークンが取得できました。
iOSアプリでLWAを使用するには、下の指示に従います。
- Amazon開発者ポータルでモバイルアプリを登録し、アプリのAPIキーを生成します。アカウントを作成してアプリを登録する方法については、「AVSスタートガイド」を参照してください。
- iOS用Login with Amazonに移動し、ステップ1、4、および5を実行します。
- 次に、以下のステップを実行して、AVSで使用するLWAアクセストークンを取得します。
- LWAをiOSプロジェクトに追加します。「Login with Amazonプロジェクトを作成する」のLogin with Amazonライブラリをインストールするを参照してください。
-
LWA APIをソースファイルにインポートします。
LWA APIをインポートするには、以下の
#import
文をソースファイルに追加します。#import <LoginWithAmazon/LoginWithAmazon.h>
-
onLoginButtonClicked
でauthorize:withHandler:
を呼び出します。アプリにLogin with Amazonボタンを追加するステップを実行した場合、
onLoginButtonClicked:
メソッドをLogin with Amazonボタンにリンクする必要があります。このメソッド内で、authorize:withHandler:
を呼び出し、ユーザーにログインしてアプリケーションを認可するプロンプトを提示します。このメソッドを使うと、ユーザーは、以下のいずれかの方法でサインインし、リクエストされた情報を承諾することができます。
- セキュアなコンテキストでのウェブ表示に切り替える(端末にAmazon ショッピングアプリがインストールされている場合)
- Safari View Controllerに切り替える(iOS 9以上)
- システムブラウザに切り替える(iOS 8以下)
1つ目に記述されているセキュアなコンテキストは、端末にAmazonショッピングアプリがインストールされているときに利用できます。ユーザーがすでにAmazonショッピングアプリにサインインしていれば、シングルサインオン(SSO)機能により、このAPIはサインインページをスキップします。
authorize:withHandler:
への最初のパラメーターは、アプリケーションがどのスコープの認可をリクエストしているかを示すAMZNAuthorizeRequest
オブジェクトです。スコープは、Login with Amazonからリクエストしているユーザーデータの範囲です。アプリに最初にログインすると、ユーザーに対してリクエストしているデータのリストが提示され、承認を求められます。authorize:withHandler:
への2つ目のパラメーターは、AMZNAuthorizationRequestHandler
です。これについては、次のステップで説明します。 -
AMZNAuthorizationRequestHandler
ブロックオブジェクトを作成します。AMZNAuthorizationRequestHandler
は、authorize:withHandler:
呼び出しの結果を処理します。objective-cブロックの詳細については、developer.apple.comでブロックの使用を参照してください。AMZNAuthorizationRequestHandler
の最初のパラメーターはAMZNAuthorizeResult
オブジェクトです。ユーザーが正常に認可されたら、AMZNAuthorizeResult
には、ユーザーのプロファイルデータにアクセスするために使用できるアクセストークンと、ユーザーのプロファイルデータを含むAMZNUser
オブジェクトが含まれます。AMZNAuthorizationRequestHandler
の2つ目のパラメーターは、userDidCancel
と呼ばれるブール値です。このパラメーターには、ユーザーが以下を実行した場合にtrueがセットされます。- ログインと認可の途中でSafari View Controllerを閉じた場合(iOS 9以上)
- Amazonショッピングアプリ内でウェブ表示を閉じた場合
- ログインをキャンセルし、認可を拒否した場合
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]; } }]; }
-
起動時にユーザーのログイン状態を確認します。
ユーザーがアプリにログインし、アプリを終了して、後でアプリを再起動した場合、アプリはまだデータの取得を認可されています。ユーザーは自動的にはログアウトされません。起動時に、アプリがまだ認可されている場合は、ユーザーにログイン状態であることを示すことができます。このセクションでは、
authorize:withHandler:
を使用してアプリがまだ認可されているかどうかを確認する方法を説明します。AMZNAuthorizeRequest
オブジェクトを作成し、アプリケーションで認可をリクエストしているユーザーデータを示すスコープを指定します。詳細については、ステップ3を参照してください。-
AMZNAuthorizeRequest.interactiveStrategy
をAMZNInteractiveStrategyNever
に設定します。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]; } }];
-
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; }
- これで、AVSへのリクエスト時に使用できるアクセストークンが取得できました。