jeduan / cordova-plugin-facebook4

Use the latest Facebook SDK in your Cordova and Ionic projects
Other
765 stars 510 forks source link

Login with Facebook does not work on iOS 13.1.3 #826

Closed andreas-aeschlimann closed 3 years ago

andreas-aeschlimann commented 4 years ago

Bug

[X] I'm reporting a reproducible issue with the code [ ] I'm reporting a feature request

Describe the bug

Since I upgraded to iOS 13, the "login with Facebook" does not seem to work anymore in my Ionic Angular 4 app using Capacitor.

Please note that I can only have issues on iOS 13. On a phone with iOS 12 there is no problem. Thus, I assume there must be a bug with the plugin on iOS 13.

In my limited understanding, the issue is related to the way how the plugin uses the web browser tab within the app.

Detailed description of what I see on iOS 13:

  1. Once I start the login process, a tab with the Facebook Login opens. As of iOS 13, this page does not cover the whole app anymore, it is slightly shifted down. I suppose this is just a new design choice by Apple how to display the in-app browser tab:

IMG_0235

  1. When I then click "Open with Facebook", the Facebook app opens up as expected.

  2. After authorizing my app for the login, Facebook sends me back to my app. This is expected as well.

  3. When my app opens again, the tab with the web login of Facebook is still here (as in the image above). It does not close unless I click Cancel on the top left, which leads to an error User cancelled.. I am not able to access the FacebookLoginResponse object inside my app (see code below).

Expected Behavior

Step 3 should return to the app instead to the FB web login.

Versions

Code

    console.log("[ Trying to login with Facebook ... ]");

    this.facebook.login(["public_profile"]).then(
        (response: FacebookLoginResponse) => {
            console.log("[ Facebook login succeeded with userID: " + response.authResponse.userID + " ]");
        }
    ).catch(
        (error: string) => {
            console.error("[ Facebook login error: " + error + " ]");
    );
peterpeterparker commented 4 years ago

Nothing we could do I think on the plugin side I think. It's either a Facebook SDK problem or something related to your app I would say, like what happened with #819

andreas-aeschlimann commented 4 years ago

I have seen this issue, but I think it's different. In #819 the problem is that the FB app is not used, but the login still works. In my case, the app is indeed opened, but the result not properly returned to the app.

I honestly don't know what could be the issue because it works on iOS 12 and Android. Would you look at it if I created a sample repo that reproduces the error?

peterpeterparker commented 4 years ago

Like I said, I think that the problem isn't on the plugin side but I'm happy to merge any PR if that would not be the case

andreas-aeschlimann commented 4 years ago

Doesn't the plugin handle the opening and closing of the browser tab? I cannot imagine that this is on the part of the SDK.

Otherwise it could only be Ionic itself, but as I don't have any insight in this plugin or Ionic, I cannot say that.

andreas-aeschlimann commented 4 years ago

I can't believe it, but I actually fixed it. I'll list the steps so other people might profit from my findings as well...

An issue on the FBSDK GitHub page has a longer discussion about the login on iOS 13: https://github.com/facebook/facebook-ios-sdk/issues/1067

You have to follow their updated guide and implement all steps, especially the ones in your AppDelegate.m/AppDelegate.swift file from here: https://developers.facebook.com/docs/ios/getting-started

On Ionic 4 using Capacitor (it uses Swift), this is what I had to do in order to fix the iOS 13 problem:

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
    // Add FBSDK fix
    ApplicationDelegate.shared.application(application, didFinishLaunchingWithOptions: launchOptions);
    return true
}

func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
    // Add FBSDK fix
    return ApplicationDelegate.shared.application(app, open: url, options: options)
    //return CAPBridge.handleOpenUrl(url, options)
}
peterpeterparker commented 4 years ago

@andreas-aeschlimann cool to hear you solved the issue 👍

my guess was no but now that you have found the solution, do you think we could solve this within the plugin?

if yes, could you provide a PR?

if no, I guess it would be cool to have something in the documentation. could you provide a PR to add something in the documentation regarding your findings?

andreas-aeschlimann commented 4 years ago

Is it even possible to provide a solution that is needed in the AppDelegate of the host app? I guess all we can do is provide the documentation to hint the users to implement the necessary code parts.

peterpeterparker commented 4 years ago

Maybe a post script or something? But agree with you, maybe, at least for now, providing a documentation/hint is what would be good to do. If you've got a bit of time to provide this that would be neat

andreas-aeschlimann commented 4 years ago

I have to work on something else now, but I hope I will find some time soon. Feel free to keep the issue open.

peterpeterparker commented 4 years ago

super, let's do that. thx in advance @andreas-aeschlimann 👍

AmrAbdalrahman commented 4 years ago

also does not work on IOS 12.3.1.

@andreas-aeschlimann thanks a lot for your attention and help

I use Cordova-ios less than 5 with ionic 3 and Cordova 8

my AppDelegate.m in Xcode is

/*
 Licensed to the Apache Software Foundation (ASF) under one
 or more contributor license agreements.  See the NOTICE file
 distributed with this work for additional information
 regarding copyright ownership.  The ASF licenses this file
 to you under the Apache License, Version 2.0 (the
 "License"); you may not use this file except in compliance
 with the License.  You may obtain a copy of the License at

 http://www.apache.org/licenses/LICENSE-2.0

 Unless required by applicable law or agreed to in writing,
 software distributed under the License is distributed on an
 "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 KIND, either express or implied.  See the License for the
 specific language governing permissions and limitations
 under the License.
 */

//
//  AppDelegate.m
//  Ekshefonline
//
//  Created by ___FULLUSERNAME___ on ___DATE___.
//  Copyright ___ORGANIZATIONNAME___ ___YEAR___. All rights reserved.
//

#import "AppDelegate.h"
#import "MainViewController.h"
#import <FBSDKCoreKit/FBSDKCoreKit.h>

@implementation AppDelegate

- (BOOL)application:(UIApplication*)application didFinishLaunchingWithOptions:(NSDictionary*)launchOptions
{
    self.viewController = [[MainViewController alloc] init];
    return [super application:application didFinishLaunchingWithOptions:launchOptions];
}

- (BOOL)application:(UIApplication *)application
            openURL:(NSURL *)url
            options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options {

    BOOL handled =  [[FBSDKApplicationDelegate sharedInstance] application:application openURL:url options:options]
    ;
    // Add any custom logic here.
    return handled;
}

@end
rtomasik commented 4 years ago

Facebook sdk is fixed

https://github.com/facebookarchive/facebook-swift-sdk/issues/482

peterpeterparker commented 4 years ago

@rtomasik it's unclear to me if it is fixed in a newer Fb SDK as the one referenced currently by the plugin (v5.7.0) or if it's already fixed with it.

what's your guess? if with a never version, have you give it a try and could you provide a PR to bump up the version?

ghost commented 4 years ago

See my post here for the solution to this - its pretty simple: https://github.com/facebook/facebook-ios-sdk/issues/1067#issuecomment-559629930

With the latest SDK, this does work fine if you are at NOT using SceneDelegate.

If you are using sceneDelegate the the following AppDelegate method is not called and therefore the login cannot be handled.

func application(_ application: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
    let handled = ApplicationDelegate.shared.application(
        application,
        open: url,
        sourceApplication: options[UIApplication.OpenURLOptionsKey.sourceApplication] as? String,
        annotation: options[UIApplication.OpenURLOptionsKey.annotation])
    return handled
}

This is because, this method is (understandably) deferred to the following method in the SceneDelegate:

func scene(_ scene: UIScene, openURLContexts URLContexts: Set<UIOpenURLContext>) {
    ...
}

The solution which I can confirm as working for iOS 13 applications implementing a SceneDelegate is:

func scene(_ scene: UIScene, openURLContexts URLContexts: Set<UIOpenURLContext>) {
    guard let url = URLContexts.first?.url else {
        return
    }
    let _ = ApplicationDelegate.shared.application(
        UIApplication.shared,
        open: url,
        sourceApplication: nil,
        annotation: [UIApplication.OpenURLOptionsKey.annotation])        
}
chaoticvibe commented 4 years ago

This's solved or not solved?

AlexMiniApps commented 4 years ago

@makveli this is not solved on the latest version of the plugin (6.3.0). But my workaround should help.

The worked solution (Tested on Ionic 4+) for the iOS 13.

In the file, FacebookConnectPlugin.m add the strings to the method - (void)pluginInitialize {

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleOpenURLWithAppSourceAndAnnotation:) name:CDVPluginHandleOpenURLWithAppSourceAndAnnotationNotification object:nil];

and then add the new method:

- (void) handleOpenURLWithAppSourceAndAnnotation:(NSNotification *) notification {
    NSMutableDictionary * options = [notification object];
    NSURL* url = options[@"url"];

    [[FBSDKApplicationDelegate sharedInstance] application:[UIApplication sharedApplication] openURL:url options:options];
}

together in the file:

@implementation FacebookConnectPlugin

- (void)pluginInitialize {
    NSLog(@"Starting Facebook Connect plugin");

    // Add notification listener for tracking app activity with FB Events
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(applicationDidFinishLaunching:)
                                                 name:UIApplicationDidFinishLaunchingNotification object:nil];

    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(applicationDidBecomeActive:)
                                                 name:UIApplicationDidBecomeActiveNotification object:nil];

    [[NSNotificationCenter defaultCenter] addObserver:self
                                              selector:@selector(handleOpenURLWithAppSourceAndAnnotation:)
                                                  name:CDVPluginHandleOpenURLWithAppSourceAndAnnotationNotification object:nil];
}

- (void) applicationDidFinishLaunching:(NSNotification *) notification {
    NSDictionary* launchOptions = notification.userInfo;
    if (launchOptions == nil) {
        //launchOptions is nil when not start because of notification or url open
        launchOptions = [NSDictionary dictionary];
    }

    [[FBSDKApplicationDelegate sharedInstance] application:[UIApplication sharedApplication] didFinishLaunchingWithOptions:launchOptions];
}

- (void) applicationDidBecomeActive:(NSNotification *) notification {
    [FBSDKAppEvents activateApp];
    if (self.applicationWasActivated == NO) {
        self.applicationWasActivated = YES;
        [self enableHybridAppEvents];
    }
}

- (void) handleOpenURLWithAppSourceAndAnnotation:(NSNotification *) notification {
    NSMutableDictionary * options = [notification object];
    NSURL* url = options[@"url"];

    [[FBSDKApplicationDelegate sharedInstance] application:[UIApplication sharedApplication] openURL:url options:options];
}

#pragma mark - Cordova commands

I think the code above should be added to this plugin.

jonasmeier1212 commented 4 years ago

@AlexMiniApps Thanks, that works!

ihsanberahim commented 4 years ago

things that @andreas-aeschlimann mention explain in the documentation from facebook.

just to add on,

in order to use ApplicationDelegate. You have to import FBSDKCoreKit.

joplaete commented 4 years ago

should @AlexMiniApps solution be rolled into the plugin?

bcrigler commented 4 years ago

Fix here for AppDelegate.swift (if using swift which I did not find in the answers) I'm also using Capacitor 1.5.2 not Cordova.


import UIKit
import Capacitor
import BugBattle
import FBSDKCoreKit

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

  var window: UIWindow?

  func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
    // Override point for customization after application launch.
    ApplicationDelegate.shared.application(application, didFinishLaunchingWithOptions: launchOptions);
    // Initialize BugBattle
    BugBattle.initWithToken("5eb174be521871518eb0ab63", andActivationMethod: SHAKE)

    return true
  }
func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
    // Add FBSDK fix
    return ApplicationDelegate.shared.application(app, open: url, options: options)
}```
kleeb commented 4 years ago

@AlexMiniApps any plans for creating PR ? I was able too reproduce this bug on iOS 12.4.3. Your code fixes the loop properly.

AlexMiniApps commented 4 years ago

@kleeb As I know the PR already created - https://github.com/jeduan/cordova-plugin-facebook4/pull/860

rareplanet1 commented 3 years ago

Also happening using cordova-ios@6.1.1 cordova-plugin-facebook4@6.4.0 Reproduced on iOS 14.2 on iPhone 12 mini and iPhone 7 Plus

noahcooper commented 3 years ago

This plugin is deprecated. Check out cordova-plugin-facebook-connect. I've included the changes from the PR by @jonasmeier1212:

https://www.npmjs.com/package/cordova-plugin-facebook-connect