[日本語 #Alexa ] スキルからユーザーの名前やメールアドレス、携帯電話番号が取得できるようになりました

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

アメリカのAlexaブログが1日に更新され、新しい "Customer Profile API" が発表されました。ユーザーが許可すれば、ユーザーのAmazonアカウントに登録された氏名やメールアドレス、携帯電話番号を取得することができるものです。詳細なドキュメントには、REST APIで取得する方法のみが書かれていましたが、ASK SDK v2 for Node.js で取得する方法を調査しましたので、ご紹介します。

Request Permission and Access Contact Information with the New Customer Profile API

背景

EC用のスキルなどでは、これまではスキルの利用には アカウントリンクが必須でした。購入する個人を正確に特定することも理由の一つですが、カスタムスロットによる認証だと、Alexaアプリの発話履歴に個人情報が残ってしまう問題があるためです。

しかしながら、エンドユーザーにスキルを使っていただく観点では、アカウントリンクという操作はハードルが高いという側面があります。そのため、これが原因でスキルそのものをご利用いただけない可能性があります。また、スキルを提供する側で、注文に際して名前やメールアドレスと電話番号程度が分かれば良い場合でも、上記の個人情報の観点から、ユーザーにはハードルの高いアカウントリンクの操作をお願いする必要がありました。

今回の "Customer Profile API" は、Alexaを利用する際に紐付けられるAmazonアカウントにあらかじめ登録された情報を取得することで、このようなアカウントリンクのハードルを下げることができる点が期待されます。ブログ記事にも、以下のような記述があります。

If you currently collect this information using a voice query and slots, consider using the Customer Profile API instead in order to achieve higher accuracy and a simpler dialogue flow for customers. If you currently use account linking solely to capture this information, consider using the Customer Profile API instead to eliminate the need to for new customers to link accounts. You can also consider asking your existing customers to grant you permission to access contact information and eliminating the need to maintain your own account pool.

スキル側の準備

Alexa Skills Kit開発者コンソールで、情報を取得したいスキルを開き、メニューの最後にある[アクセス権限]を開きます。 Alexa Skills Kit開発者コンソールのアクセス権限の画面 今回対象となるのは、次の項目です。

  • ユーザー名(姓名)
  • ユーザーのEメールアドレス
  • ユーザーの電話番号

取得する情報は必要最小限とするべきです。ユーザー名について「名前(Given Name/First Name)」は日本では対象外のようです。また「ユーザーの電話番号」とありますが、正確には携帯電話番号になります。

以上で、skill.json には次の項目が追加されます。

    "permissions": [
      {
        "name": "alexa::profile:name:read"
      },
      {
        "name": "alexa::profile:mobile_number:read"
      },
      {
        "name": "alexa::profile:email:read"
      }
    ]

これで、スキル側の準備ができました。

ユーザー側

取得できる情報

取得するエンドユーザーの情報は、Amazon.co.jp で買い物をする際に登録した情報になります。場所を確認しましょう。

  1. Amazon.co.jpにログインしている状態で、ナビゲーションバーの「<名前>さん アカウント&リスト」をクリックします。 Amazon.co.jpのトップページ、ナビゲーションの箇所
  2. メニューから[アカウントサービス]を選択し、[ログインとセキュリティ] を選択します。 [アカウントサービス]の[ログインとセキュリティ]
  3. ここで表示される[ログインとセキュリティ]の情報を、Alexaスキルで取得できるようになります。 [ログインとセキュリティ]の情報。名前、Eメールアドレス、携帯電話番号、現在のパスワード、高度なセキュリティ設定 の項目があり、それぞれ編集できるようになっている。

携帯電話番号の欄は入力されていない可能性も考慮した方が良さそうです。私がプライベートで利用しているアカウントには、携帯電話番号は登録していませんでした。もし、スキル側で携帯電話番号が必須の場合、ここまでの手順をユーザーに示して、登録いただく配慮が必要と思われます。

また、この携帯電話欄に入力するには、SMSの認証が必要です。したがって、SMSが受信できない端末の番号は登録できません。

スキルに対する許可

Alexaスキルで情報を取得するには、Alexaを利用するエンドユーザーが、スキルに対して情報取得の許可をする必要があります。その手順を確認しましょう。

  1. Alexaアプリで、メニューの [スキル] → [有効なスキル] から、許可したいスキルを表示します。

スキルの詳細画面

[このスキルは以下のアクセス権を必要としています。] の部分に、スキルが要求する情報が列挙されています。今回のサンプルスキルでは、以下のように書かれています。

  • 氏名
  • 携帯電話番号
  • Eメールアドレス
  1. [設定] ボタンをクリックします。

情報を許可していないスキルの設定画面

[以下のアクセス権を許可しました。]の後に、氏名や携帯電話番号などが並んでいますが、それぞれ「×」が付いています。これは許可していない状態です。許可するには、[アクセス権限の管理] ボタンをクリックします。

アクセス許可のダイアログ

[以下をリクエストしています] として、スキルが共有する情報が列挙されますので、それぞれラジオボタンをオンにして許可しています。最後に [権限を保存] ボタンをクリックします。

先ほどのスキルの設定画面に戻ると、アクセス権限を許可した情報にはチェックマークが付いています。

情報を許可したスキルの設定画面

これで、エンドユーザーによる、スキルに対する情報取得の許可が終わりました。

スキルのコード

ここまでの状況を前提に、スキル側で情報を取得していきます。

今回の "Customer Profile API" に関しては、詳細なドキュメントがすでに提供されていますが、情報の取得に関してはREST APIで説明されています。

これは有益な情報ですが、実装にはハードルがありますので、ASK SDK v2 for Node.jsを調査したところ、より簡単に情報を得る方法がありました。

分野としては、これは Alexa Service Client という仕組みを使います。これは今まで、端末の所在地情報を取得するためなどに利用してきました。今回も、この記事を参考に進めていきます。

情報の取得

説明の都合上、まず情報の取得から説明します。

ユーザー情報の取得には、serviceClientFactorygetUpsServiceClient()を呼び出します。

その後、serviceClientに対して、必要な情報を取得するメソッドを呼び出します。次の表は、取得する情報と対応するメソッドの関係です。

取得する情報 対応メソッド 備考
氏名 getProfileName()
Eメールアドレス getProfileEmail()
携帯電話番号 getProfileMobileNumber() 戻り値はJSON

単純に情報を取得するコード例は次の通りです(コード例は省略している箇所があります)。

      const upsServiceClient = serviceClientFactory.getUpsServiceClient();  // Clientの作成
      const userName = await upsServiceClient.getProfileName();            // 氏名の取得
      const email = await upsServiceClient.getProfileEmail();               // Eメールアドレスの取得
      const mobileNumber = await upsServiceClient.getProfileMobileNumber(); // 携帯電話番号の取得

氏名、Eメールアドレスは文字列として取得できますが、携帯電話番号は以下のようなJSON形式になっています。

{
    "countryCode": "81",
    "phoneNumber": "120123456"
}

phoneNumber については、先頭の0が抜けた番号になっていますので、利用の際には0を補う必要があると思われます。

情報取得のパーミッションの確認

端末の所在地情報と異なり、スキルに対してエンドユーザーがユーザー情報の取得を許可しているかどうかは、Tokenなどでは判断できないそうです。

The apiAccessToken is included in all requests to your skill, regardless of whether the user granted your skill the permissions needed to fulfill the request. Therefore, the token may not contain the right set of permissions for your skill to fulfill the request. Your skill can display a special permissions card to ask customers for consent dynamically.

そのため、情報取得許可があるかどうかの事前の確認処理をはさまずに情報取得のメソッドを呼び出し、その例外処理で情報の許可を求めるカードを出す形になります。例外処理を含めた処理全体は次のようになります(コード例は省略している箇所があります)。

const Alexa = require('ask-sdk-core');

const LaunchRequestHandler = {
  canHandle(handlerInput) {
    return handlerInput.requestEnvelope.request.type === 'LaunchRequest';
  },
  async handle(handlerInput) {

    const PERMISSIONS = [
      'alexa::profile:name:read',
      'alexa::profile:mobile_number:read',
      'alexa::profile:email:read'
    ];

    const { responseBuilder, serviceClientFactory } = handlerInput;

    try {
      const upsServiceClient = serviceClientFactory.getUpsServiceClient();  // Clientの作成
      const userName = await upsServiceClient.getProfileName();            // 氏名の取得
      const email = await upsServiceClient.getProfileEmail();               // Eメールアドレスの取得
      const mobileNumber = await upsServiceClient.getProfileMobileNumber(); // 携帯電話番号の取得
     
      const speechText = '氏名: ' + userName + ',メールアドレス: ' + email + ',携帯電話番号: ' + mobileNumber.phoneNumber;

      return handlerInput.responseBuilder
      .speak(speechText)
      .getResponse();
    } catch (error) {
      if (error.name == 'ServiceError') {
        console.log('ERROR StatusCode:' + error.statusCode + ' ' + error.message);
      }
      return responseBuilder
        .speak('連絡先の利用が許可されていません。アレクサアプリの設定を変更して下さい。')
        .withAskForPermissionsConsentCard(PERMISSIONS)
        .getResponse();
    }
  },
};

const skillBuilder = Alexa.SkillBuilders.custom();

exports.handler = skillBuilder
  .addRequestHandlers(
    LaunchRequestHandler
  )
  .withApiClient(new Alexa.DefaultApiClient())
  .lambda();

例外処理で呼び出しているwithAskForPermissionsConsentCard()は、引数の権限の付与をユーザーに求めるカードをAlexaアプリに表示します。次は、カードの表示例です。

Alexaアプリで、情報取得権限の付与を求めるカードの表示例

このカードの [権限の管理] の部分をクリックすると、スキルの詳細画面に移動します。

2018年8月24日 追記

ブログの記載内容についてお問い合わせをいただき、上記「例外処理を含めた処理全体」のコードを修正しました。 このコード例を利用される場合には、以下の点をご確認ください。

  1. スキルをASK SDK v2 for Node.js を使って開発していること(package.jsonには"ask-sdk-core": "^2.0.0""ask-sdk-model": "^1.0.0"の記述で確認しました)
  2. AWS LambdaのランタイムはNode.js 8.10であること
  3. 上記コード例にもありますが、Skillインスタンス.withApiClient(new Alexa.DefaultApiClient()) をコールしていること
  4. 上記コード例にもありますが、handle()関数をasyncで呼んでいること
  5. ドキュメントにあるように、取得された電話番号の文字列にはバリエーションがあり得ること

まとめ

従来、アカウントリンクでなければ取得できなかった情報の一部が、Amazon.co.jpのアカウントから取得可能になったAPIと、そのSDKからの呼び出し方についてご紹介しました。スキルに対するユーザーの許可があれば、ユーザーの提供なしに情報が利用できるため、スキルを利用するハードルを下げるものとして期待できると思われます。