ReactでLIFF v2の機能を試してみる

# はじめに
この記事は弊社の[Advent Calender 2019](https://qiita.com/advent-calendar/2019/access)の１日目の記事です。今年のAdvent Calenderの旗振り役は私、@ufoo68が担当します！
たまには弊社に即した内容を書いてみようかなとか思うのですが、この前参加してきた[LINE DEVELOPER DAY](https://linedevday.linecorp.com/jp/2019/)でLIFF V2関係の記事を書いてみたかったので、またまたLINE記事を書くことにしました。

# LIFF v2で新しくなったこと
新機能についての詳しい資料は[公式のもの](https://speakerdeck.com/line_devday2019/whats-new-in-line-front-end-framework)があるのでそちらをメインに見てください。新機能としては以下のものが紹介されました。

- **scanQR**
  - QRコードリーダー
- **login/logout**
  - `isLoggedin`を使ってログイン状態を取得できる
- shareTargetPicker
  - 特定のユーザーにメッセージが送れる機能

あとは、詳細には触れませんでしたがこんなものも追加されたようです。

- getFriendship
- getDecodedIDToken
- getLanguage
- isInClient

とはいえ、まだ公開されてないAPIもあったり、用途が不明のものがあったりするみたいですね。今回は太字で書いた**login**と**QRコード**を試してみました。[他のAPIの詳しい情報はここ](https://engineering.linecorp.com/ja/blog/liff-v2/)にあります。
このAPI思ったより簡単だったのでこのあとの内容のボリュームがかなり少なくなってます。。。

# 実装してみた
やってみたことは以下です。

1. ログインボタンをつくる
2. LINEログインしたときだけQRスキャンを起動できる

Reactでの環境構築については[過去の記事](https://qiita.com/ufoo68/items/3e6ff0613ebd87a8edd9)を参照してください。
実装したコードは以下です。

```typescript:App.tsx
import React, { FC, useState, useEffect } from 'react';
import Button from '@material-ui/core/Button';
import './App.scss';

const liff = window.liff

const App: FC = () => {
  const [value, setValue] = useState<string>('')
  const [isLogin, setIsLogin] = useState<boolean>(false)

  useEffect(() => {
    liff.init({ liffId: process.env.REACT_APP_LIFF_ID as string }).then(() => {
      setIsLogin(liff.isLoggedIn())
    })
  }, [])

  const login = () => {
    liff.init({ liffId: process.env.REACT_APP_LIFF_ID as string }).then(() => {
      liff.login()
      setIsLogin(liff.isLoggedIn())
    })
  }

  const openQR = () => {
    liff.init({ liffId: process.env.REACT_APP_LIFF_ID as string }).then(() => {
      try {
        liff.scanCode()
          .then(result => setValue(result.value!))
          .catch(() => alert('cannot read QR'))
      } catch {
        alert('cannot open QR camera')
      }
    })
  }

  return (
    <div className="App">
      <div className="qrValue">{value}</div>
      <div className="loginButton">
        <Button variant="contained" color="primary" onClick={() => login()} disabled={isLogin}>
          Login
        </Button>
      </div>
      <div className="qrButton">
        <Button variant="contained" color="secondary" onClick={() => openQR()} disabled={!isLogin}>
          Open QR camera
      </Button>
      </div>
    </div>
  );
}

export default App;

```

ソースコードは[ここ](https://github.com/ufoo68/qr-test)で公開してます。

# 結果
どうも失敗に終わりました。。実装は悪くはなかったのですが、LIFF URL（line://appで始まるURL）はそもそも最初からログインした状態だったので、ログインボタンが何も意味をなさないという自体に。
また、このLIFF V2からは外部ブラウザからLIFFアプリを開くことができるようになったのですが、このQRコードスキャンのような特殊なAPIは使えないみたいなので、LINEログインは機能してもQRカメラが起動しないということに。
ちなみにURLは以下のような感じにすると、LINEがある人にはLINEアプリで、持ってない人は適当なブラウザが立ち上がるようになるみたいです。

```
https://liff.line.me/{liffid}
```

この`{liffid}`に`line://app/`以下で書かれてるやつを入れます。

そして読み取り結果ですが、以下のようなQRを読んでみて（内容は**"test"**と書かれたstring）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/209689/f87736a2-ed06-cdbc-780f-4966caac96e6.png)
こんな感じでの表示結果となりました。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/209689/aba4373c-cff9-9767-3714-d8bed27ab4c0.png" width=200px>
一応うまく読み取れました。しかしこのscanQRなのですが、`liff-type`の定義にまちがいがあったので自分で直しました。~~一応作者さんにPRを出しましたが、まだ反映されてない場合はこっちの方で`yarn add`してみてください。~~←マージされたようです。

```bash
yarn add -D https://github.com/ufoo68/liff-type.git
```

# さいごに
実はこのLIFFですが、どうやら今後はLINEログインチャネルのみをサポートして、MessagingAPIでのサポートをしなくしようとしている（すぐにではないが）ようです。[ここ](https://developers.line.biz/ja/docs/liff/getting-started/)に**「今後はMessagingAPIにLIFFを追加しないでくれ」**みたいなことが書いてあります。
これについてこの前のLINE DEVELOPER DAYでも議論したのですが、どうやら今後はこのLIFFをLINE botのサブアプリ的な立ち位置から、**LINEログイン機能などをサポートした１つのウェブアプリケーションへと独立**させようと思っているようですね（憶測かもしれませんが）。
また、今回は[liff-type](https://www.npmjs.com/package/liff-type)という非公式のnpmパッケージを使って開発しましたが、LINE公式でもLIFFのType用のnpmパッケージをそのうち公開してくれるみたいです。今後は公式の方もTypeScriptでの開発をサポートしてくれるようなのでかなり期待しております。

とまあ、完全にACCESSと関係ないLINE APIの記事になってしまいましたが、このAdvent Calenderの記事投稿のハードルを下げられたという意味では旗振り役としての役割を果たせたのではないかと思うので良しとしましょうw
ということで１日目の投稿はこんな感じで締めようと思います。次は@irisTa56さんの投稿です。お楽しみに！