expo: [expo-facebook] requestPermissionsAsync model doesn't close

Summary

I was trying to make the facebook authentication on a manage workflow. So i implemented the method as the documentation said. It works perfectly on Expo go.

In standalone app, if safari has not logged in to facebook. The sdk will prompt the screen asking you if you want to make login with facebook app. Once i logged in with facebook app, facebook app redirects back the modal that was previously open never get closed so the authentication never completes.

Managed or bare workflow? If you have ios/ or android/ directories in your project, the answer is bare!

managed

What platform(s) does this occur on?

iOS

SDK Version (managed workflow only)

41

Environment

  Expo CLI 4.9.1 environment info:
    System:
      OS: macOS 11.4
      Shell: 5.8 - /bin/zsh
    Binaries:
      Node: 12.16.3 - ~/.nvm/versions/node/v12.16.3/bin/node
      Yarn: 1.22.10 - ~/.nvm/versions/node/v12.16.3/bin/yarn
      npm: 6.14.7 - ~/.nvm/versions/node/v12.16.3/bin/npm
    Managers:
      CocoaPods: 1.10.1 - /usr/local/bin/pod
    SDKs:
      iOS SDK:
        Platforms: iOS 14.5, DriverKit 20.4, macOS 11.3, tvOS 14.5, watchOS 7.4
    IDEs:
      Android Studio: 4.2 AI-202.7660.26.42.7351085
      Xcode: 12.5.1/12E507 - /usr/bin/xcodebuild
    npmPackages:
      expo: ~41.0.1 => 41.0.1 
      react: 16.13.1 => 16.13.1 
      react-dom: 16.13.1 => 16.13.1 
      react-native: https://github.com/expo/react-native/archive/sdk-41.0.0.tar.gz => 0.63.2 
      react-native-web: ~0.13.12 => 0.13.18 
    npmGlobalPackages:
      expo-cli: 4.9.1
    Expo Workflow: managed

Reproducible demo or steps to reproduce from a blank project

import React from 'react';
import { StyleSheet, Text, View, TouchableWithoutFeedback, Alert } from 'react-native';
import * as Facebook from 'expo-facebook';

export default function App({props}) {
  
  const fbLogin = async () => {

    try {
      console.log('abc111123')
      await Facebook.initializeAsync({
        appId: 'xxxxxxx',
      });
      const {
        type,
        token,
        expirationDate,
        permissions,
        declinedPermissions,
      } = await Facebook.logInWithReadPermissionsAsync({
        permissions: ['public_profile', 'email']
      });
      
      if (type === 'success') {
        // Get the user's name using Facebook's Graph API

        Alert.alert('Logged in!', `Hi ${token}!`);
      } else {
        // type === 'cancel'
      }
    } catch ({ message }) {
      Alert.alert(`Facebook Login Error: ${message}`);
    }
  
  }

  return (
    <View style={styles.container}>
      <Text>Open up App.js to start working on your app!</Text>
      <TouchableWithoutFeedback onPress={() => {
        fbLogin()
      }}><Text>Login</Text></TouchableWithoutFeedback>
      <StatusBar style="auto" />
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#fff',
    alignItems: 'center',
    justifyContent: 'center',
  },
});

About this issue

  • Original URL
  • State: closed
  • Created 3 years ago
  • Reactions: 6
  • Comments: 50 (18 by maintainers)

Most upvoted comments

This is my solution for EAS. Hope this helps someone.

// plugins/ios/with-facebook.js
const { WarningAggregator, withAppDelegate } = require('@expo/config-plugins');

const linkingBlock =
  '- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options {';

function modifyAppDelegate(appDelegate) {
  if (appDelegate.includes(linkingBlock)) {
    const integratedBlock =
      linkingBlock +
      `
      NSString *fbScheme = [NSString stringWithFormat:@"fb%@", NSBundle.mainBundle.infoDictionary[@"FacebookAppID"]];
      if ([[url scheme] isEqualToString:fbScheme]) {
          return [super application:application openURL:url options:options];
      }
    `;
    appDelegate = appDelegate.replace(linkingBlock, integratedBlock);
  }

  return appDelegate;
}

exports.withFacebook = (config) => {
  return withAppDelegate(config, (config) => {
    if (config.modResults.language === 'objc') {
      config.modResults.contents = modifyAppDelegate(
        config.modResults.contents
      );
    } else {
      WarningAggregator.addWarningIOS(
        'withFacebook',
        'Swift AppDelegate files are not supported yet.'
      );
    }
    return config;
  });
};
// plugins/index.js
const { withFacebook } = require('./ios/with-facebook');

module.exports = function withCustomPlugins(config, props) {
  config = withFacebook(config);
  return config;
};
// app.json
{
  ...,
  "plugins": ["./plugins", ...]
}

anyone fixed this issue?

As a temporary measure, I modified the facebook app to not run by using the InfoPlist mod plugin and it works as expected. However it’s not a real solution.

const withInfoPlist = require('@expo/config-plugins').withInfoPlist;
const fbSchemes = ['fbapi', 'fb-messenger-api', 'fbauth2', 'fbshareextension'];

module.exports = function withFacebook(config) {
  return withInfoPlist(config, (config) => {
    const existingSchemes = config.modResults.LSApplicationQueriesSchemes || [];

    for (const scheme of fbSchemes) {
      const index = existingSchemes.findIndex((s) => s === scheme);

      if (index > -1) {
        existingSchemes.splice(index, 1);
      }
    }

    config.modResults.LSApplicationQueriesSchemes = [...existingSchemes];

    return config;
  });
};

Try creating something like with-facebook.js and then in your config plugins: ['./with-facebook']

@jkk could you please explain how to implement your workaround in standalone apps? Seems like I will have to implement it, considering that this issue may be here around 2 or 3 more years (that’s the average of time I wait for features in Expo. Like the in-app payment).

Thank you so much!

😃, ok man… hope someone will help you too with your problem.

I checked and I think it’s not that different. Note that the production of my app is currently expo 40, and Facebook works well(same code).

+1 same issue on ios with expo 42 (eas build)