Skip to content

Commit

Permalink
[expo-local-authentication] Add support for promptMessage, `cancelL…
Browse files Browse the repository at this point in the history
…abel` and `disableDeviceFallback` on Android (#8219)

* [ANDROID] Add local authentication options

* Unify tests

* Remove empty space

* Use Map

* Change variables scope

* Fix lint

* Build

* Unnecessary empty space removal

* Add changelog

* Update packages/expo-local-authentication/CHANGELOG.md

Co-authored-by: Łukasz Kosmaty <lukasz.kosmaty@student.uj.edu.pl>

Co-authored-by: Łukasz Kosmaty <lukasz.kosmaty@student.uj.edu.pl>
  • Loading branch information
diegolmello and lukmccall committed May 18, 2020
1 parent 027317d commit 425d5cc
Show file tree
Hide file tree
Showing 11 changed files with 55 additions and 58 deletions.
Expand Up @@ -33,8 +33,9 @@ export default class LocalAuthenticationScreen extends React.Component<{}, State
this.setState({ waiting: true });
try {
const result = await LocalAuthentication.authenticateAsync({
promptMessage: 'This message only shows up on iOS',
fallbackLabel: '',
promptMessage: 'Authenticate',
cancelLabel: 'Cancel label',
disableDeviceFallback: true,
});
if (result.success) {
alert('Authenticated!');
Expand Down
2 changes: 2 additions & 0 deletions packages/expo-local-authentication/CHANGELOG.md
Expand Up @@ -6,4 +6,6 @@

### 🎉 New features

- Added support for `promptMessage`, `cancelLabel` and `disableDeviceFallback` on Android. ([#8219](https://github.com/expo/expo/pull/8219) by [@diegolmello](https://github.com/diegolmello))

### 🐛 Bug fixes
Expand Up @@ -15,6 +15,7 @@

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;

Expand Down Expand Up @@ -96,7 +97,7 @@ public void isEnrolledAsync(final Promise promise) {
}

@ExpoMethod
public void authenticateAsync(final Promise promise) {
public void authenticateAsync(final Map<String, Object> options, final Promise promise) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
promise.reject("E_NOT_SUPPORTED", "Cannot display biometric prompt on android versions below 6.0");
return;
Expand Down Expand Up @@ -130,6 +131,22 @@ public void run() {
return;
}

String promptMessage = "";
String cancelLabel = "";
boolean disableDeviceFallback = false;

if (options.containsKey("promptMessage")) {
promptMessage = (String) options.get("promptMessage");
}

if (options.containsKey("cancelLabel")) {
cancelLabel = (String) options.get("cancelLabel");
}

if (options.containsKey("disableDeviceFallback")) {
disableDeviceFallback = (Boolean) options.get("disableDeviceFallback");
}

mIsAuthenticating = true;
mPromise = promise;
mCancellationSignal = new CancellationSignal();
Expand All @@ -138,10 +155,13 @@ public void run() {
Executor executor = Executors.newSingleThreadExecutor();
BiometricPrompt biometricPrompt = new BiometricPrompt(fragmentActivity, executor, mAuthenticationCallback);

BiometricPrompt.PromptInfo promptInfo = new BiometricPrompt.PromptInfo.Builder()
.setDeviceCredentialAllowed(true)
.setTitle("Authenticate")
.build();
BiometricPrompt.PromptInfo.Builder promptInfoBuilder = new BiometricPrompt.PromptInfo.Builder()
.setDeviceCredentialAllowed(!disableDeviceFallback)
.setTitle(promptMessage);
if (cancelLabel != null && disableDeviceFallback) {
promptInfoBuilder.setNegativeButtonText(cancelLabel);
}
BiometricPrompt.PromptInfo promptInfo = promptInfoBuilder.build();
biometricPrompt.authenticate(promptInfo);
}
});
Expand Down
20 changes: 7 additions & 13 deletions packages/expo-local-authentication/build/LocalAuthentication.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

27 changes: 11 additions & 16 deletions packages/expo-local-authentication/src/LocalAuthentication.ts
@@ -1,6 +1,5 @@
import { UnavailabilityError } from '@unimodules/core';
import invariant from 'invariant';
import { Platform } from 'react-native';

import ExpoLocalAuthentication from './ExpoLocalAuthentication';
import {
Expand Down Expand Up @@ -47,24 +46,20 @@ export async function authenticateAsync(
options = { promptMessage: options };
}

if (Platform.OS === 'ios') {
if (options.hasOwnProperty('promptMessage')) {
invariant(
typeof options.promptMessage === 'string' && options.promptMessage.length,
'LocalAuthentication.authenticateAsync : `options.promptMessage` must be a non-empty string.'
);
}
if (options.hasOwnProperty('promptMessage')) {
invariant(
typeof options.promptMessage === 'string' && options.promptMessage.length,
'LocalAuthentication.authenticateAsync : `options.promptMessage` must be a non-empty string.'
);
}

const promptMessage = options.promptMessage || 'Authenticate';
const result = await ExpoLocalAuthentication.authenticateAsync({ ...options, promptMessage });
const promptMessage = options.promptMessage || 'Authenticate';
const result = await ExpoLocalAuthentication.authenticateAsync({ ...options, promptMessage });

if (result.warning) {
console.warn(result.warning);
}
return result;
} else {
return await ExpoLocalAuthentication.authenticateAsync();
if (result.warning) {
console.warn(result.warning);
}
return result;
}

export async function cancelAuthenticate(): Promise<void> {
Expand Down
Expand Up @@ -6,9 +6,9 @@ export enum AuthenticationType {
}

export type LocalAuthenticationOptions = {
// iOS only
promptMessage?: string;
cancelLabel?: string;
fallbackLabel?: string;
disableDeviceFallback?: boolean;
// iOS only
fallbackLabel?: string;
};

This file was deleted.

Expand Up @@ -6,7 +6,7 @@ beforeEach(() => {
ExpoLocalAuthentication.authenticateAsync.mockImplementation(async () => ({ success: true }));
});

it(`uses options on iOS`, async () => {
it(`uses options`, async () => {
const options = {
promptMessage: 'Authentication is required',
cancelLabel: 'Abort',
Expand All @@ -18,7 +18,7 @@ it(`uses options on iOS`, async () => {
expect(ExpoLocalAuthentication.authenticateAsync).toHaveBeenLastCalledWith(options);
});

it(`throws when an invalid message is used on iOS`, async () => {
it(`throws when an invalid message is used`, async () => {
expect(
LocalAuthentication.authenticateAsync({ promptMessage: undefined as any })
).rejects.toThrow();
Expand Down

0 comments on commit 425d5cc

Please sign in to comment.