JavaScript
Android
iOS
React
reactnative

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

はじめに

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

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

顔認証について

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

ステマではないですが、僕が愛してやまない神ブラウザSmoozにもとうとう顔認証、指紋認証が実装されました!!
Smoozについては、ほんと意味もなく人に薦めまくっているぐらい良いブラウザなので、ぜひ使ってみてください!

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

React Nativeでできるのか

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

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からいじってみます。

スクリーンショット 2018-12-16 2.25.20.png

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

emulatorで動かす前に

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

スクリーンショット 2018-12-16 2.48.12.png

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

実装

/**
 * 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のところで認証をはさんでみました。

スクリーンショット 2018-12-16 2.47.52.png

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

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

スクリーンショット 2018-12-16 2.53.19.png

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

スクリーンショット 2018-12-16 2.54.25.png

はい!認証通った!!

スクリーンショット 2018-12-16 2.55.54.png

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

 インターフェース

authenticate(reason, config)

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

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

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

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

passcodeFallback

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

スクリーンショット 2018-12-16 3.13.05.png

すると

スクリーンショット 2018-12-16 3.13.45.png

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

fallbackLabel

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

スクリーンショット 2018-12-18 13.05.01.png

このように出てきます。

TouchID

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

スクリーンショット 2018-12-18 12.32.07.png

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

スクリーンショット 2018-12-18 12.55.21.png

エラーハンドリング

  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というメソッドも用意されています。
こちらを使うことによってサポート状況を確認できます。

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

スクリーンショット 2018-12-18 13.18.23.png

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

iPhoneX

スクリーンショット 2018-12-18 13.18.23.png

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

iPhone7

スクリーンショット 2018-12-18 13.22.27.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での許可

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

スクリーンショット 2018-12-18 14.02.42.png

しっかりとでますね!

スクリーンショット 2018-12-18 14.03.56.png

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

スクリーンショット 2018-12-18 14.04.26.png

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

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

スクリーンショット 2018-12-18 14.09.36.png

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

スクリーンショット 2018-12-18 14.10.51.png

おわりに

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