React Nativeで顔認証とか指紋認証をやる

# はじめに

管理職になって、もうコード書くことが減ってきて今年はおすすめコンポーネントやれるほどナレッジが蓄積しませんでした・・・・。
やっぱコード書くのが一番蓄積する・・・・！！

代わりに、面白そうなライブラリをみつけました。
使ってみる機会がなかったのでこれを機に使ってみようって感じでやってみた　＋　仕様解説です〜！！
思ったより簡単すぎて書くことなくて、焦ったぐらい良いライブラリでした！

# 顔認証について

昨年の９月にiPhoneXが発売されて以来、faceIdに対応しているアプリが多くありますね。
身近なところだとmobile suicaや楽天カードといったアプリも顔認証が実装されています。

ステマではないですが、僕が愛してやまない神ブラウザ[Smooz](https://itunes.apple.com/jp/app/smooz-%E3%82%B9%E3%83%A0%E3%83%BC%E3%82%BA-%E3%83%96%E3%83%A9%E3%82%A6%E3%82%B6/id1151364449?mt=8)にもとうとう顔認証、指紋認証が実装されました！！
Smoozについては、ほんと意味もなく人に薦めまくっているぐらい良いブラウザなので、ぜひ使ってみてください！

僕は昔、変な調べ物をしててそれを会議中に出してしまったという失態を犯したことがあります。
ですが、これで変な調べ物をしても大丈夫ですね！笑

# React Nativeでできるのか

そしてそんな顔認証（指紋認証）をReact Nativeでも実装できるのです！
それがこちらのライブラリ

[react-native-touch-id](https://github.com/naoufal/react-native-touch-id)

早速入れて動かすところまでやってみます。

# 実装

```
react-native init faceId
cd faceId
yarn add react-native-touch-id
react-native link
```

いつも通りの呪文です。

## FaceID

plistを少し弄る必要があります。
直接plistをいじってもいいですし、XCodeで追記しても良いです！
僕はいつもXCodeで弄るのでXCodeからいじってみます。

<img width="1151" alt="スクリーンショット 2018-12-16 2.25.20.png" src="https://qiita-image-store.s3.amazonaws.com/0/121851/15ae42af-040d-d065-e4dd-b6cc9b494b76.png">

こんな感じで、`NSFaceIDUsageDescription`をplistに追加します。この時、descriptionも書いておきましょう！

### emulatorで動かす前に
emulatorでFaceIdを使うためにはちょっと設定を変える必要があります。

<img width="418" alt="スクリーンショット 2018-12-16 2.48.12.png" src="https://qiita-image-store.s3.amazonaws.com/0/121851/398cfb66-36cc-7733-f8ca-b79e2ca3eb96.png">

このEnrolledにチェックを入れてください。

### 実装

```jsx
/**
 * Sample React Native App
 * https://github.com/facebook/react-native
 *
 * @format
 * @flow
 */

import React, {Component} from 'react';
import {Platform, StyleSheet, Text, View} from 'react-native';
import TouchID from 'react-native-touch-id';

const instructions = Platform.select({
  ios: 'Press Cmd+R to reload,\n' + 'Cmd+D or shake for dev menu',
  android:
    'Double tap R on your keyboard to reload,\n' +
    'Shake or press menu button for dev menu',
});

type Props = {};
export default class App extends Component<Props> {
  componentDidMount() {
    TouchID.authenticate('試しに認証してみます')
      .then(success => {
        console.log({ success });
      })
      .catch(error => {
        console.log({ error });
      });
  }

  render() {
    return (
      <View style={styles.container}>
        <Text style={styles.welcome}>Welcome to React Native!</Text>
        <Text style={styles.instructions}>To get started, edit App.js</Text>
        <Text style={styles.instructions}>{instructions}</Text>
      </View>
    );
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    backgroundColor: '#F5FCFF',
  },
  welcome: {
    fontSize: 20,
    textAlign: 'center',
    margin: 10,
  },
  instructions: {
    textAlign: 'center',
    color: '#333333',
    marginBottom: 5,
  },
});

```

できたてのApp.jsに変更を加えます。CDMのところで認証をはさんでみました。

<img width="398" alt="スクリーンショット 2018-12-16 2.47.52.png" src="https://qiita-image-store.s3.amazonaws.com/0/121851/979330a2-cd1f-eac7-2fb5-98aec13d929f.png">

すると先ほどの文言がちゃんとでてパーミッション確認できましたね！
めっちゃ楽。

そしてOKを押すと・・・・。

<img width="394" alt="スクリーンショット 2018-12-16 2.53.19.png" src="https://qiita-image-store.s3.amazonaws.com/0/121851/9ebb3849-5d3f-e0ab-1ca2-7553abba27ff.png">

でました！。
当然ながらエミュだとどんなに凝視しても開かないので、hardwareから認証させてあげます。

<img width="407" alt="スクリーンショット 2018-12-16 2.54.25.png" src="https://qiita-image-store.s3.amazonaws.com/0/121851/0f505eb4-960b-710a-a5d1-3b7ba248f0f5.png">

はい！認証通った！！

<img width="783" alt="スクリーンショット 2018-12-16 2.55.54.png" src="https://qiita-image-store.s3.amazonaws.com/0/121851/170013fa-c34b-34dd-e5a2-cba62c4ce3f4.png">

これで終わっちゃうとすっごい中身ない記事になるのでちゃんと細かな説明を書きます！

###　インターフェース

```
authenticate(reason, config)
```

みたいですね。
configには以下のプロパティを使えますがAndroid入れるとめっちゃ多くなるので一旦iOSの部分について。

```
iOS
passcodeFallback - iOS - default:false faceId touchId使えない時にパスコードを入れさせるか否か
fallbackLabel - iOS - default: Enter Password 認証に失敗した時にラベルをどう出すか
```

ちょっと内容を変えてみます。

```jsx
  componentDidMount() {
    TouchID.authenticate('試しに認証してみます', {
      fallbackLabel: '諦める',
      passcodeFallback: true,
    })
      .then(success => {
        console.log({ success });
      })
      .catch(error => {
        console.log({ error });
      });
  }
```

### passcodeFallback
一旦HardwareのFaceId enrolledを外します。

<img width="399" alt="スクリーンショット 2018-12-16 3.13.05.png" src="https://qiita-image-store.s3.amazonaws.com/0/121851/7da3fb05-8be3-f64e-8a44-6ec063c52195.png">

すると

<img width="388" alt="スクリーンショット 2018-12-16 3.13.45.png" src="https://qiita-image-store.s3.amazonaws.com/0/121851/c1242c98-e2d2-0c72-871b-58c4347de096.png">

reasonに入れた内容が出てきましたね！
そして紛らわしいですが・・・・、faceidというのはこのアプリケーションの名前です・・・。
へんな名前つけたのでみすりました・・・。
ただ、他のアプリケーションをみていると、パスコードなどについては、独自UIで入れてたり、各社のアイパスつかってやってるのがほとんどなのであんまり使い道はないかもですね・・・。

### fallbackLabel
認証に失敗してみます。
すると、

<img width="384" alt="スクリーンショット 2018-12-18 13.05.01.png" src="https://qiita-image-store.s3.amazonaws.com/0/121851/bb653320-6e37-f6f4-f563-af65573fc91b.png">


このように出てきます。

## TouchID

TouchIDの時も同じ仕組みでできます。
こっちをやる場合はとりわけplistへパーミッションを追加する必要がないので、いきなりreasonにいれた内容が出てきます。

<img width="393" alt="スクリーンショット 2018-12-18 12.32.07.png" src="https://qiita-image-store.s3.amazonaws.com/0/121851/ac218102-e5fd-35ff-2bd4-ac9cc4bc508b.png">

FallbackLabelもしっかりとでますね！

<img width="409" alt="スクリーンショット 2018-12-18 12.55.21.png" src="https://qiita-image-store.s3.amazonaws.com/0/121851/dd7aaf9b-9472-91ab-8fcf-98d2f420a6c6.png">

## エラーハンドリング

```jsx
  componentDidMount() {
    TouchID.authenticate('試しに認証してみます', {
      fallbackLabel: '諦める',
      passcodeFallback: true,
    })
      .then(success => {
        console.log({ success });
      })
      .catch(error => {
        console.log({ error });
      });
  }
```

といった具合に、エラーの際はcatch節に処理が移行します。
その時のerrorは型が

```
name: string;
message: string;
details: {
 name: string;
 message: string;
}
```

という型になっています。
この時nameが重要で、

|name|description|
|:------|:--------|
|LAErrorAuthenticationFailed| 認証に失敗した|
|LAErrorUserCancel| cancelが押された|
|LAErrorUserFallback| fallbackボタンが押された。|
|LAErrorSystemCancel | 認証のためのポップアップが出ている間に、他のアプリケーションがフォアグラウンドにくるなど、認証がシステムによって中断された。 |
|LAErrorPasscodeNotSet | パスコードが設定されていないため、認証ができなかった |
|LAErrorTouchIDNotAvailable|TouchIDが利用不可能 |
|LAErrorTouchIDNotEnrolled | TouchIDが許可されていない |
|RCTTouchIDUnknownError | よくわからない理由によって認証が不可能だった |
|RCTTouchIDNotSupported| TouchIDがサポートされていない |

といった感じになっています！

## サポート状態確認

isSupportedというメソッドも用意されています。
こちらを使うことによってサポート状況を確認できます。


```jsx
  componentDidMount() {
    TouchID.isSupported()
      .then(success => {
        console.log({ success });
      })
      .catch(error => {
        console.log({ error });
      });
  }
```

![スクリーンショット 2018-12-18 13.18.23.png](https://qiita-image-store.s3.amazonaws.com/0/121851/8db38d02-3b77-844d-f97e-123a9d86a0f9.png)

こういった感じでサポート状況が帰ってきます。

### iPhoneX

![スクリーンショット 2018-12-18 13.18.23.png](https://qiita-image-store.s3.amazonaws.com/0/121851/58a20984-0232-2abf-95a0-772033ef955b.png)

FaceIDに対応しているためFaceIDという文字列が返ります。

### iPhone7

![スクリーンショット 2018-12-18 13.22.27.png](https://qiita-image-store.s3.amazonaws.com/0/121851/78b4481f-2612-c3ef-98e5-a1219d1d8773.png)

TouchIDに対応しているためTouchIDという文字列が返ります。

## Android

AndroidManifest.xmlに`<uses-permission android:name="android.permission.USE_FINGERPRINT" />`を追加します。

```:AndroidManifest.xml
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
    <uses-permission android:name="android.permission.USE_FINGERPRINT" />
```

こんな感じで追加します。

## Emulatorでの許可

設定 > セキュリティ
で指紋認証を有効にしましょう。エミュレーターから指紋を認証させることができます。

<img width="819" alt="スクリーンショット 2018-12-18 14.02.42.png" src="https://qiita-image-store.s3.amazonaws.com/0/121851/5b11b604-a7df-7c4c-2d67-1a2abe194ac2.png">


しっかりとでますね！

<img width="338" alt="スクリーンショット 2018-12-18 14.03.56.png" src="https://qiita-image-store.s3.amazonaws.com/0/121851/15a04eec-39b7-5830-3cc9-d008cbdf620e.png">

認証もバッチリ通ります。

![スクリーンショット 2018-12-18 14.04.26.png](https://qiita-image-store.s3.amazonaws.com/0/121851/8977ee41-3218-5e3d-d74c-d253026dc1ea.png)

プロパティも多くこんな感じで、色々と変更することができます。

```
  componentDidMount() {
    TouchID.authenticate('test',{
      title: 'Androidだよ',
      imageColor: '#008080',
      imageErrorColor: 'yellow',
      sensorDescription: '押せ！',
      sensorErrorDescription: '失敗しとるやないかい！',
      cancelText: 'もうええわ'
    })
      .then(success => {
        console.log({ success });
      })
      .catch(error => {
        console.log({ error });
      });
  }
```

<img width="332" alt="スクリーンショット 2018-12-18 14.09.36.png" src="https://qiita-image-store.s3.amazonaws.com/0/121851/eb026957-d85a-a617-c342-a58e3c1300e6.png">

しっぱいするとこんな感じに・・・！！

<img width="325" alt="スクリーンショット 2018-12-18 14.10.51.png" src="https://qiita-image-store.s3.amazonaws.com/0/121851/09a06a89-f6fd-40c8-9600-73b924c4c1ca.png">


## おわりに

おもったより簡単すぎて書くのが逆にたいへんでした・・・・。
とはいえめっちゃいいライブラリだと思うので認証のさいはぜひつかってみてくださいー！