Reputation: 43
Well, I can`t find anything like this on the web, so I am hoping someone can help me on this one.
I`m creating a bare react native android app, and I need to check for the user's Local Authentication whenever the app comes from the background.
I'm using Expo Authentication to handle the authentication, however, checking the app state with AppState from React Native is not useful, since every time the authentication screen (biometrics, facial recognition or even the PIN number) shows up on the screen the AppState will change from active to background, so it will require for an authentication again and again, because it will always come from the 'background'.
I'm not able to control it with a variable, since I don't have any identifier that could tell me the app came from expo Local Authentication screen, so I`m stuck on this "which came first, the chicken or the egg" problem.
Here is the part of the component that I`ve created to handle it so far:
AppState.addEventListener('change', _handleAppStateChange);
return () => {
AppState.removeEventListener('change', _handleAppStateChange);
};
}, []);
const _handleAppStateChange = async (nextAppState: any) => {
if (
appState.current.match(/inactive|background/) &&
nextAppState === 'active'
) {
clearTimeout(authenticationRequiredTimeout);
if (user && shouldAuthenticate) {
LocalAuthentication.hasHardwareAsync().then((hasHardware) => {
if (hasHardware) {
LocalAuthentication.isEnrolledAsync().then((isEnrolled) => {
if (isEnrolled) {
LocalAuthentication.authenticateAsync().then(
(authentication) => {
if (authentication.success !== true) {
logout();
}
setShouldAuthenticate(false);
console.log(authentication);
},
);
}
});
}
});
}
} else {
let timeout = setTimeout(() => {
setShouldAuthenticate(true);
}, 5000);
setAuthenticationRequiredTimeout(timeout);
}
console.log(shouldAuthenticate);
appState.current = nextAppState;
console.log('AppState', appState);
};```
Any help would be much appreciatted
Upvotes: 4
Views: 2318
Reputation: 1
I made it a little easier. I simply record the time when the application went into the background in the storage. When the status becomes "active", I compare the time difference and if this difference is greater than the delay I need, I call the authentication method.
export const useAppStateCheck = () => {
const verificationHandle = () => {
// YOURT BOI AUTH CODE HERE...
};
const changeAppStateListener = async (status: AppStateStatus) => {
if (status === "background") {
const date = Date.now();
await Storage.set("temporaryMovedToBg", date);
}
if (status === "active") {
const date = await Storage.get("temporaryMovedToBg");
if (Date.now() - Number(date) >= CONFIG.BIO_AUTH_EXPIRATION_TIME) verificationHandle();
}
};
useEffect(() => {
const subscription = AppState.addEventListener("change", changeAppStateListener);
return subscription.remove;
}, []);
};
Upvotes: 0
Reputation: 738
I've ran into the same problem and solved it as follows:
My app contains a store (just a single instance of a class). In this store I have added a property temporarilyMovedToBackground
. Whenever I call Expo's localAuthentication
, I first set the property temporarilyMovedToBackground
to true. After the call finishes I set it to false again, with a timeout of 1000.
Then, when checking if the appState changed to background, I also check if temporarilyMovedToBackground
is false.
Upvotes: 3