前提
- スキルのモデル
- カスタムスキルのみ
- アカウントリンク設定
-
ユーザーが音声を使用して自分のアカウントをスキルにリンクすることを許可する
をオンにする
-
- ユーザー認証
- Login with Amazon (LWA) のみ
- アクセス権限
-
ユーザー名(姓名または名前)
をオンにする -
スキルのパーソナライズ
はオフにする
-
- ユーザープロフィール
- ユーザーの
プロフィール
に電話番号が登録されている
- ユーザーの
キーワード
- Account Linking
- Login with Amazon (LWA)
- Skill Connections
実装手順
- プロフィールの確認
- セキュリティプロファイルの設定
- スキルの設定
- コード作成
プロフィールの確認
アカウント所有者に対して、電話番号が登録されていないと以下のようなエラーが出て Voice-Forward Account Linking が使用できないので、まずはここを確認する。
The user hasn't specified phone number necessary to validate their account linking request.
家族アカウントがたくさんあってどれがアカウント所有者かわからなくなってしまった場合は、 プロフィール管理画面で確認できる。プロフィールの詳細を開いて
アカウント管理者
と書いてあるアカウントを探す。また、プロフィールを作り過ぎてしまってAlexaアプリでプロフィール消せずに困っている場合はここで削除することができる。Alexaアプリでは削除ができない。
不要なアカウントを消したはいいけど、Alexaアプリで以下のようなエラーがでるようになってしまったら、Alexaアプリをサインアウトすることで元にもどる。
セキュリティプロファイルの設定
Login With Amazonの設定。新規作成して必要情報を入力するだけ。簡単です。
スキルの設定
Devloper Console の ツール
- アカウントリンク
から、ユーザーが音声を使用して自分のアカウントをスキルにリンクすることを許可する
をオンにする。
当然ユーザーがアカウントや既存アカウントへのリンクを作成することを許可しますか?
もオンにしておく。
アカウントリンクなしでスキルを有効にすることをユーザーに許可します (推奨)。
これもオンにしておく。そうしないと、Alexaアプリでスキルを有効化した時にアカウントリンクを求められるため。
Auth Code Grant
に、セキュリティプロファイルの値を設定する。
Devloper Console の ツール
- アクセス権限
で、ユーザー名(姓名または名前)
をオンにする。また、スキルのパーソナライズ
がオンになっていると、音声によるアカウントリンクができないので、これはオフにしておく。
コード作成
設定ができていれば、サンプルコードをコピペするだけで動く。サンプルコードやステータスは以下に記載されている。
参考:Voice-Forward Account Linking Implementation Details (LWA)
responseBuilder
で 下記のディレクティブを設定するだけです。下記の例は LaunchRequestHandler
に記載していますが、アカウントリンクが必要なハンドラーのresponseBuilder
に記載すればOKです。Skill Connections
の機能を利用してAmazon側に処理を投げる。
const LaunchRequestHandler = {
canHandle(handlerInput) {
return Alexa.getRequestType(handlerInput.requestEnvelope) === 'LaunchRequest';
},
handle(handlerInput) {
const accessToken = handlerInput.requestEnvelope.context.System.user.accessToken;
console.log(`accessToken: ${JSON.stringify(accessToken)}`);
if (accessToken === undefined){
//Account is not linked
return handlerInput.responseBuilder
.speak('音声によるアカウントリンクを開始します。')
.addDirective({
'type': 'Connections.StartConnection',
'uri': 'connection://AMAZON.AskForAccountLinking/1',
'onCompletion': 'RESUME_SESSION',
'input': {
'@version': '1',
'@type': 'AskForAccountLinking'
},
'token': 'accountLinking'
// Token can be anything that can be used to identify the request on session resumption
})
.getResponse();
}else{
// Handle the account already linked flow.
}
}
};
Amazon側で処理が完了したら、SessionResumedRequest
というリクエストが送信されてくるので、このリクエストを受け取るハンドラーを作っておく必要がある。これもサンプル通り。他のSkill Connections
のリクエストと区別できるように、request.cause.token === 'accountLinking'
を条件に加えられている。
const AccountLinkingSessionResumedHandler = {
canHandle(handlerInput) {
const request = handlerInput.requestEnvelope.request;
return request.type === 'SessionResumedRequest' && request.cause.token === 'accountLinking'; // Token needs to be same as passed in request
},
handle(handlerInput) {
console.log(`AccountLinkingSessionResumedHandler: ${JSON.stringify(handlerInput)}`);
const status = handlerInput.requestEnvelope.request.cause.status;
const code = status.code;
const message = status.message;
console.log(`AccountLinkingSessionResumedHandler received status code : ${code} and message : ${message}`);
const accountLinkingStatus = handlerInput.requestEnvelope.request.cause.result.status;
if (code !== '200'){
//Error occured in the request
//Response
return handlerInput.responseBuilder
.speak('リクエストでエラーが発生しました。')
.withLinkAccountCard()
.getResponse();
}
// Now check to see if the user passed or failed account linking.
const accountLinkingTaskResult = handlerInput.requestEnvelope.request.cause.result;
const accountLinkingTaskStatus = accountLinkingTaskResult.status;
console.log(`accountLinkingTaskStatus: ${JSON.stringify(accountLinkingTaskStatus)}`);
if (accountLinkingTaskStatus === 'LINKED') {
// Account was linked or is linked successfully as part of the request
// <HANDLE_LINKED>
//Response
var accessToken = handlerInput.requestEnvelope.context.System.user.accessToken;
// Logic to look up or create account if necessary
// If you have a resource server that makes call internally to LWA to get the LWA ID
// makeHttpCall('resource_server',accessToken);
// If you need LWA_ID for your operation
// https://developer.amazon.com/docs/login-with-amazon/obtain-customer-profile.html#call-profile-endpoint
// makeHttpCall('https://api.amazon.com/user/profile?access_token=*',accessToken);
// Use LWA_ID from the request above to look up or create an account as necessary
// If you need customer contact information, use the Alexa Customer Profile API
// https://developer.amazon.com/en-US/docs/alexa/custom-skills/request-customer-contact-information-for-use-in-your-skill.html
return handlerInput.responseBuilder
.speak('アカウントがリンクされました。')
.getResponse();
} else if (accountLinkingTaskStatus === 'DENIED') {
// User denied the account linking permissions on request or sharing the information with the skill, hence the account linking flow failed.
// <HANDLE_DENIED>
//Response
return handlerInput.responseBuilder
.speak('アカウントリンクができませんでした。。')
.withLinkAccountCard()
.getResponse();
} else if (accountLinkingTaskStatus === 'NOT_ANSWERED') {
// The user did not answer the question, asked as part of the skill.
// <HANDLE_NOT_ANSWERED>
//Response
return handlerInput.responseBuilder
.speak('ユーザーからの答えがありませんでした。。')
.withLinkAccountCard()
.getResponse();
} else if (accountLinkingTaskStatus === 'USER_REQUIREMENTS_NOT_MET'){
// The request was cancelled because the voice account linking flow can't be triggered for the customer or can't be completed.
// <HANDLE_USER_REQUIREMENTS_NOT_MET>
//Response
return handlerInput.responseBuilder
.speak('リクエストがキャンセルされました。')
.withLinkAccountCard()
.getResponse();
}
}
};
こんな感じで、音声でアカウントリンクさせることができる。