15

This is my pubspec.yaml. I'm using Flutter:

  dependencies:
    flutter:
      sdk: flutter

    cupertino_icons: ^0.1.2
    http: ^0.11.3

    #Google Sign In
    google_sign_in: 3.0.3
    firebase_auth: ^0.5.18
    flutter_svg: ^0.5.0

I can authenticate fine, the Sign In structure works, however if I'm at the Google Sign In and I cancel Google's authentication flow by hitting the back button on my physical device (S7 Edge), the application locks up and returns this:

Exception has occurred.
PlatformException(sign_in_failed, Status{statusCode=ERROR, resolution=null}, null)

Here is the log of the situation. It seems to me as if it fails silently:

I/InputMethodManager(13050): startInputInner - mService.startInputOrWindowGainedFocus
D/ViewRootImpl@3c3c6cd[SignInHubActivity](13050): MSG_WINDOW_FOCUS_CHANGED 0
D/ViewRootImpl@3c3c6cd[SignInHubActivity](13050): MSG_WINDOW_FOCUS_CHANGED 1
V/InputMethodManager(13050): Starting input: tba=android.view.inputmethod.EditorInfo@4d4a683 nm : com.xYNP82hMsgxfvzA.pqfrontend ic=null
I/InputMethodManager(13050): startInputInner - mService.startInputOrWindowGainedFocus
D/ViewRootImpl@3c3c6cd[SignInHubActivity](13050): MSG_WINDOW_FOCUS_CHANGED 0
D/ViewRootImpl@a981422[MainActivity](13050): MSG_WINDOW_FOCUS_CHANGED 1
    V/InputMethodManager(13050): Starting input: tba=android.view.inputmethod.EditorInfo@5990000 nm : com.xYNP82hMsgxfvzA.pqfrontend ic=null
I/InputMethodManager(13050): startInputInner - mService.startInputOrWindowGainedFocus
I/FlutterActivityDelegate(13050): onResume setting current activity to this
D/OpenGLRenderer(13050): eglDestroySurface = 0x7cb041df50
D/ViewRootImpl@3c3c6cd[SignInHubActivity](13050): Relayout returned: old=[0,0][1440,2560] new=[0,0][1440,2560] result=0x5 surface={valid=false 0} changed=true
D/ViewRootImpl@3c3c6cd[SignInHubActivity](13050): dispatchDetachedFromWindow
D/InputEventReceiver(13050): channel 'a2e7010 com.xYNP82hMsgxfvzA.pqfrontend/com.google.android.gms.auth.api.signin.internal.SignInHubActivity (client)' ~ Disposing input event receiver.
D/InputEventReceiver(13050): channel 'a2e7010 com.xYNP82hMsgxfvzA.pqfrontend/com.google.android.gms.auth.api.signin.internal.SignInHubActivity (client)' ~NativeInputEventReceiver.

Haven't found any solutions online, can someone help me out?

Update: I just got an Exception notice in the logs:

E/flutter (13050): [ERROR:topaz/lib/tonic/logging/dart_error.cc(16)] Unhandled exception:
E/flutter (13050): PlatformException(sign_in_failed, Status{statusCode=ERROR, resolution=null}, null)
E/flutter (13050): #0      StandardMethodCodec.decodeEnvelope (package:flutter/src/services/message_codecs.dart:547:7)
E/flutter (13050): #1      MethodChannel.invokeMethod (package:flutter/src/services/platform_channel.dart:279:18)
E/flutter (13050): <asynchronous suspension>
E/flutter (13050): #2      GoogleSignIn._callMethod (package:google_sign_in/google_sign_in.dart:183:58)
E/flutter (13050): <asynchronous suspension>
E/flutter (13050): #3      GoogleSignIn._addMethodCall (package:google_sign_in/google_sign_in.dart:222:20)
E/flutter (13050): #4      GoogleSignIn.signIn (package:google_sign_in/google_sign_in.dart:293:48)
E/flutter (13050): #5      handleSignIn (file:///C:/Users/dark_/picquest-dev/pq_frontend/lib/src/services/auth.dart:9:62)
E/flutter (13050): <asynchronous suspension>
E/flutter (13050): #6      main (file:///C:/Users/dark_/picquest-dev/pq_frontend/lib/main.dart:18:10)
E/flutter (13050): <asynchronous suspension>
E/flutter (13050): #7      _startIsolate.<anonymous closure> (dart:isolate/runtime/libisolate_patch.dart:279:19)
E/flutter (13050): #8      _RawReceivePortImpl._handleMessage (dart:isolate/runtime/libisolate_patch.dart:165:12)

It points to my auth service which I wrote: Here's that:

import 'package:firebase_auth/firebase_auth.dart';
import 'package:google_sign_in/google_sign_in.dart';
import 'dart:async';

final GoogleSignIn _googleSignIn = GoogleSignIn();
final FirebaseAuth _auth = FirebaseAuth.instance;

Future<FirebaseUser> handleSignIn() async {
  final GoogleSignInAccount googleUser = await _googleSignIn.signIn();
  final GoogleSignInAuthentication googleAuth = await googleUser.authentication;

  final FirebaseUser user = await _auth.signInWithGoogle(
    accessToken: googleAuth.accessToken,
    idToken: googleAuth.idToken,
  );
  print("signed in " + user.displayName);
  return user;
}


Future<Null> handleSignOut() async {
  await _auth.signOut();
  await _googleSignIn.signOut();
}

Here's where that's called:

void main()  {
  //Default unauthenticated home page

  try {
    auth.handleSignIn();
  } catch(e) {
    print(e);
  }

  SystemChrome.setPreferredOrientations([
    DeviceOrientation.portraitUp,
    DeviceOrientation.portraitDown
    ]);

    runApp(new MaterialApp(
      title: 'Test',
      home: _defaultHome,
      theme: new ThemeData(
        primaryColor: Colors.white
      ),
      routes: <String, WidgetBuilder> {
        '/onboarding/basic-info': (BuildContext context) => new UserOnBoarding_BasicInfo_Page(),
        //'/onboarding/interests': (BuildContext context) => new UserOnBoarding_Interests_Page(),
        '/avatar-repository': (BuildContext context) => new AvatarRepositoryPage(),
        '/login': (BuildContext context) => new LoginPage(),
        '/app/settings': (BuildContext context) => new AppSettingsPage()
      },
    )
  );
} 
Ryan Bargholz
  • 163
  • 1
  • 1
  • 7

9 Answers9

13

You can capture the error using catchError like this:

      Future<FirebaseUser> handleSignIn() async {
        final GoogleSignInAccount googleUser =
            await _googleSignIn.signIn().catchError((onError) {
          print("Error $onError");
        });
        if (googleUser != null) {
          final GoogleSignInAuthentication googleAuth =
              await googleUser.authentication;
          final FirebaseUser user = await _auth
              .signInWithGoogle(
            accessToken: googleAuth.accessToken,
            idToken: googleAuth.idToken,
          )
              .catchError((onError) {
            print("error $onError");
          });
          if (user != null) {
            print("signed in " + user.displayName);
            return user;
          }
        }

        return null;
      }
diegoveloper
  • 93,875
  • 20
  • 236
  • 194
9

This error will not occur in release mode as said by @monojmnj I think this is error causing by IDE Because when you run your app in terminal there is no exception caused.

Omkar Sawant
  • 293
  • 3
  • 6
8

According to the comments on the signIn() function in google_sign_in.dart, request cancellation should return null instead of throwing a PlatformException:

/// Returned Future resolves to an instance of [GoogleSignInAccount] for a /// successful sign in or `null` in case sign in process was aborted.

I've raised an issue for this bug in the Flutter repository here

For now, you'll have to stick with catching the error manually

BuntagonalPrism
  • 409
  • 3
  • 6
  • Legend. I hope that bug gets fixed for others down the line. We pivoted from Flutter to Android Java for a number of reasons, one of which was this problem. – Ryan Bargholz Sep 23 '18 at 04:53
5

I can confirm that this issue still persists as of today (but only in debug mode),And when sign in cancelled in the release mode the app doesnt crash/freeze and continues to function,So I feel this is mostly with the ide that throws the exception and dart is not able to capture it.so till it gets fixed,so a simple workaround is to use the release version of the app.

Note: Make sure to sign the app and enter the hash in firebase console otherwise google signin wont work in release mode

Mahesh Jamdade
  • 17,235
  • 8
  • 110
  • 131
  • 1
    Yes, This is true. This works for me. Release APK will work fine. I think it's an IDE issue when it crashes. – Jay Tillu Nov 24 '20 at 14:38
1

I have also recently faced this error and, I have found out that the .catchError() callback wasn't being called in the debug mode (which is when you click the Run->Start Debugging button in VSCode).

However, when you type in flutter run -d , then, the .catchError() method gets called back as it is not in debug mode.

To get your preferred simulator's code paste this line of code in the terminal:

instruments -s devices

If that doesn't work, you can also try pasting this:

xcrun simctl list

The .catchError() method will get called unlike before and the code inside that will get executed as expected!

Additionally, the app won't crash anymore with a PlatformException() and instead you will get a log like this one:

[VERBOSE-2:ui_dart_state.cc(157)] Unhandled Exception: NoSuchMethodError: The getter 'uid' was called on null.
Receiver: null

I have been facing this problem in Google Sign In too, in which the .catchError() was not being called!

In conclusion, if you have some error with handling errors in Firebase Authentication, you should first try to first run in through the terminal. Thanks, and I hope this helps!

XtremeDevX
  • 1,482
  • 2
  • 13
  • 38
1

One workaround on interrupting the Google sign in flow I found here is to do the following:

Find the package: package:flutter/src/services/platform_channel.dart and change:

final Map<dynamic, dynamic> result = await invokeMethod<Map<dynamic, dynamic>>(method, arguments);
    return result?.cast<K, V>();

to:

try {
    final Map<dynamic, dynamic> result = await invokeMethod<Map<dynamic, dynamic>>(method, arguments);
    return result?.cast<K, V>();
} on PlatformException catch (err) { // Checks for type PlatformException
    if (err.code == 'sign_in_canceled') { // Checks for sign_in_canceled exception
        print(err.toString());
    } else {
        throw err; // Throws PlatformException again because it wasn't the one we wanted
    }
}
0

On my project case

Just run it via terminal, it happens when you run using vscode (f5), but when you run using flutter run on the terminal, the exception will not happen.

0

I was facing this issue with my release build as of today. Cancelling Google login in debug mode was working fine. After making a release build and also uploaded to TestFlight the App used to crash when ever I tried this functionality. Even my app got rejected from App store for this. I was not getting this issue with Android build thou. The only thing that fixed this bug was adding a null check. Even with try can catch the IoS App used to crash. Hope this helps someone in the same boat as me as it took 3 days for me figure this out and solve it

 try {
  // Trigger the authentication flow
  final GoogleSignInAccount? googleUser = await GoogleSignIn().signIn();
  if(googleUser == null){
    return LoginUserData(functionRespData: FunctionRespData( error: "login-error"));
  }

  // Obtain the auth details from the request
  final GoogleSignInAuthentication? googleAuth =
      await googleUser?.authentication;

  // Create a new credential
  final credential = GoogleAuthProvider.credential(
    accessToken: googleAuth?.accessToken,
    idToken: googleAuth?.idToken,
  );
  // UserCredential? userCredential = await FirebaseAuth.instance.currentUser
  //     ?.linkWithCredential(credential);
  // Once signed in, return the UserCredential
  UserCredential userCredential =
      await FirebaseAuth.instance.signInWithCredential(credential);

  return LoginUserData(userData:_userFromFirebase(userCredential.user));
} on FirebaseAuthException catch (e) {
  return LoginUserData(functionRespData: FunctionRespData(error: e.message));
} catch(e){
  return LoginUserData(functionRespData: FunctionRespData( error: "login-error"));
}
0

If you cancel the flow, the call to final GoogleSignInAccount googleUser = await _googleSignIn.signIn() returns a null value. The rest of the flow is dependent on the value not being null, so return early if that's the case.

final GoogleSignInAccount googleUser = await _googleSignIn.signIn()
if (googleUser == null) {
  return; // or throw an error
}
Taiwosam
  • 469
  • 7
  • 13