あなたのClovaスキルは友だち追加されているのか？

# この記事で言いたいこと

ClovaスキルとBotの連携の落とし穴についてです。
***Clovaに「LINEにメッセージを送りました」なんて言わせないで！***
***友だち追加していない人にClovaが友だち追加を勧めるの、ありじゃない？(友だち追加して〜って言わせる）***
っていうお話です。
つまり、あなたのClovaスキルと連携しているBotが友だち追加されているのかを確認する必要性を話します。
ついでに追加されているかの確認の方法も説明します。
確認方法は２つ

* プッシュメッセージを送る時。
* プロフィールを取得する時

です。それではなぜ僕が友だち追加を確認する必要があると感じたかの話からさせてください。

# ことのはじめ

ある日私はボイスシンガーというClovaスキルとBotを作成していました。
ざっくりどういうサービスかというと、シンガーソングライターさんの歌をランダムで流して曲の詳細をBotの方に通知するようなサービスです。
これ以上の説明は蛇足なので、詳しくは省きます。
気になる方は以下のツイートをご覧ください。

<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">【拡散希望】<br>多くのシンガーさんを「知るきっかけ」を作っています！<br><br>曲を数秒聞いて「いいね！」と思ったら歌とシンガーさんのTwitterのプロフィールなどを見れるアプリです！<br><br>もし、僕の、私の曲使っても良いよ！ってシンガーさんがいましたらリプかDMください！🙇<br><br>沢山のシンガーさんに届け！ <a href="https://t.co/a8KtWcb2tQ">pic.twitter.com/a8KtWcb2tQ</a></p>&mdash; imajo (@imasirooo) <a href="https://twitter.com/imasirooo/status/1030077141625401345?ref_src=twsrc%5Etfw">2018年8月16日</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

重要なのはスキル内で「LINEへ歌の詳細を送りました」と***必ず***言わせていたことです。
お分かりかと思いますが、この仕様はクソです。
何がクソかと言うと、Botを友だち追加していない人にも「LINEへ歌の詳細を送りました」と言ってしまうからです。
ユーザー側としては友だち追加しないと通知が来ないなんて知らずにLINEを開き、「何も来てないじゃん！」となってしまいます。
しかし、そんなことを考えていなかった僕はそのまま公開申請をしてしまいました。（LINEさんごめんなさい）

こんなこと言われなくてもそんな仕様にしねえわ！！って方、長々とごめんなさい、、、笑

# なぜ必要か？

そもそもなんで「LINEに送ったよ」って言わないといけないのでしょうか。
別に言う必要なくない？と言われればそこまでですし、毎回言う必要もないとは思っています。
しかし、Clovaの良さはBotとの連携ですし、どんな発話をしたらどのタイミングでメッセージが届のか、ユーザーに伝えたかったからです。（サービスの内容的にも）

まあ、状況は色々考えられますが友だち追加されているかを確認したい場合（したほうがいい場合）は多々あるかと思います。

# リジェクトされる

申請後、案の定見事にリジェクトされました。
友だち追加されていないのに「LINEに送りました〜」ってくるよ？おかしくない？って、、、
いや、そもそもそんなんどうやってわかるんやろ〜って思ってたんですが、なんとなくやり方がわかりました。

ってことで以下の仕様に変更しました。

```js
if(友だち追加されている時){
  const msg = "LINEに通知を送ったよ〜"
}
else{
  const msg = "LINEに通知を送ろうとしたけど、友だち追加されていないから遅れなかったよ〜"
    + "スキルストアから友だち追加してね〜"
}
```

# コード（プッシュ通知）

実装していきたいと思います。
まずはプッシュ通知を送る時に友だち追加されているかを判断します。
大体はこのパターンかと思います。

Botへの通知で公式SDKを使用します。
プッシュ通知の仕様として、`client.pushMessage`でメッセージ送った時に友だち追加されていなかったらエラーを吐きます。
しかし、ほかのエラーの可能性もあります。アクセストークンが間違っているなどです。
`catch`でエラーを拾ってあげて、`err.originalError.response.data.message`でエラーの内容を判断します。

エラーの内容は以下になります。

```
'The property, \'to\', in the request body is invalid (line: -, column: -)'
```


以下コード

```js
const line = require('@line/bot-sdk');
const channelAccessToken = "MessagingAPIのアクセストークン"
const userId = "userId"

const client = new line.Client({
  channelAccessToken: channelAccessToken
});

const message = {
  type: 'text',
  text: 'Hello World!'
};

client.pushMessage(userId, message)
  .then((data) => {
    console.log(data.body);
  })
  .catch((err) => {
    // 友だち追加されていない時のエラー
    if(err.originalError.response.data.message === 'The property, \'to\', in the request body is invalid (line: -, column: -)'){
      console.log("友だち追加されていない時のエラー");
      const msg = "LINEに通知を送ったよ〜"
    }
    // そのほかのエラー
    else{
      console.log("そのほかのエラー");
      const msg = "LINEに通知を送ろうとしたけど、友だち追加されていないから遅れなかったよ〜"
        + "スキルストアから友だち追加してね〜"
    }
  });
```

# コード（ユーザー情報取得）

さて、次はプッシュ通知を送る時以外の確認方法です。
シーンとしては、スキル起動時（LaunchRequest)で追加していない人には「追加して〜」って言わせたりするかと思います。
こちらはBotのSDKを使わずに手動(request-promise)でGETして確認しています。
やり方は大体同じで、追加されていない場合はエラーを吐きます。
エラーのメッセージ内容から友だち追加されていないエラーかどうかを判断します。

エラー内容は

```
{"message":"Not found"}
```

コードは、、、

```js
const rp = require('request-promise');
const channelAccessToken = "MessagingAPIのアクセストークン"
const userId = "userId"

var options = {
  method: 'GET',
  uri: 'https://api.line.me/v2/bot/profile/' + userId,
  headers: {
    "Authorization": "Bearer {" + channelAccessToken + "}"
  }
};

rp(options)
  .then( async (data) => {
    // 友だち追加されているとき
    console.log(data);
  })
  .catch( err => {

    console.log(err.response.body);

    // 友だち追加していない場合
    if(err.response.body === '{"message":"Not found"}'){
      console.log("友だち追加されていない時のエラー");
    }
    // そのほかのエラー
    else{
      console.log("そのほかのエラー");
    }
  });
```

# 最後に

実際にBot連携を主としたスキルを公開してわかったことは、意外とBotを友だち追加してくれない人が多いいです。
いかにしてClovaから追加してもらうかなど、難しいですが奥が深いと感じましたVUI。Clova。