Keeping your phone secure from strangers is the top most priority. People use various kinds of methods to secure their phones, but what about adding Security to your mobile app?
Well lets talk about adding fingerprint(Touch ID) security in your mobile app.
In this tutorial, we'll be using the react-native-fingerprint-scanner
package for securing our mobile app. You can visit here for npm package.
Step 1: Enable Fingerprint in your mobile device:
1. For iOS:
- Tap Settings > Touch ID & Passcode, then enter your passcode.
- Tap Add a Fingerprint and hold your device as you normally would when touching the Touch ID sensor.
2. For Android Phones:
- Samsung: Navigate to Settings, then tap Biometrics and security, and then tap Fingerprints.
- OnePlus: Navigating to the Security & lockscreen menu, locate the Fingerprint list subheading
- Motorola: Touch Settings > Security & Location, and touch Fingerprint.
Step 2: Installing the package:
npm i react-native-fingerprint-scanner
OR
yarn add react-native-fingerprint-scanner
Linking the library to app:
- For RN >= 0.60:
$ cd ios && pod install
- For RN < 0.60, use react-native link to add the library to your project:
$ react-native link react-native-fingerprint-scanner
Step 3: Adding app permission:
- Android:
In your AndroidManifest.xml
: (API level 28+)
<uses-permission android:name="android.permission.USE_BIOMETRIC" />
- iOS:
In your Info.plist
:
<key>NSFaceIDUsageDescription</key>
<string>$(PRODUCT_NAME) requires FaceID access to allows you quick and secure access.</string>
Make sure the following versions are all correct in android/app/build.gradle
// API v29 enables FaceId
android {
compileSdkVersion 29
buildToolsVersion "29.0.2"
...
defaultConfig {
targetSdkVersion 29
Step 4: Testing the code in app using fingerprint
You can test the fingerprint(Touch ID) by following code.
- iOS:
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { AlertIOS } from 'react-native';
import FingerprintScanner from 'react-native-fingerprint-scanner';
class FingerprintPopup extends Component {
componentDidMount() {
FingerprintScanner
.authenticate({ description: 'Scan your fingerprint on the device scanner to continue' })
.then(() => {
this.props.handlePopupDismissed();
AlertIOS.alert('Authenticated successfully');
})
.catch((error) => {
this.props.handlePopupDismissed();
AlertIOS.alert(error.message);
});
}
render() {
return false;
}
}
FingerprintPopup.propTypes = {
handlePopupDismissed: PropTypes.func.isRequired,
};
export default FingerprintPopup;
- Android:
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import {
Alert,
Image,
Text,
TouchableOpacity,
View,
ViewPropTypes,
Platform,
} from 'react-native';
import FingerprintScanner from 'react-native-fingerprint-scanner';
import styles from './FingerprintPopup.component.styles';
import ShakingText from './ShakingText.component';
// - this example component supports both the
// legacy device-specific (Android < v23) and
// current (Android >= 23) biometric APIs
// - your lib and implementation may not need both
class BiometricPopup extends Component {
constructor(props) {
super(props);
this.state = {
errorMessageLegacy: undefined,
biometricLegacy: undefined
};
this.description = null;
}
componentDidMount() {
if (this.requiresLegacyAuthentication()) {
this.authLegacy();
} else {
this.authCurrent();
}
}
componentWillUnmount = () => {
FingerprintScanner.release();
}
requiresLegacyAuthentication() {
return Platform.Version < 23;
}
authCurrent() {
FingerprintScanner
.authenticate({ title: 'Log in with Biometrics' })
.then(() => {
this.props.onAuthenticate();
});
}
authLegacy() {
FingerprintScanner
.authenticate({ onAttempt: this.handleAuthenticationAttemptedLegacy })
.then(() => {
this.props.handlePopupDismissedLegacy();
Alert.alert('Fingerprint Authentication', 'Authenticated successfully');
})
.catch((error) => {
this.setState({ errorMessageLegacy: error.message, biometricLegacy: error.biometric });
this.description.shake();
});
}
handleAuthenticationAttemptedLegacy = (error) => {
this.setState({ errorMessageLegacy: error.message });
this.description.shake();
};
renderLegacy() {
const { errorMessageLegacy, biometricLegacy } = this.state;
const { style, handlePopupDismissedLegacy } = this.props;
return (
<View style={styles.container}>
<View style={[styles.contentContainer, style]}>
<Image
style={styles.logo}
source={require('./assets/finger_print.png')}
/>
<Text style={styles.heading}>
Biometric{'\n'}Authentication
</Text>
<ShakingText
ref={(instance) => { this.description = instance; }}
style={styles.description(!!errorMessageLegacy)}>
{errorMessageLegacy || `Scan your ${biometricLegacy} on the\ndevice scanner to continue`}
</ShakingText>
<TouchableOpacity
style={styles.buttonContainer}
onPress={handlePopupDismissedLegacy}
>
<Text style={styles.buttonText}>
BACK TO MAIN
</Text>
</TouchableOpacity>
</View>
</View>
);
}
render = () => {
if (this.requiresLegacyAuthentication()) {
return this.renderLegacy();
}
// current API UI provided by native BiometricPrompt
return null;
}
}
BiometricPopup.propTypes = {
onAuthenticate: PropTypes.func.isRequired,
handlePopupDismissedLegacy: PropTypes.func,
style: ViewPropTypes.style,
};
export default BiometricPopup;
- Screenshot: Taken from the docs
Step 5: Using the appropriate APIs:
For iOS & Android (common):
isSensorAvailable()
: Starts Fingerprint authentication on iOS- Returns a
Promise<string>
- biometryType: String - The type of biometric authentication supported by the device.
- iOS: biometryType = 'Touch ID', 'Face ID'
- Android: biometryType = 'Biometrics'
error: FingerprintScannerError { name, message, biometric }
- The name and message of failure and the biometric type in use.
- Returns a
componentDidMount() {
FingerprintScanner
.isSensorAvailable()
.then(biometryType => this.setState({ biometryType }))
.catch(error => this.setState({ errorMessage: error.message }));
}
For iOS:
authenticate({ description, fallbackEnabled })
- Returns a
Promise
description: String
- the string to explain the request for user authentication.fallbackEnabled: Boolean
- default totrue
, whether to display fallback button (e.g. Enter Password).
- Returns a
componentDidMount() {
FingerprintScanner
.authenticate({ description: 'Scan your fingerprint on the device scanner to continue' })
.then(() => {
this.props.handlePopupDismissed();
AlertIOS.alert('Authenticated successfully');
})
.catch((error) => {
this.props.handlePopupDismissed();
AlertIOS.alert(error.message);
});
}
For Android:
authenticate({ title="Log In", subTitle, description, cancelButton="Cancel", onAttempt=() => (null) })
: Starts Fingerprint authentication- Returns a
Promise
title: String
the title text to display in the native Android popupsubTitle: String
the sub title text to display in the native Android popupdescription: String
the description text to display in the native Android popupcancelButton: String
the cancel button text to display in the native Android popuponAttempt: Function
- a callback function when users are trying to scan their fingerprint but failed.
- Returns a
componentDidMount() {
if (requiresLegacyAuthentication()) {
authLegacy();
} else {
authCurrent();
}
}
componentWillUnmount = () => {
FingerprintScanner.release();
}
requiresLegacyAuthentication() {
return Platform.Version < 23;
}
authCurrent() {
FingerprintScanner
.authenticate({ title: 'Log in with Biometrics' })
.then(() => {
this.props.onAuthenticate();
});
}
authLegacy() {
FingerprintScanner
.authenticate({ onAttempt: this.handleAuthenticationAttemptedLegacy })
.then(() => {
this.props.handlePopupDismissedLegacy();
Alert.alert('Fingerprint Authentication', 'Authenticated successfully');
})
.catch((error) => {
this.setState({ errorMessageLegacy: error.message, biometricLegacy: error.biometric });
this.description.shake();
});
}
handleAuthenticationAttemptedLegacy = (error) => {
this.setState({ errorMessageLegacy: error.message });
this.description.shake();
};
release()
: Stops fingerprint scanner listener, cancels native prompt if visible.- Returns a
Void
- Returns a
componentWillUnmount() {
FingerprintScanner.release();
}
By reading this blog, I'm pretty sure that you'll be able to implement Fingerprint(Touch ID) in your React Native app. If you face any error while implementing, you can always have a look at docs here .
Cover GIF Credits: Gfycat