はじめに

NativeScript で iOS の FaceID や TouchID、Android の指紋認証などの生体認証を利用する方法。

TL;DR

目次

  1. はじめに
  2. TL;DR
  3. 環境・条件
  4. 詳細
    1. セットアップ
      1. インストール
      2. Android の minSdkVersion 確認
      3. FaceID の利用理由 (iOS のみ)
    2. 実装
      1. 生体認証の 利用可否/種別 の確認
      2. 生体認証の変更有無の確認
      3. 生体認証(Fallback: パスコード)
      4. 生体認証(Fallback: カスタム) (iOS のみ)
    3. Tips
      1. メッセージの変更
  5. まとめ
  6. 参考文献

環境・条件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
$ sw_vers
ProductName: Mac OS X
ProductVersion: 10.15.3
BuildVersion: 19D76

$ node -v
v12.7.0

$ npm -v
6.10.3

$ tns --version
6.4.0

$ grep -C1 version package.json
"tns-ios": {
"version": "6.4.1"
},
"tns-android": {
"version": "6.4.1"
}

$ tns plugin
Dependencies:
┌───────────────────────────────┬─────────┐
│ Plugin │ Version │
│ @nativescript/theme │ ^2.2.1 │
│ @vue/devtools │ ^5.0.6 │
│ nativescript-barcodescanner │ ^3.4.1 │
│ nativescript-fingerprint-auth │ ^7.0.2 │
│ nativescript-plugin-firebase │ ^10.4.0 │
│ nativescript-socketio │ ^3.2.1 │
│ nativescript-toasty │ ^1.3.0 │
│ nativescript-vue │ ^2.4.0 │
│ nativescript-vue-devtools │ ^1.2.0 │
│ tns-core-modules │ ^6.0.0 │
│ vue-router │ ^3.1.5 │
└───────────────────────────────┴─────────┘
Dev Dependencies:
┌────────────────────────────────────┬─────────┐
│ Plugin │ Version │
│ @babel/core │ ^7.0.0 │
│ @babel/preset-env │ ^7.0.0 │
│ babel-loader │ ^8.0.2 │
│ nativescript-dev-webpack │ ^1.0.0 │
│ nativescript-vue-template-compiler │ ^2.0.0 │
│ nativescript-worker-loader │ ~0.9.0 │
│ node-sass │ ^4.9.2 │
│ vue-loader │ ^15.4.0 │
└────────────────────────────────────┴─────────┘
  • iPhone 11 Pro: iOS 13.3
  • Android HUAWEI nova lite 2: Android 9 (ビルド 9.1.0.160)

詳細

リポジトリ: 17number/nativescript-vue-tutorial

参考コミット(時系列順):

セットアップ

インストール

1
$ tns plugin add nativescript-fingerprint-auth

Android の minSdkVersion 確認

Installation には、「AndroidManifest.xmlminSdkVersion23 未満であれば編集」とあるが、minSdkeVersion の設定がなくてもビルド時にエラーとなったため、一律編集するほうが良いと思われる。

app/App_Resources/Android/src/main/AndroidManifest.xml を編集。

1
2
3
4
5
6
7
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
package="__PACKAGE__"
android:versionCode="10000"
android:versionName="1.0">
...
+ <uses-sdk tools:overrideLibrary="com.jesusm.kfingerprintmanager"/>

※自分の環境では <uses-sdk /> 自体がなかったので、必要な部分のみを追加している。定義されている場合は tools:overrideLibrary=".." のみを追加すれば良いと思われる。

FaceID の利用理由 (iOS のみ)

以下画像の赤枠部分を設定したい場合、app/App_Resources/iOS/Info.plist を編集
参考: Face ID (iOS) - EddyVerbruggen/nativescript-fingerprint-auth

1
2
3
4
5
6
7
8
 ...
<plist version="1.0">
<dict>
...
+ <key>NSFaceIDUsageDescription</key>
+ <string>FaceID 利用の詳細(理由など)</string>
</dict>
</plist>

実装

参考: Demo

nativescript-fingerprint-auth/demo にサンプルがあるので参考に実装すると良い。

ローカルでコード確認や、アプリ実行する場合は git clone する。

1
2
3
$ git clone https://github.com/EddyVerbruggen/nativescript-fingerprint-auth
$ cd nativescript-fingerprint-auth/src
$ npm run demo.android # or demo.ios

生体認証の 利用可否/種別 の確認

参考コード

available() で生体認証の利用可否や種別を取得。

1
2
3
import { FingerprintAuth } from "nativescript-fingerprint-auth";
const fingerprintAuth = new FingerprintAuth();
fingerprintAuth.available().then(result => console.log({result}));

iPhone 11 Pro

1
2
3
4
5
6
// result
{
"any": true,
"touch": false,
"face": true
}

Android HUAWEI nova lite 2 (背面に指紋認証センサーがある)

1
2
3
4
5
// result
{
"any": true,
"touch": true
}

生体認証の変更有無の確認

参考コード

didFingerprintDatabaseChange() で、生体認証に変更があったかを確認可能。

Since iOS9 it’s possible to check whether or not the list of enrolled fingerprints changed since the last time you checked it. It’s recommended you add this check so you can counter hacker attacks to your app. See this article for more details.
So instead of checking the fingerprint after available add another check. In case didFingerprintDatabaseChange returns true you probably want to re-authenticate your user before accepting valid fingerprints again.
https://github.com/EddyVerbruggen/nativescript-fingerprint-auth#security-ios より

以下は Google 翻訳。(書いてあることはなんとなく分かるが、具体的な利用シーンが思いつかないというのが正直なところ)

iOS9以降、登録した指紋のリストが最後にチェックしてから変更されたかどうかを確認することができます。 アプリへのハッカー攻撃に対抗できるように、このチェックを追加することをお勧めします。 詳細については、この記事を参照してください。
そのため、利用可能な後に指紋をチェックする代わりに、別のチェックを追加します。 didFingerprintDatabaseChangeがtrueを返す場合、おそらく有効な指紋を再度受け入れる前にユーザーを再認証する必要があります。

1
2
3
4
import { FingerprintAuth } from "nativescript-fingerprint-auth";
const fingerprintAuth = new FingerprintAuth();
fingerprintAuth.didFingerprintDatabaseChange()
.then(changed => console.log({changed}));

iPhone 11 Pro

1
2
// changed
false

Android HUAWEI nova lite 2

1
2
// changed
false

生体認証(Fallback: パスコード)

参考コード

verifyFingerprint() で生体認証の実施。

title, authenticationValidityDuration, useCustomAndroidUI は Android のオプション。message は iOS, Android 共通、ただし iOS の FaceID 利用時のメッセージは app/App_Resources/iOS/Info.plist で設定する。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import { FingerprintAuth } from "nativescript-fingerprint-auth";
const fingerprintAuth = new FingerprintAuth();
const CONFIGURED_PASSWORD = "MyP@ssword";

fingerprintAuth.verifyFingerprint({
title: "指紋認証 (Android only)", // optional
message: "指紋をスキャンしてください (iOS and Android)", // optional
authenticationValidityDuration: 10, // Android only (default: 5)
useCustomAndroidUI: true, // Android only (default: false)
}).then(enteredPassword => {
if (enteredPassword === undefined) {
this.status = "Biometric ID OK";
} else {
// パスコードでの検証
if (enteredPassword === CONFIGURED_PASSWORD) {
this.status = "Biometric ID OK, using password";
} else {
this.status = "Wrong password.";
}
}
})

生体認証に成功した場合、enteredPasswordundefined となっている。

生体認証に失敗し、パスコードが認証された場合は enteredPassword が設定されている。説明文を読む限りは、スマホ本体に設定されているパスコードの検証ではなく、事前にアプリ内に設定しておいたパスワードとの一致検証を行う。

  • iPhone 11 Pro: FaceID が起動
  • Android HUAWEI nova lite 2: 指紋認証が起動
iPhone 11 Pro でパスコードへのフォールバックが発生しない

参考コード

パスコードでの検証にフォールバックするはずなのだが、iPhone 11 Pro で動作確認したところ、FaceID での認証に失敗してもパスコードでの認証に移行できなかった(ボタン自体が表示されなかった)。

以下を参考に、後述の verifyFingerprintWithCustomFallback() の第2引数に true を設定することで、パスコードでの検証にフォールバックできた。
※ただし、 アプリ内に独自に設定したパスコード ではなく、 iPhone 本体のパスコード での検証だった。

以下は実装イメージ。

1
2
fingerprintAuth.verifyFingerprintWithCustomFallback({/* ... */}, true)
.then(/* ... */).catch(/* ... */);
Android で生体認証

Android HUAWEI nova lite 2 では、以下のような挙動となった。

  • useCustomAndroidUI: true: 指紋認証が起動
  • useCustomAndroidUI: false: パターンロック認証が起動
1
2
3
fingerprintAuth.verifyFingerprint({
useCustomAndroidUI: true,
})

※機種、OS version、設定 などによっては、特に何もしなくてもパスコードにフォールバックできるかもしれないが詳細不明。

生体認証(Fallback: カスタム) (iOS のみ)

参考コード

verifyFingerprintWithCustomFallback() で、カスタムフォールバックありの生体認証。

前項で書いた通り、第2引数に true を設定することで、iPhone 本体でのパスコード認証にフォールバック可能。

1
2
3
4
5
6
7
8
9
import { FingerprintAuth } from "nativescript-fingerprint-auth";
const fingerprintAuth = new FingerprintAuth();
const usePasscode = false; // README には記載されてないオプション(default: false)

fingerprintAuth.verifyFingerprintWithCustomFallback({
message: 'Scan yer finger',
fallbackMessage: 'Enter PIN',
authenticationValidityDuration: 10,
}, usePasscode).then(/* ... */);
  • iPhone 11 Pro: FaceID が起動 → 認証失敗時パスコード認証に移行可能

Tips

メッセージの変更

参考: optional change

Android でメッセージを変更するには App_Resources/Android/src/main/res/values/strings.xml を変更すると良いっぽい。

まとめ

参考文献

関連記事