I have the following code that I am using to log a user in silently
try {
result = await GoogleSignIn().signInSilently().catchError((x) {
print(x);
});
} catch (e) {
print(e);
}
If the user cannot sign in silently, it results in an error.
PlatformException (PlatformException(sign_in_required, com.google.android.gms.common.api.ApiException: 4: 4: , null))
The problem I am having is that I cannot seem to catch the exception. catchError nor the catch block are being hit. How do I catch this error?
Do the following in your method
try {
result = await GoogleSignIn().signInSilently(suppressErrors: false).catchError((x) {
print(x);
});
} catch (e) {
print(e);
}
By default suppressErrors = true suppressing the error messages you want to catch.
Looking at the source code
The SignInSilently method is used to suppress error messages thus not throwing the exception you want to catch.
From the docs of this method:
/// When [suppressErrors] is set to `false` and an error occurred during sign in
/// returned Future completes with [PlatformException] whose `code` can be
/// either [kSignInRequiredError] (when there is no authenticated user) or
/// [kSignInFailedError] (when an unknown error occurred).
Full Method
/// Attempts to sign in a previously authenticated user without interaction.
///
/// Returned Future resolves to an instance of [GoogleSignInAccount] for a
/// successful sign in or `null` if there is no previously authenticated user.
/// Use [signIn] method to trigger interactive sign in process.
///
/// Authentication process is triggered only if there is no currently signed in
/// user (that is when `currentUser == null`), otherwise this method returns
/// a Future which resolves to the same user instance.
///
/// Re-authentication can be triggered only after [signOut] or [disconnect].
///
/// When [suppressErrors] is set to `false` and an error occurred during sign in
/// returned Future completes with [PlatformException] whose `code` can be
/// either [kSignInRequiredError] (when there is no authenticated user) or
/// [kSignInFailedError] (when an unknown error occurred).
Future<GoogleSignInAccount> signInSilently({bool suppressErrors = true}) {
final Future<GoogleSignInAccount> result = _addMethodCall('signInSilently');
if (suppressErrors) {
return result.catchError((dynamic _) => null);
}
return result;
}
Reference
Google Sign In Plugin Repo
Method Source Code Starting Line 283
This might help.
Checklists :
Did not register a sha fingerprint.
Make sure to have my "support email" set.
Enable the Google Sign-in method.
The catchError block is actually getting hit if you use suppressErrors = false
Try the following code and see what it prints on your console.
result = await GoogleSignIn().signInSilently(suppressErrors: false).
catchError((x) {
print("inside catchError");
});
The problem is the print(e); line in the catch statement. 'e' is not a string so an error occurs. I don't know why but no breakpoints are hit in the catch statement for this error and no error is output to the console. If I put a catch statement around a function that calls the login code ie.
void tryLogin(){
try{
myLoginLogic();
} catch(e) {
print(e);
}
}
Then I do get an error message
Unhandled Exception: type '_TypeError' is not a subtype of type 'String'
So to be clear the correct code would be
try {
result = await GoogleSignIn().signInSilently().catchError((e) {
print(e.toString());
});
} catch (e) {
print(e.toString());
}
Why code doesn't break on error and no message is written to the console for the original function I don't know. Also what I don't understand is why, even when the catch statement is written without errors, in debug mode the code breaks on the signInSilently() line.
Related
I am implementing Facebook Sign In with Firebase in my Flutter App, and when a user signs in with Facebook Sign In for the first time I am changing the "emailverified" property to true. I do this through functions with the following code:
if (facebookUser.user?.emailVerified == false) {
try {
HttpsCallable callable = FirebaseFunctions.instance.httpsCallable('verifyFacebook');
await callable.call();
} on FirebaseFunctionsException catch (e) {
print(e.code);
print(e.plugin);
print(e.message);
}
}
where verifyFacebook is:
exports.verifyFacebook = functions.auth.user().onCreate(async (snap) => {
return await admin.auth().updateUser(snap.uid, {
emailVerified: true
});
})
What I do not understand is that a Firebase Function Exception of "unauthenticated" is printed in the console, but when I sign in for the second time the "emailverified" property is changed to true (meaning that the Firebase Function was executed properly)! How could this happen if in the try-catch part I was thrown an error?
I searched for other answers such as adding a permission in Google Cloud Console but none helped me :(
Thanks in advance!
In Google Cloud Console I added "allUsers" in the Permission property, and I expected my app to work fine without the "unauthenticated" error. However, the issue persisted.
The verifyFacebook function triggers every time a user is created with Firebase Authentication and is not a callable function. You don't have to call the function yourself. When you try to call it, the callable function does not exists and hence you get an error but the function triggered by Firebase Auth does run.
I don't understand why I'm getting this error. It happens either on a virtual or real device. I try to uninstall the app and nothing change. Why a simple helloWord function throw this error. I have no console log displayed. In the log I have this message: "Request has invalid method. GET" then "Error: Invalid request, unable to process. at entryFromArgs..." Why redirect? Could it be related to the cloud region I change? How could I clean that. Thank you.
Below the cloud function.
exports.belleDiana = functions.region(CLOUD_REGION).https.onCall(async (data, context) : Promise<String> => {
console.log("belleDiana", data, context);
console.log("context.auth", context.auth?.uid, context);
return "belleDianaDone";
});
The call on flutter side.
try {
final result =
await FirebaseFunctions.instance.httpsCallable('belleDiana').call();
print("result: $result");
} on FirebaseFunctionsException catch (error) {
print(error);
print(error.code);
print(error.details);
print(error.message);
}
I switch to the original region 'us-central1'. When I change cloud region I have this message " Unhandled error cleaning up build images. This could result in a small monthly bill if not corrected. You can attempt to delete these images by redeploying or you can delete them manually at https://console.cloud.google.com/artifacts/docker/myproject/europe-west1/gcf-artifacts
"
After the deletion of that manually, every thing work as attended. I don't really understand why...
I made a https call in cloud functions and threw an error if a condition fails, in flutter i handled it successfully and it shows me this : PlatformException(functionsError, Cloud function failed with exception., {code: FAILED_PRECONDITION, details: null, message: Error: Your card was declined.})
but i want to know how i can get just the message part to display to the user? so far i already tried e.message but that didnt work
CloudFunctions(app: Firebase.app(), region: 'asia-southeast2')
.getHttpsCallable(functionName: 'addPayment')
.call({
'paymentMethodId': paymentMethod.id,
'userid': FirebaseAuth.instance.currentUser.uid,
}).catchError((e) => print('ERROR $e'));
this is my function
The PlatformException class has the following properties:
code → String An error code. final
details → dynamic Error details, possibly null. final
hashCode → int The hash code for this object. [...] read-only,
inherited
message → String A human-readable error message, possibly null.
final
runtimeType → Type A representation of the runtime type of the
object. read-only, inherited
To handle it you would do:
.catchError((e) {
if (e is PlatformException){
// Show e.details['message']
}else{
print('ERROR $e');
}
});
.catchError((error) {
String errorMessage = error.toString();
if (error is PlatformException &&
error.message != null &&
error.message!.isNotEmpty) {
errorMessage = error.message!;
}
}
I have a firebase cloud function to create a user document with user data whenever a user registers. How would I return an error when the set() fails? Since this is not an http request (an I don't want to use an http request in this case) I have no response. So how would I catch errors?
export const onUserCreated = functions.region('europe-west1').auth.user().onCreate(async user => {
const privateUserData = {
phoneNumber: user.phoneNumber
}
const publicUserData = {
name: 'Nameless'
}
try
{
await firestore.doc('users').collection('private').doc('data').set(privateUserData);
}catch(error)
{
//What do I put here?
}
try
{
await firestore.doc('users').collection('public').doc('data').set(publicUserData);
}catch(error)
{
//What do I put here?
}
});
You can't "return" an error, since the client doesn't even "know" about this function running, there is nobody to respond to.
You can make a registration collection, and in your function make a document there for the current user (using the uid as the document id). In that document, you can put any information you'd like your user to know (status, errors, etc).
So your clients would have to add a listener to this document to learn about their registration.
In your particular code, I think the error is in doc('users'). I guess you meant doc('users/'+user.uid).
Your catch -block will receive errors that occur on your set -call:
try {
await firestore.doc('users').collection('public').doc('data').set(publicUserData);
} catch (error) {
// here you have the error info.
}
I need to trap all of the listed PurchasesErrorCode error codes in my Flutter app so I can respond to them accordingly.
Currently I can only trap "userCancelled", for everything else I can only report the information returned in the standard PlatformException code, message and details properties, without knowing what they will contain.
try {
// Code to make purchase..
} on PlatformException catch (e) {
if (!(e.details as Map)["userCancelled"]) {
// Here I need a comprehensive switch statement so I can
// retry where appropriate/control what messages the user sees
String reason = '';
(e.details as Map).forEach((k,v) => reason += '$k => $v');
showError(context, 'Error', '${e.code} : ${e.message}');
} else {
showError(context, 'Purchase Cancelled', 'Your purchase was not completed, you have not been charged.');
}
}
These codes are exposed in IOS/Swift and Android/Kotlin but I can't get them in Flutter/Dart - what am I missing?
I developed the RevenueCat Flutter plugin and I created an issue on GitHub some time ago to track this (https://github.com/RevenueCat/purchases-flutter/issues/3). I am sorry there is some room for improvement in our Flutter error handling.
When we send the platform exceptions we pass the error code as an String:
result.error(error.getCode().ordinal() + "", error.getMessage(), userInfoMap);
Too bad we can't just pass an int as the first parameter and we have to pass a String, I guess we could pass it in the userInfoMap. But for now, since we are not providing the enum with the error codes yet, you would have to do something like this in your code:
enum PurchasesErrorCode {
UnknownError,
PurchaseCancelledError,
StoreProblemError,
PurchaseNotAllowedError,
PurchaseInvalidError,
ProductNotAvailableForPurchaseError,
ProductAlreadyPurchasedError,
ReceiptAlreadyInUseError,
InvalidReceiptError,
MissingReceiptFileError,
NetworkError,
InvalidCredentialsError,
UnexpectedBackendResponseError,
ReceiptInUseByOtherSubscriberError,
InvalidAppUserIdError,
OperationAlreadyInProgressError,
UnknownBackendError,
InsufficientPermissionsError
}
try {
} on PlatformException catch (e) {
PurchasesErrorCode errorCode = PurchasesErrorCode.values[int.parse(e.code)];
switch (errorCode) {
case PurchasesErrorCode.UnknownError:
case PurchasesErrorCode.PurchaseCancelledError:
case PurchasesErrorCode.StoreProblemError:
// Add rest of cases
}
}
When you do e.details, you also get access to a readableErrorCode containing the name of the error code; and an underlyingErrorMessage, that can hopefully help you debug any issue.
I hope that helps
The issue mentioned on the previous answer was solved, after version 1.0.0 you can handle like this:
try {
PurchaserInfo purchaserInfo = await Purchases.purchasePackage(package);
} on PlatformException catch (e) {
var errorCode = PurchasesErrorHelper.getErrorCode(e);
if (errorCode == PurchasesErrorCode.purchaseCancelledError) {
print("User cancelled");
} else if (errorCode == PurchasesErrorCode.purchaseNotAllowedError) {
print("User not allowed to purchase");
}
}