1import * as LocalAuthentication from 'expo-local-authentication';
2import React from 'react';
3import { Text, View } from 'react-native';
4
5import Button from '../components/Button';
6import MonoText from '../components/MonoText';
7
8interface State {
9  waiting: boolean;
10  supportedAuthenticationTypes?: string[];
11  hasHardware?: boolean;
12  isEnrolled?: boolean;
13}
14
15export default class LocalAuthenticationScreen extends React.Component<object, State> {
16  static navigationOptions = {
17    title: 'LocalAuthentication',
18  };
19
20  readonly state: State = {
21    waiting: false,
22  };
23
24  componentDidMount() {
25    this.checkDevicePossibilities();
26  }
27
28  async checkDevicePossibilities() {
29    const [hasHardware, isEnrolled, supportedAuthenticationTypes] = await Promise.all([
30      LocalAuthentication.hasHardwareAsync(),
31      LocalAuthentication.isEnrolledAsync(),
32      this.getAuthenticationTypes(),
33    ]);
34    this.setState({ hasHardware, isEnrolled, supportedAuthenticationTypes });
35  }
36
37  async getAuthenticationTypes() {
38    return (await LocalAuthentication.supportedAuthenticationTypesAsync()).map(
39      type => LocalAuthentication.AuthenticationType[type]
40    );
41  }
42
43  authenticateWithFallback = () => {
44    this.authenticate(true);
45  };
46
47  authenticateWithoutFallback = () => {
48    this.authenticate(false);
49  };
50
51  async authenticate(withFallback: boolean = true) {
52    this.setState({ waiting: true });
53    try {
54      const result = await LocalAuthentication.authenticateAsync({
55        promptMessage: 'Authenticate',
56        cancelLabel: 'Cancel label',
57        disableDeviceFallback: !withFallback,
58      });
59      if (result.success) {
60        alert('Authenticated!');
61      } else {
62        alert('Failed to authenticate, reason: ' + result.error);
63      }
64    } finally {
65      this.setState({ waiting: false });
66    }
67  }
68
69  render() {
70    const { waiting, ...capabilities } = this.state;
71
72    return (
73      <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
74        <View style={{ paddingBottom: 30 }}>
75          <Text>Device capabilities:</Text>
76          <MonoText textStyle={{ fontSize: 14 }}>{JSON.stringify(capabilities, null, 2)}</MonoText>
77        </View>
78        <View style={{ height: 200 }}>
79          {waiting ? (
80            <Text>Waiting for authentication...</Text>
81          ) : (
82            <View>
83              <Button
84                style={{ margin: 5 }}
85                onPress={this.authenticateWithFallback}
86                title="Authenticate with device fallback"
87              />
88              <Button
89                style={{ margin: 5 }}
90                onPress={this.authenticateWithoutFallback}
91                title="Authenticate without device fallback"
92              />
93            </View>
94          )}
95        </View>
96      </View>
97    );
98  }
99}
100