AlexaとLINEをアカウントリンクしてAlexaスキルにLINEメッセージ送信機能を実装する

AlexaスキルからLINEメッセージを送れたら面白いなと思って調べながら試行錯誤してたら、できました。

#仕組み
仕組みを図で表現すると、ざっくり以下のような感じです。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/354808/c79da7f2-63e0-066d-df82-6198070087ba.png)

#やること
大まかには、以下の感じで実現できました。

**開発側で準備すること**
　１．LINEのプロバイダ&チャネル作成
　２．Alexa開発者コンソールでアカウントリンクを設定
　３．lambdaでのコーディング

**ユーザーがやること**
　１．アカウントリンクの実施・Messaging APIチャネル(LINE Bot)を友だちに追加
　２．Alexaスキル呼び出し

以下、各ステップを簡単に説明していきます。

# １．開発側で準備すること

## １．１．LINEのプロバイダ&チャネル作成
[LINE Developers](https://developers.line.me/ja) のページでプロバイダとチャネルを作成してください。

チャネルは２個作成します。
　・通知送信用のMessaging APIチャネル(LINE Bot)
　・アカウントリンク用のLINEログインチャネル

プロバイダ、チャネル作成は以下の公式リファレンスをみて進めてください。
[Messaging APIを利用するには](https://developers.line.biz/ja/docs/messaging-api/getting-started/)
[LINEログインを利用するには](https://developers.line.biz/ja/docs/line-login/getting-started/)

### 通知送信用のMessaging APIチャネル(LINE Bot)
Messaging APIチャネルを作成する際に気を付けるべき点は以下です。
・プランは"Developer Trial"にする(PUSH_MESSAGEを利用可能にしたいため)
・アクセストークンを発行し控えておく(→lambdaソースで利用するため。失効までの時間を0時間にしておけばずっと有効にできる)

### アカウントリンク用のLINEログインチャネル
LINEログインチャネルを作成する際、気を付けるべき点は以下です。
・アプリタイプは"WEB"にする
・"このチャネルにリンクされたボット"で、Messaging APIチャネルを指定する
・作成したチャネルで、チャネルIDとシークレットを控えておく(→Alexa開発者コンソールで利用する)
・アプリ設定タブのCallback URLに、後述するAlexa開発者コンソールのアカウントリンク画面下部にある"リダイレクト先のURL"を貼り付ける

![image.png](https://qiita-image-store.s3.amazonaws.com/0/354808/d2ae2f55-0f86-76a9-46bf-9485a22773c1.png)
上のキャプチャは、アプリタイプをWEBで作成し、Messaging APIチャネルをリンクした様子です。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/354808/d46e3b8b-13d2-5d1a-56b0-92fb73fd5bfa.png)
こちらは、アプリ設定のCallback URLにAlexa開発者コンソールのリダイレクトURLを貼り付けたところです。


そんな感じで2個チャネルを作成しました。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/354808/63c93929-21ce-4dc1-177f-c6c6d2c9c67a.png)
(※LINEログインチャネルを非公開にしていますが、状況に応じて公開にする必要あり)

## １．２．Alexa開発者コンソールでアカウントリンクを設定
つぎにAlexaスキル側を準備します。
Alexa開発者コンソールで、LINE連携したいカスタムスキルの編集画面でアカウントリンクの設定をします。


スキルビルド画面左側の"アカウントリンク"をクリックしてアカウントリンク設定画面に遷移し、アカウントリンクを有効にして以下の通り設定します。
認証画面のURIにbot_promptパラメータを付与しているのがミソです。
これを入れることで、アカウントリンク時にMessaging APIチャネルの友だち追加画面を挟むことができます。

|項目|値|
|---|---|
|認証画面のURI|https://access.line.me/oauth2/v2.1/authorize?bot_prompt=aggressive|
|アクセストークンのURI|https://api.line.me/oauth2/v2.1/token|
|クライアント ID|(LINEログインチャネルのチャネルID)|
|クライアントシークレット|(LINEログインチャネルのシークレット)|
|クライアントの認可方法|HTTP Basic認証(推奨)|
|スコープ|profile|
|ドメインリスト|(空)|
|デフォルトのアクセストークンの有効期限|(空)|

## １．３．lambdaでのコーディング
カスタムスキルのlambdaソースは、以下のようにコーディングします。
※一部抜粋
※package.jsonも適当に修正してください

``` node.js
'use strict';
const Alexa = require('ask-sdk');
const request = require('request');
const LINE_API_BASE_URL = 'https://api.line.me/v2';

// LINE Messaging APIのチャネル設定で発行したアクセストークン
const MESSAGING_API_ACCESSTOKEN = '【ここにMessaging APIチャネルで生成したアクセストークンを記載する】';

// スキル起動
const LaunchRequestHandler = {
    canHandle(handlerInput) {
        return handlerInput.requestEnvelope.request.type === 'LaunchRequest';
    },
    async handle(handlerInput) {
        const lineMessage = "Alexaからのメッセージです！";
        const speechText = 'LINEアカウントにメッセージを送信しました！';
        // チャネルへのアクセストークン取得
        const profileAccessToken = handlerInput.requestEnvelope.session.user.accessToken;
      
        // ソーシャルAPIでユーザープロフィール情報を取得
        var resBody = await getProfile(profileAccessToken);

        // プロフィール情報からuserIdを取得
        const userId = resBody.userId; 
        
        // プッシュ通知を送信
        resBody = await push(userId,lineMessage);

        return handlerInput.responseBuilder
            .speak(speechText)
            .reprompt(speechText)
            .getResponse();
    }
};

// LINEユーザー情報を取得する
function getProfile(profileAccessToken){
    var options = {
        url: LINE_API_BASE_URL + '/profile',
        headers: {
            'Authorization': 'Bearer ' + profileAccessToken
        },
        json: true,
    };
    
    // GETでリクエスト送信
    return new Promise(function(resolve, reject){
        request.get(options, function(err, res, body) {
            if (err) {
                reject(body);
                return;
            }
            resolve(body);
        });
    });
}

// Messaging APIチャネルからpushメッセージを送信する
async function push(to,message){
    // メッセージオブジェクトを生成
    var objMessage = {
        type:"text",
        text:message
    };
    // body生成(messagesは配列で最大5件まで同時に送信できるが、今回は1件だけ送信する)
    var body = {
        to: to,
        messages: [objMessage]
    };
    var options = {
        url: LINE_API_BASE_URL + '/bot/message/push',
        headers: {
            'Content-type': 'application/json; charset=UTF-8',
            'Authorization': 'Bearer ' + MESSAGING_API_ACCESSTOKEN
        },
        json: true,
        body: body
    };
    
    // POSTでリクエスト送信
    return new Promise(function(resolve, reject){
        request.post(options, function(err, res, body) {
            if (err) {
                reject(body);
                return;
            }
            resolve(body);
        });
    });
}

// 以下、省略。。。
```
ここまでできたら開発側の準備は完了です。

# ２．ユーザーがやること
## ２．１．アカウントリンクの実施・Messaging APIチャネル(LINE Bot)を友だちに追加
Alexaのユーザーページから、作成したスキルのアカウントリンクを実施してください。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/354808/4832a42f-61ba-738a-c98d-a22316d34052.png)
"有効にする"ボタン押下でLINEログイン画面(作成したLINEログインチャネル)に遷移します。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/354808/8d04ec5f-9b8d-d523-ec87-4b4b3fc64bc9.png)
ログインすると、権限利用の許可を求められる画面に遷移しますので、"許可する"を押下します。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/354808/60cb2ad7-71b5-d63c-73ac-9f3341092c18.png)
許可すると、作成したMessaging APIチャネルを友だちに追加する画面に遷移します。
私はこのチャネルを以前友だち追加していて今はブロック状態のため"ブロック解除"になってますが、初めての場合"友だち追加"とかになっているはずです。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/354808/f7cede1e-fcd6-fabd-f39c-620752cfbe95.png)

チャネルを友だち追加してアカウントリンクは完了です。アカウントリンク完了画面に遷移します。
("LINE連携"はスキル名です)
![image.png](https://qiita-image-store.s3.amazonaws.com/0/354808/283f9488-ce8b-d98d-8080-1c01d8ceae35.png)

## ２．２．Alexaスキル呼び出し
アカウントリンク後、スキルを実行してみます。

Echoの方の挙動は以下の感じ。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/354808/105b7d86-885d-42d4-cd16-c1264bce3750.png)

LINEをみてみると…
![image.png](https://qiita-image-store.s3.amazonaws.com/0/354808/4658cfce-8f75-6df6-d135-da4abf782dec.png)
通知が届いています！
(上の絵文字交じりのメッセージは友だち追加時に自動送信されるものです)

# 注意点
LINEのMessaging APIチャネルは、無料枠(Developer Trial)だと友達上限が50人のため、必然的にAlexaスキルの利用者上限も50人となってしまいます。
回避するには、以下のような工夫が必要そうです(思いついたもの列挙しただけです)。
　・有料版を利用する
　・チャネルを複数作る
　・先着50名とそれ以降の人で機能に差をつける

参考：[LINE@ プラン・料金](https://at.line.me/jp/plan)

また、上記のlambdaソースは正常系しかカバーしていません。
ざっと思いつくだけでも以下の考慮が必要になるかと思います。
　・アカウントリンクしないままスキルを実行した場合
　・アカウントリンクはしたがMessaging APIチャネルを友だち追加せずにスキル実行した場合
　・API連携に失敗した場合



# 最後に
以上でAlexaスキルからLINEメッセージ送信を実装することができました。
AlexaとLINE Botをうまく連携すればスキル開発の可能性が広がりそうです。

最後の最後に…
結構がんばって書いたんですが、先人がいました…
[AlexaからLINE Botに通知してみる(ASK+Messaging API+LINEログイン+Social API)](https://qiita.com/imajoriri/items/0e975b15b9023cafce24)

私の記事との差はアカウントリンク時の認証画面のURIにパラメータ付与があるかどうか(→アカウントリンク後に友だち追加画面を挟むかどうか)くらいです。

# 参考URL
[[Alexa] LINEログインでAccount Linkingしてみた](https://dev.classmethod.jp/cloud/alexa-account-linking-line-login/)
[LINE Messaging API を使ってLINEにメッセージ送信／メッセージ返信する](https://qiita.com/fkooo/items/d07a7b717e120e661093)
[LINE Login 超入門](https://qiita.com/nkjm/items/c8eac296dfee14fe5cf7)
[ユーザープロフィールを取得する (LINE Developers)](https://developers.line.biz/ja/docs/social-api/getting-user-profiles/)
[Messaging APIリファレンス (LINE Developers)]
(https://developers.line.biz/ja/reference/messaging-api/)