@@ -25,6 +25,10 @@ It provides a **Default View** that prompts the user to place a finger to the iP
2525</div >
2626
2727### Android Version
28+ 4.0.0 Prefers the new native Android BiometricPrompt lib on any Android >= v23 (M)
29+ 4.0.0 also DEPRECATES support for the legacy library that provides support for Samsung & MeiZu phones
30+
31+ 3.0.2 and below:
2832Using an expandable Android Fingerprint API library, which combines [ Samsung] ( http://developer.samsung.com/galaxy/pass# ) and [ MeiZu] ( http://open-wiki.flyme.cn/index.php?title=%E6%8C%87%E7%BA%B9%E8%AF%86%E5%88%ABAPI ) 's official Fingerprint API.
2933
3034Samsung and MeiZu's Fingerprint SDK supports most devices which system versions less than Android 6.0.
@@ -76,7 +80,7 @@ $ react-native link react-native-fingerprint-scanner
7680 ```
77813 . Insert the following lines inside the dependencies block in ` android/app/build.gradle ` :
7882 ```
79- compile project(': react-native-fingerprint-scanner ')
83+ implementation project(': react-native-fingerprint-scanner ')
8084 ```
8185
8286### App Permissions
@@ -86,12 +90,18 @@ Add the following permissions to their respective files:
8690#### Android
8791In your ` AndroidManifest.xml ` :
8892
89- API level 28+ ([ Reference] ( https://developer.android.com/reference/android/Manifest.permission#USE_BIOMETRIC ) )
93+ API level 28+ (Uses Android native BiometricPrompt) ( [ Reference] ( https://developer.android.com/reference/android/Manifest.permission#USE_BIOMETRIC ) )
9094``` xml
9195<uses-permission android : name =" android.permission.USE_BIOMETRIC" />
9296```
9397
94- API level <28 ([ Reference] ( https://developer.android.com/reference/android/Manifest.permission#USE_FINGERPRINT ) )
98+ API level 23-28 (Uses Android native FingerprintCompat) [ Reference] ( https://developer.android.com/reference/android/Manifest.permission#USE_FINGERPRINT ) )
99+ ``` xml
100+ <uses-permission android : name =" android.permission.USE_FINGERPRINT" />
101+ ```
102+
103+ // DEPRECATED in 4.0.0
104+ API level <23 (Uses device-specific native fingerprinting, if available - Samsung & MeiZu only) [ Reference] ( https://developer.android.com/reference/android/Manifest.permission#USE_FINGERPRINT ) )
95105``` xml
96106<uses-permission android : name =" android.permission.USE_FINGERPRINT" />
97107```
@@ -107,23 +117,26 @@ In your `Info.plist`:
107117
1081181 . Make sure the following versions are all correct in ` android/app/build.gradle `
109119 ```
120+ // API v29 enables FaceId
110121 android {
111- compileSdkVersion 25
112- buildToolsVersion "25 .0.3 "
122+ compileSdkVersion 29
123+ buildToolsVersion "29 .0.2 "
113124 ...
114125 defaultConfig {
115- targetSdkVersion 25
126+ targetSdkVersion 29
116127 ```
117128
1181292. Add necessary rules to `android/app/proguard-rules.pro` if you are using proguard:
119130 ```
120131 # MeiZu Fingerprint
121132
133+ // DEPRECATED in 4.0.0
122134 -keep class com.fingerprints.service.** { *; }
123135 -dontwarn com.fingerprints.service.**
124136
125137 # Samsung Fingerprint
126138
139+ // DEPRECATED in 4.0.0
127140 -keep class com.samsung.android.sdk.** { *; }
128141 -dontwarn com.samsung.android.sdk.**
129142 ```
@@ -133,6 +146,7 @@ In your `Info.plist`:
133146* For Gradle < 3 you MUST install react-native-fingerprint-scanner at version <= 2.5.0
134147* For RN >= 0.57 and/or Gradle >= 3 you MUST install react-native-fingerprint-scanner at version >= 2.6.0
135148* For RN >= 0.60 you MUST install react-native-fingerprint-scanner at version >= 3.0.0
149+ * For Android native Face Unlock, MUST use >= 4.0.0
136150
137151## Example
138152
@@ -174,54 +188,84 @@ export default FingerprintPopup;
174188
175189** Android Implementation**
176190``` javascript
191+
177192import React , { Component } from ' react' ;
178193import PropTypes from ' prop-types' ;
179-
180194import {
181195 Alert ,
182196 Image ,
183197 Text ,
184198 TouchableOpacity ,
185199 View ,
186- ViewPropTypes
200+ ViewPropTypes ,
201+ Platform ,
187202} from ' react-native' ;
188- import FingerprintScanner from ' react-native-fingerprint-scanner' ;
189203
190- import ShakingText from ' ./ShakingText.component ' ;
204+ import FingerprintScanner from ' react-native-fingerprint-scanner ' ;
191205import styles from ' ./FingerprintPopup.component.styles' ;
206+ import ShakingText from ' ./ShakingText.component' ;
192207
193- class FingerprintPopup extends Component {
194208
209+ // - this example component supports both the
210+ // legacy device-specific (Android < v23) and
211+ // current (Android >= 23) biometric APIs
212+ // - your lib and implementation may not need both
213+ class BiometricPopup extends Component {
195214 constructor (props ) {
196215 super (props);
197- this .state = { errorMessage: undefined };
216+ this .state = {
217+ errorMessageLegacy: undefined ,
218+ biometricLegacy: undefined
219+ };
220+
221+ this .description = null ;
198222 }
199223
200224 componentDidMount () {
225+ if (requiresLegacyAuthentication ()) {
226+ authLegacy ();
227+ } else {
228+ authCurrent ();
229+ }
230+ }
231+
232+ componentWillUnmount = () => {
233+ FingerprintScanner .release ();
234+ }
235+
236+ requiresLegacyAuthentication () {
237+ return Platform .Version < 23 ;
238+ }
239+
240+ authCurrent () {
201241 FingerprintScanner
202- .authenticate ({ onAttempt : this . handleAuthenticationAttempted })
242+ .authenticate ({ description : ' Log in with Biometrics ' })
203243 .then (() => {
204- this .props .handlePopupDismissed ();
244+ this .props .onAuthenticate ();
245+ });
246+ }
247+
248+ authLegacy () {
249+ FingerprintScanner
250+ .authenticate ({ onAttempt: this .handleAuthenticationAttemptedLegacy })
251+ .then (() => {
252+ this .props .handlePopupDismissedLegacy ();
205253 Alert .alert (' Fingerprint Authentication' , ' Authenticated successfully' );
206254 })
207255 .catch ((error ) => {
208- this .setState ({ errorMessage : error .message });
256+ this .setState ({ errorMessageLegacy : error .message , biometricLegacy : error . biometric });
209257 this .description .shake ();
210258 });
211259 }
212260
213- componentWillUnmount () {
214- FingerprintScanner .release ();
215- }
216-
217- handleAuthenticationAttempted = (error ) => {
218- this .setState ({ errorMessage: error .message });
261+ handleAuthenticationAttemptedLegacy = (error ) => {
262+ this .setState ({ errorMessageLegacy: error .message });
219263 this .description .shake ();
220264 };
221265
222- render () {
223- const { errorMessage } = this .state ;
224- const { style , handlePopupDismissed } = this .props ;
266+ renderLegacy () {
267+ const { errorMessageLegacy , biometricLegacy } = this .state ;
268+ const { style , handlePopupDismissedLegacy } = this .props ;
225269
226270 return (
227271 < View style= {styles .container }>
@@ -233,17 +277,17 @@ class FingerprintPopup extends Component {
233277 / >
234278
235279 < Text style= {styles .heading }>
236- Fingerprint {' \n ' }Authentication
280+ Biometric {' \n ' }Authentication
237281 < / Text >
238282 < ShakingText
239283 ref= {(instance ) => { this .description = instance; }}
240- style= {styles .description (!! errorMessage )}>
241- {errorMessage || ' Scan your fingerprint on the\n device scanner to continue' }
284+ style= {styles .description (!! errorMessageLegacy )}>
285+ {errorMessageLegacy || ` Scan your ${ biometricLegacy } on the\n device scanner to continue` }
242286 < / ShakingText>
243287
244288 < TouchableOpacity
245289 style= {styles .buttonContainer }
246- onPress= {handlePopupDismissed }
290+ onPress= {handlePopupDismissedLegacy }
247291 >
248292 < Text style= {styles .buttonText }>
249293 BACK TO MAIN
@@ -254,14 +298,25 @@ class FingerprintPopup extends Component {
254298 < / View>
255299 );
256300 }
301+
302+
303+ render = () => {
304+ if (this .requiresLegacyAuthentication ()) {
305+ return this .renderLegacy ();
306+ }
307+
308+ // current API UI provided by native BiometricPrompt
309+ return null ;
310+ }
257311}
258312
259- FingerprintPopup .propTypes = {
313+ BiometricPopup .propTypes = {
314+ onAuthenticate: PropTypes .func .isRequired ,
315+ handlePopupDismissedLegacy: PropTypes .func ,
260316 style: ViewPropTypes .style ,
261- handlePopupDismissed: PropTypes .func .isRequired ,
262317};
263318
264- export default FingerprintPopup ;
319+ export default BiometricPopup ;
265320```
266321
267322## API
@@ -271,6 +326,8 @@ Checks if Fingerprint Scanner is able to be used by now.
271326
272327- Returns a ` Promise<string> `
273328- ` biometryType: String ` - The type of biometric authentication supported by the device.
329+ - iOS: biometryType = 'Touch ID', 'Face ID'
330+ - Android: biometryType = 'Biometrics'
274331- ` error: FingerprintScannerError { name, message, biometric } ` - The name and message of failure and the biometric type in use.
275332
276333``` javascript
@@ -304,29 +361,59 @@ componentDidMount() {
304361}
305362```
306363
307- ### ` authenticate({ onAttempt }) ` : (Android)
364+ ### ` authenticate({ description="Log In", onAttempt=() => (null) }) ` : (Android)
308365Starts Fingerprint authentication on Android.
309366
310367- Returns a ` Promise `
368+ - ` description: String ` the title text to display in the native Android popup
311369- ` onAttempt: Function ` - a callback function when users are trying to scan their fingerprint but failed.
312370
313371``` javascript
314372componentDidMount () {
373+ if (requiresLegacyAuthentication ()) {
374+ authLegacy ();
375+ } else {
376+ authCurrent ();
377+ }
378+ }
379+
380+ componentWillUnmount = () => {
381+ FingerprintScanner .release ();
382+ }
383+
384+ requiresLegacyAuthentication () {
385+ return Platform .Version < 23 ;
386+ }
387+
388+ authCurrent () {
315389 FingerprintScanner
316- .authenticate ({ onAttempt : this . handleAuthenticationAttempted })
390+ .authenticate ({ description : ' Log in with Biometrics ' })
317391 .then (() => {
318- this .props .handlePopupDismissed ();
392+ this .props .onAuthenticate ();
393+ });
394+ }
395+
396+ authLegacy () {
397+ FingerprintScanner
398+ .authenticate ({ onAttempt: this .handleAuthenticationAttemptedLegacy })
399+ .then (() => {
400+ this .props .handlePopupDismissedLegacy ();
319401 Alert .alert (' Fingerprint Authentication' , ' Authenticated successfully' );
320402 })
321403 .catch ((error ) => {
322- this .setState ({ errorMessage : error .message });
404+ this .setState ({ errorMessageLegacy : error .message , biometricLegacy : error . biometric });
323405 this .description .shake ();
324406 });
325407}
408+
409+ handleAuthenticationAttemptedLegacy = (error ) => {
410+ this .setState ({ errorMessageLegacy: error .message });
411+ this .description .shake ();
412+ };
326413```
327414
328415### ` release() ` : (Android)
329- Stops fingerprint scanner listener, releases cache of internal state in native code.
416+ Stops fingerprint scanner listener, releases cache of internal state in native code, and cancels native prompt if visible .
330417
331418- Returns a ` Void `
332419
@@ -338,27 +425,32 @@ componentWillUnmount() {
338425
339426### ` Types of Biometrics `
340427
341- | Value | OS |
342- | ---| ---|
343- | Touch ID | iOS |
344- | Face ID | iOS |
345- | Fingerprint | Android |
428+ | Value | OS | Description |
429+ | ---| ---| --- |
430+ | Touch ID | iOS | |
431+ | Face ID | iOS | |
432+ | Biometrics | Android | Refers to the biometric set as preferred on the device |
346433
347434### ` Errors `
348435
349436| Name | Message |
350437| ---| ---|
351438| AuthenticationNotMatch | No match |
352439| AuthenticationFailed | Authentication was not successful because the user failed to provide valid credentials |
440+ | AuthenticationTimeout | Authentication was not successful because the operation timed out |
441+ | AuthenticationProcessFailed | 'Sensor was unable to process the image. Please try again |
353442| UserCancel | Authentication was canceled by the user - e.g. the user tapped Cancel in the dialog |
354443| UserFallback | Authentication was canceled because the user tapped the fallback button (Enter Password) |
355444| SystemCancel | Authentication was canceled by system - e.g. if another application came to foreground while the authentication dialog was up |
356445| PasscodeNotSet | Authentication could not start because the passcode is not set on the device |
357- | FingerprintScannerNotAvailable | Authentication could not start because Fingerprint Scanner is not available on the device |
358- | FingerprintScannerNotEnrolled | Authentication could not start because Fingerprint Scanner has no enrolled fingers |
446+ | DeviceLocked | Authentication was not successful, the device currently in a lockout of 30 seconds |
447+ | DeviceLockedPermanent | Authentication was not successful, device must be unlocked via password |
448+ | DeviceOutOfMemory | Authentication could not proceed because there is not enough free memory on the device |
449+ | HardwareError | A hardware error occurred |
359450| FingerprintScannerUnknownError | Could not authenticate for an unknown reason |
360451| FingerprintScannerNotSupported | Device does not support Fingerprint Scanner |
361- | DeviceLocked | Authentication was not successful, the device currently in a lockout of 30 seconds |
452+ | FingerprintScannerNotEnrolled | Authentication could not start because Fingerprint Scanner has no enrolled fingers |
453+ | FingerprintScannerNotAvailable | Authentication could not start because Fingerprint Scanner is not available on the device |
362454
363455## License
364456
0 commit comments