import React from 'react'; import { Subscription } from '@unimodules/core'; import * as AppleAuthentication from 'expo-apple-authentication'; import { Alert, AsyncStorage, ScrollView, StyleSheet, View, Text, Button, Slider } from 'react-native'; import MonoText from '../components/MonoText'; const { AppleAuthenticationButtonStyle, AppleAuthenticationButtonType, AppleAuthenticationCredentialState, AppleAuthenticationScope, } = AppleAuthentication; type State = { isAvailable: boolean; buttonStyle: AppleAuthentication.AppleAuthenticationButtonStyle; buttonType: AppleAuthentication.AppleAuthenticationButtonType; cornerRadius: number; credentials?: AppleAuthentication.AppleAuthenticationCredential | null; credentialState?: AppleAuthentication.AppleAuthenticationCredentialState; } const USER_CREDENTIAL_KEY = 'ExpoNativeComponentList/AppleAuthentication'; const CREDENTIAL_MESSAGES = { [AppleAuthenticationCredentialState.REVOKED]: 'Your authorization has been revoked.', [AppleAuthenticationCredentialState.AUTHORIZED]: 'You\'re authorized.', [AppleAuthenticationCredentialState.NOT_FOUND]: 'You\'re not registered yet.', [AppleAuthenticationCredentialState.TRANSFERRED]: 'Credentials transferred.', // Whatever that means... }; export default class AppleAuthenticationScreen extends React.Component<{}, State> { static navigationOptions = { title: 'Apple Authentication', }; readonly state: State = { isAvailable: false, buttonStyle: AppleAuthenticationButtonStyle.WHITE, buttonType: AppleAuthenticationButtonType.SIGN_IN, cornerRadius: 5, credentials: null, }; _subscription?: Subscription; componentDidMount() { this.checkAvailability(); this.checkCredentials(); this._subscription = AppleAuthentication.addRevokeListener(this.revokeListener); } componentWillUnmount() { if (this._subscription) { this._subscription.remove(); } } revokeListener = () => { this.setState({ credentials: null }); Alert.alert('Credentials revoked!'); }; checkAvailability = async () => { const isAvailable = await AppleAuthentication.isAvailableAsync(); this.setState({ isAvailable }); }; signIn = async () => { try { const credentials = await AppleAuthentication.signInAsync({ requestedScopes: [ AppleAuthenticationScope.FULL_NAME, AppleAuthenticationScope.EMAIL, ], state: 'this-is-a-test', }); this.setState({ credentials }); if (credentials.user) { await AsyncStorage.setItem(USER_CREDENTIAL_KEY, credentials.user); } await this.checkCredentials(); } catch (error) { alert(error); } } refresh = async () => { try { const credentials = await AppleAuthentication.refreshAsync({ requestedScopes: [ AppleAuthenticationScope.FULL_NAME, AppleAuthenticationScope.EMAIL, ], user: await this.getUserIdentifier(), state: 'this-is-a-test', }); this.setState({ credentials }); await this.checkCredentials(); } catch (error) { alert(error); } } signOut = async () => { try { const credentials = await AppleAuthentication.signOutAsync({ user: await this.getUserIdentifier(), state: 'this-is-a-test', }); this.setState({ credentials: null, credentialState: null }); } catch (error) { alert(error); } } async checkCredentials() { try { const user = await this.getUserIdentifier(); const credentialState = await AppleAuthentication.getCredentialStateAsync(user); this.setState({ credentialState }); } catch (e) { // Obtaining a user or the credentials failed - fallback to not found. this.setState({ credentialState: AppleAuthenticationCredentialState.NOT_FOUND }); } }; async getUserIdentifier(): Promise { return this.state.credentials && this.state.credentials.user || await AsyncStorage.getItem(USER_CREDENTIAL_KEY); } isAuthorized(): boolean { return this.state.credentialState === AppleAuthenticationCredentialState.AUTHORIZED; } render() { if (this.state.isAvailable === undefined) { return ( Checking availability ... ); } if (!this.state.isAvailable) { return ( SignIn with Apple is not available ) } return ( {CREDENTIAL_MESSAGES[this.state.credentialState]} Button Style: