0

I'm implementing a OTP phone verification through Firebase Authentication with Flutter. On Android it works like a charm, but in the other hand, on iOS I can't make it work. This is the error that I'm getting:

Notice that I'm using OneSignal and it works fine in both on Android and iOS

flutter: Phone number verification failed. Code: verifyPhoneNumberError. Message: If app delegate swizzling is disabled, remote notifications received by UIApplicationDelegate need to be forwarded to FIRAuth's canHandleNotificaton: method.

My flutter doctor:

enter image description here

My CocoaPods:

enter image description here

My OPT Function on Flutter:

import 'package:firebase_auth/firebase_auth.dart';

class SMSFunctions {
  /// Sends the code to the specified phone number.
  static Future<void> sendCodeToPhoneNumber(
      String phoneNo, Function onSuccess, Function onFailed) async {
    FirebaseAuth.instance.signOut();

    final PhoneVerificationCompleted verificationCompleted =
        (AuthCredential user) {
      print(
          'Inside _sendCodeToPhoneNumber: signInWithPhoneNumber auto succeeded: $user');
    };

    final PhoneVerificationFailed verificationFailed =
        (AuthException authException) {
      print(
          'Phone number verification failed. Code: ${authException.code}. Message: ${authException.message}');
      onFailed();
    };

    final PhoneCodeSent codeSent =
        (String verificationId, [int forceResendingToken]) async {
      verificationId = verificationId;
      print("code sent to " + phoneNo);
      onSuccess(verificationId);
    };

    final PhoneCodeAutoRetrievalTimeout codeAutoRetrievalTimeout =
        (String verificationId) {
      verificationId = verificationId;
      print("time out");
      onFailed();
    };

    await FirebaseAuth.instance.verifyPhoneNumber(
        phoneNumber: phoneNo,
        timeout: const Duration(seconds: 5),
        verificationCompleted: verificationCompleted,
        verificationFailed: verificationFailed,
        codeSent: codeSent,
        codeAutoRetrievalTimeout: codeAutoRetrievalTimeout);
  }

  static Future<bool> confirmSMS(String smsCode, String verificationId) async {
    print(smsCode);
    print(verificationId);
    final AuthCredential credential = PhoneAuthProvider.getCredential(
      verificationId: verificationId,
      smsCode: smsCode,
    );
    AuthResult authResult;
    try {
      authResult = await FirebaseAuth.instance.signInWithCredential(credential);
      print(authResult.user);
      final FirebaseUser currentUser = authResult.user;
      if (currentUser != null)
        return true;
      else
        return false;
    } catch (e) {
      print(e);
    }
    return false;
  }
}

Plugin Version:

firebase_auth: ^0.16.1

These are my tries so far:

  1. Modified my AppDelegate.swift, like in this post

import UIKit
import Flutter

@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
  override func application(
    _ application: UIApplication,
    didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
  ) -> Bool {
    GeneratedPluginRegistrant.register(with: self)
    return super.application(application, didFinishLaunchingWithOptions: launchOptions)
  }

  func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
    // Pass device token to auth
    Auth.auth().setAPNSToken(deviceToken, type: .prod)

  }

  func application(_ application: UIApplication,
      didReceiveRemoteNotification notification: [AnyHashable : Any],
      fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
    if Auth.auth().canHandleNotification(notification) {
      completionHandler(.noData)
      return
    }
    // This notification is not auth related, developer should handle it.
  }

  // For iOS 9+
  func application(_ application: UIApplication, open url: URL,
      options: [UIApplicationOpenURLOptionsKey : Any]) -> Bool {
    if Auth.auth().canHandle(url) {
      return true
    }
    // URL not auth related, developer should handle it.
  }

  // For iOS 8-
  func application(_ application: UIApplication,
                  open url: URL,
                  sourceApplication: String?,
                  annotation: Any) -> Bool {
    if Auth.auth().canHandle(url) {
      return true
    }
    // URL not auth related, developer should handle it.
  }

  func scene(_ scene: UIScene, openURLContexts URLContexts: Set<UIOpenURLContext>) {
    for urlContext in URLContexts {
        let url = urlContext.url
        Auth.auth().canHandle(url)
    }
    // URL not auth related, developer should handle it.
  }

  func application(_ application: UIApplication,
                  didReceiveRemoteNotification notification: [AnyHashable : Any],
                  fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
    if Auth.auth().canHandleNotification(notification) {
        completionHandler(.noData)
        return
    }
    // This notification is not auth related, developer should handle it.
    handleNotification(notification)
  }



}

  1. Tried changing the FirebaseAuth plugin version, like in this post
  2. Changed my URLSCHEMES, like in this post

    My google.services-info.plist (Copied the yellow stripe) enter image description here

    My info.plist URL SCHEMES (Pasted the yellow stripe) //Note that the second item is the Facebook URL SCHEME my URLSCHEMES

  3. Changed my FirebaseAppDelegateProxyEnabled, like in this post

enter image description here

  1. Configured my Firebase APNs Auth Key and the reCAPTCHA verification, following the Google Docs

    enter image description here

enter image description here

  1. Configured my Signing & Capabilities on Xcode

enter image description here

Vitor
  • 762
  • 6
  • 26

1 Answers1

1

I had exact issue and I made some change and it fixed using below code.

AppDelegate.swift

import UIKit
import Flutter
import Firebase
import FirebaseAuth
import UserNotifications
import FirebaseInstanceID

@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
  override func application(
    _ application: UIApplication,
    didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
  ) -> Bool {
        FirebaseApp.configure()
        GeneratedPluginRegistrant.register(with: self)
        if #available(iOS 10.0, *) {
          UNUserNotificationCenter.current().delegate = self as? UNUserNotificationCenterDelegate
        }
        return true
  }
    override func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
        let firebaseAuth = Auth.auth()
        firebaseAuth.setAPNSToken(deviceToken, type: AuthAPNSTokenType.unknown)

    }
    override func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
        let firebaseAuth = Auth.auth()
        if (firebaseAuth.canHandleNotification(userInfo)){
            print(userInfo)
            return
        }

    }
}

Info.plist I added below lines

<key>FirebaseAppDelegateProxyEnabled</key>
<false/>

I got reference from the below link. [https://pub.dev/packages/firebase_messaging][1]

sunita
  • 470
  • 1
  • 6
  • 22
  • 1
    I'm getting this error while trying to build: `no module firebase instance id ` do you know what can i do to solve it? – Vitor Jul 13 '20 at 13:59
  • 1
    I tried many many solutions and yours was the only one that helped. Can't thank you enough. I can finally sleep with peace. Thanks a ton and a bit more!! – Hashir Baig Dec 26 '20 at 22:13