expo-dev-menu
Version:
Expo/React Native module with the developer menu.
92 lines (75 loc) • 2.57 kB
text/typescript
import { NativeModules, AppState, Linking } from 'react-native';
const DevMenu = NativeModules.ExpoDevMenuInternal;
let redirectHandler: ((event: any) => void) | null = null;
let onWebBrowserCloseAndroid: null | (() => void) = null;
let isAppStateAvailable: boolean = AppState.currentState !== null;
function onAppStateChangeAndroid(state: any) {
if (!isAppStateAvailable) {
isAppStateAvailable = true;
return;
}
if (state === 'active' && onWebBrowserCloseAndroid) {
onWebBrowserCloseAndroid();
}
}
function stopWaitingForRedirect() {
if (!redirectHandler) {
throw new Error(
`The WebBrowser auth session is in an invalid state with no redirect handler when one should be set`
);
}
Linking.removeEventListener('url', redirectHandler);
redirectHandler = null;
}
async function openBrowserAndWaitAndroidAsync(startUrl: string): Promise<any> {
const appStateChangedToActive = new Promise(resolve => {
onWebBrowserCloseAndroid = resolve;
AppState.addEventListener('change', onAppStateChangeAndroid);
});
let result = { type: 'cancel' };
await DevMenu.openWebBrowserAsync(startUrl);
const type = 'opened';
if (type === 'opened') {
await appStateChangedToActive;
result = { type: 'dissmiss' };
}
AppState.removeEventListener('change', onAppStateChangeAndroid);
onWebBrowserCloseAndroid = null;
return result;
}
function waitForRedirectAsync(returnUrl: string): Promise<any> {
return new Promise(resolve => {
redirectHandler = (event: any) => {
if (event.url.startsWith(returnUrl)) {
resolve({ url: event.url, type: 'success' });
}
};
Linking.addEventListener('url', redirectHandler);
});
}
async function openAuthSessionPolyfillAsync(startUrl: string, returnUrl: string): Promise<any> {
if (redirectHandler) {
throw new Error(
`The WebBrowser's auth session is in an invalid state with a redirect handler set when it should not be`
);
}
if (onWebBrowserCloseAndroid) {
throw new Error(`WebBrowser is already open, only one can be open at a time`);
}
try {
return await Promise.race([
openBrowserAndWaitAndroidAsync(startUrl),
waitForRedirectAsync(returnUrl),
]);
} finally {
stopWaitingForRedirect();
}
}
export async function openAuthSessionAsync(url: string, returnUrl: string): Promise<any> {
if (DevMenu.openAuthSessionAsync) {
// iOS
return await DevMenu.openAuthSessionAsync(url, returnUrl);
}
// Android
return await openAuthSessionPolyfillAsync(url, returnUrl);
}