Here is a minimal repro. It will work on web, but it will open the “custom tabs activity” with a blank screen when coming back from auth on Android. Note: no facebook app installed.
APK download (available up to 29 days from this post).
// app.json
{
"expo": {
"name": "Sounders Music Facebook",
"slug": "sounders-music-facebook",
"version": "1.0.0",
"orientation": "portrait",
"icon": "./assets/icon.png",
"extra": {
"facebook-client-id": "771225260278103"
},
"facebookScheme": "fb771225260278103",
"facebookAppId": "771225260278103",
"facebookDisplayName": "Sounders Music Integration Sample",
"scheme": "com.soundersmusic.facebook",
"splash": {
"image": "./assets/splash.png",
"resizeMode": "contain",
"backgroundColor": "#ffffff"
},
"updates": {
"fallbackToCacheTimeout": 0
},
"assetBundlePatterns": [
"**/*"
],
"ios": {
"supportsTablet": true
},
"web": {
"favicon": "./assets/favicon.png"
},
"android": {
"package": "com.soundersmusic.facebook"
}
}
}
// package.json
{
"main": "node_modules/expo/AppEntry.js",
"dependencies": {
"expo": "~38.0.8",
"expo-auth-session": "~1.4.0",
"expo-status-bar": "^1.0.2",
"react": "~16.11.0",
"react-dom": "~16.11.0",
"react-native": "https://github.com/expo/react-native/archive/sdk-38.0.2.tar.gz",
"react-native-web": "~0.11.7"
},
"devDependencies": {
"@babel/core": "^7.8.6",
"@types/react": "~16.9.41",
"@types/react-native": "~0.62.13",
"typescript": "~3.9.5"
},
"private": true
}
// App.tsx
import { makeRedirectUri, useAuthRequest } from 'expo-auth-session';
import Constants from 'expo-constants';
import { StatusBar } from 'expo-status-bar';
import * as WebBrowser from 'expo-web-browser';
import React, { useEffect, useMemo, useState } from 'react';
import { Button, Platform, StyleSheet, Text, View } from 'react-native';
WebBrowser.maybeCompleteAuthSession();
export default function App() {
const [result, setResult] = useState('');
return (
<View style={styles.container}>
<Facebook loading={false} attempt={setResult} />
<Text>{JSON.stringify(result, undefined, 2)}</Text>
<StatusBar style="auto" />
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
},
});
const FACEBOOK_ID = Constants.manifest.extra['facebook-client-id'];
const discovery = {
authorizationEndpoint: 'https://www.facebook.com/v8.0/dialog/oauth',
tokenEndpoint: 'https://graph.facebook.com/v8.0/oauth/access_token',
};
const useProxy = Constants.appOwnership === 'expo' && Platform.OS !== 'web';
function Facebook_(props: { loading: boolean; attempt: (prop: any) => void }) {
if (!FACEBOOK_ID) {
return null;
}
return <FacebookButton {...props} />;
}
function FacebookButton({
loading,
attempt,
}: {
loading: boolean;
attempt: (prop: any) => void;
}) {
const [isAuthenticating, setAuthenticating] = useState(false);
const config = useMemo(
() => ({
clientId: FACEBOOK_ID,
scopes: ['public_profile', 'email'],
// For usage in managed apps using the proxy
redirectUri: makeRedirectUri({
useProxy,
// For usage in bare and standalone
// Use your FBID here. The path MUST be `authorize`.
native: `fb${FACEBOOK_ID}://authorize`,
}),
useProxy,
extraParams: {
// Use `popup` on web for a better experience
display: Platform.select({ web: 'popup' }) as string,
// Optionally you can use this to rerequest declined permissions
// auth_type: 'rerequest',
},
}),
[]
);
const [request, response, promptAsync] = useAuthRequest(config, discovery);
useEffect(() => {
if (!response) {
return;
}
setAuthenticating(false);
if (response.type === 'success') {
const { code, state } = response.params;
const result = {
type: 'facebook',
success: true,
redirect_uri: fixRedirectUri(config.redirectUri),
code,
state,
};
attempt(result);
}
}, [response, attempt, setAuthenticating]);
return (
<View
style={{
borderRadius: 30,
backgroundColor: '#347AE5',
marginHorizontal: 4,
elevation: 2,
}}
>
<Button
disabled={!request || isAuthenticating || loading}
color="#347AE5"
title="Facebook Go"
onPress={() => {
setAuthenticating(true);
promptAsync({
useProxy,
windowFeatures: { width: 700, height: 600 },
});
}}
/>
</View>
);
}
function fixRedirectUri(redirectUri: string, forProxy?: boolean) {
if (forProxy) {
return redirectUri;
}
if (Platform.OS !== 'web' && !redirectUri.startsWith('fb')) {
return redirectUri;
}
if (Platform.OS === 'web' && redirectUri !== window.origin) {
return redirectUri;
}
return redirectUri + '/';
}
export const Facebook = React.memo(Facebook_);