kun432's blog

Alexaなどスマートスピーカーの話題中心に、Voiceflowの日本語情報を発信してます。たまにAWSやkubernetesなど。

〜スマートスピーカーやVoiceflowの記事は右メニューのカテゴリからどうぞ。〜

AlexaタイマーAPIを試してみた② 〜音声による権限の許可〜

f:id:kun432:20200411225821p:plain

前回に引き続き、タイマーAPIのお試しです。

前回は、

  • タイマーの権限チェック
  • タイマーのセット
  • タイマーの状況確認

までやりました。今回は、

  • タイマーの権限を音声で許可する

をやります。全2回の予定でしたが、タイマーの一時停止・再開は次回に回します。

タイマーの権限を音声で許可する

おさらいです。前回のコードでは、タイマーの権限チェックはLaunchRequestHandlerとsetTimerIntentHandlerの中で、以下のようにconsentTokenをチェックして、権限が許可されていなければカードを送信していました。

この場合、スキルに権限を許可するには、

  • スマホのアレクサアプリを開く
  • アクティビティーからカードをタップ
  • スキルの設定画面で権限にチェック

という形になり、どうしても一手間かかります。これを音声でやれるとEchoデバイスだけで完結するのでとてもシームレスですよね。

ということで、

タイマーの場合は音声による権限の許可ができますのでこれを使ってみましょう。

ちなみにリマインダーも音声での権限許可ができるようになっています。詳しくはこちら。

では早速コードを修正していきます。まず、今の権限チェックのコード、LaunchRequestHandlerとsetTimerIntentHandlerの両方に同じコードが書いてあって冗長です。関数に切り出してしまいましょう。verifyConsentTokenという関数を用意します。

handlerInputをまるっと関数に渡して、関数の中でアクセス権をチェックします。アクセス権がなければレスポンスをまるっと返します。アクセス権があればnullが返ります。

これを呼び出し元のLaunchRequestHandlerとsetTimerIntentHandlerで以下のように修正します。

とてもシンプルになりましたね。

ではこのverifyConsentToken関数を修正して音声での権限許可ができるようにします。音声での権限許可はSkill Connectionの機能を使っています。つまり、リクエストを投げるだけであとはアレクサがよしなにユーザとやりとりしてくれるということです。verifyConsentToken関数のコードはこういう感じになります。

ISPやSkill Connectionsをやったことがあればわかりやすいかと思います。'nameAskFor'を指定してpayloadに必要なパーミッションを含めて、Connections.SendRequestディレクティブを送信してあげればよいようです。これリマインダの場合もpermissionScope変えるだけであとは同じです。ちょっとだけ引っかかったのは、カードだと複数の権限を一気に要求できるのでwithAskForPermissionsConsentCardには権限を配列で渡していましたが、音声の場合は一つだけのようです。したがって、以下の部分も変更する必要があります。

で、ISPやSkill Connectionsと同じような感じ・・・ということは、結果がConnections.Responseで返ってきますので、この結果を受けて処理を行うためのレスポンスハンドラを追加する必要があります。

レスポンスハンドラではRequestTypeがConnection.Responseでrequest.nameがAskForのレスポンスを受け取るようにします。Connections.SendRequestが正常に処理されれば、status.code 200が返りますが、あくまでもこれは処理が正常に行われたかどうかであり、ユーザの権限許可が行われたかどうかはpayloadに含まれるstatusを見て判断します。結果は以下の3種類です。

  • ACCEPTED(ユーザが許可した)
  • DECLINED(ユーザが許可しなかった)
  • NOT_ANSWERED(ユーザが応答しなかった、もしくは聞き取れなかった)

ACCEPTED以外は音声での権限許可ができなかったということなのでスキルをそのまま終わらせています。ACCEPTEDの場合は権限が許可されたのでこのままスキルを継続してタイマーをセットするように促します。あと、これは調べても出てこなかったのですが、ACCEPTED以外の場合にpayloadにisCardThrownというキーが返ってくる場合があるようで、この場合はこれまで通りカードによる権限要求を行うようです。どういう条件でこれが発動されるのかはちょっとわかりませんが、カードによる権限要求はwithAskForPermissionsConsentCardを使うので、必要な権限はこれまで通り配列で渡さないといけないという・・・ややこしいですね。

とりあえず音声による許可の実装は完了です。リクエストハンドラにAskForResponseHandlerを追加しておくこともお忘れなく。

ではテストしてみましょう。

テスト

テストの前にタイマーの権限を一旦もとに戻しておいてください。今回はタイマーのセットの手前までなので、開発者コンソールで試してみます。

f:id:kun432:20200415033027p:plain

スキル起動後に権限を許可するメッセージが出ていますね。これスキル側では何もしてなくてSkill Connectionsの機能によるものです。対話を作らなくていいのは非常に楽ちんですね。「はい」で許可するとそのままシームレスにタイマーセットに行くのもいい感じです。

f:id:kun432:20200415033040p:plain

こちらは拒否した場合です。先程記載していたisCardThrown、これ逆にデフォルトで返ってくるようです。一旦は拒否したけどいつでも設定を変更できるようにカードは送っておくということなのかな?テストシミュレータでも"isCardThrown": falseが返ってきていました。

で公式ドキュメントには説明が見つからなかったのですが、githubのデモで見つけました。

Check if the user has granted permissions through voice permissions and whether the home card has already been sent. If not, send an AskForPermissionsConsent card to the Alexa Companion mobile app. Otherwise let the user know a home card requesting permissions has been sent to the mobile app and they can also grant permissions through the skill. Reference: https://developer.amazon.com/docs/custom-skills/request-customer-contact-information-for-use-in-your-skill.html#permissions-card-for-requesting-customer-consent

うーん、ちょっとよくわからないですが、カードが既に送られたかどうか?をチェックしているんですかね???今回のスキルでは起動直後に権限のチェックを行っていて、権限がなければスキルを継続できない様になっていますが、もしかすると同一セッション内で権限許可のチェックが複数回行われた場合とかを見てるのかもしれませんね、2回目以降は送らないみたいな。ごめんなさい、ここはちょっと未確認なので想像です。

一応想定通りに動いているので良しとします。

まとめ

音声だけで権限許可からタイマーの利用までが一気通貫でできるのはやっぱりいいですね。

次回は残りのタイマーの一時停止と再開をやります。