FIrebaseAuth verifyPhoneNumber crash in flutter IOS - ios

I got this error when i call verifyPhoneNumber method:
My code works fine in android. Only in IOS it throws me this error. I checked a lot of issues on stackoverflow and github and have made sure that my GoogleService-Info.plist is in the right folder. I imported GoogleService-Info.plist through Xcode only and it is also added in CopyBundleResources section in Xcode-> Runner -> BuildPhases. Also a lot of places I saw that I need to add REVERSED_CLIENT_ID in URL Types in Xcode. Done this and also checked Info.plist that my REVERSED_CLIENT_ID is added correctly.
I have done everything but still don't know what is causing the issue.
My code for mobile auth:
import 'package:firebase_auth/firebase_auth.dart';
import 'package:[**package_name**]/functions/typedef.dart';
import 'package:[**package_name**]/helpers/log_helper.dart';
class MobileAuth{
MobileAuth(
this.mobileNumber,
this.afterCodeSent,
this.verificationCompleted,
this.verificationFailed,
this.autoTimeout,
this.ifOtpFailed,
this.afterOtpSend);
final String mobileNumber;
final AfterCodeSent afterCodeSent;
final PhoneAuthVerificationCompleted verificationCompleted;
final PhoneAuthVerificationFailed verificationFailed;
final AuthFailedMessage autoTimeout;
final AuthFailedMessage ifOtpFailed;
final AfterOtpSend afterOtpSend;
FirebaseAuth auth = FirebaseAuth.instance;
/// to sent the code to the given mobile number
void initialAuth() async{
await auth.verifyPhoneNumber(
phoneNumber: mobileNumber,
verificationCompleted: (PhoneAuthCredential credential) {
verificationCompleted(credential);
},
verificationFailed: (FirebaseAuthException e) {
verificationFailed(e);
},
codeSent: (String verificationId, int? resendToken) {
afterCodeSent(verificationId, resendToken ?? 0);
},
timeout: const Duration(seconds: 15),
codeAutoRetrievalTimeout: (String verificationId) {
autoTimeout(verificationId);
},
);
}
/// check otp by submitting to the auth api
void verifyOtp(String smsCode, String verificationId) async{
// Create a PhoneAuthCredential with the code
PhoneAuthCredential credential = PhoneAuthProvider.credential(verificationId: verificationId, smsCode: smsCode);
// Sign the user in (or link) with the credential
try{
UserCredential userCredential = await auth.signInWithCredential(credential);
LogHelper.log("After sending OTP: ${userCredential.user?.uid}");
afterOtpSend(userCredential);
}catch(e){
LogHelper.log("After sending OTP ${e.toString()}");
ifOtpFailed(e.toString());
}
}
void resendVerificationCode(int token) {
auth.verifyPhoneNumber(
forceResendingToken: token,
phoneNumber: mobileNumber,
verificationCompleted: (PhoneAuthCredential credential) {
verificationCompleted(credential);
},
verificationFailed: (FirebaseAuthException e) {
verificationFailed(e);
},
codeSent: (String verificationId, int? resendToken) {
afterCodeSent(verificationId , resendToken ?? 0);
},
timeout: const Duration(seconds: 60),
codeAutoRetrievalTimeout: (String verificationId) {
autoTimeout(verificationId);
},
);
}
}
And i call this in my statefull widget init method like this:
#override
void initState(){
String mobileNumber = "${widget.countryCode} ${widget.phoneNumber}";
mobileAuth = MobileAuth(mobileNumber, afterCodeSent,
verificationCompleted, verificationFailed, autoTimeout, ifOtpFailed, afterOtpSend);
sendOtpToPhone();
}
void sendOtpToPhone(){
mobileAuth.initialAuth();
}
The code works fine in android debug and release mode, so I only have this issue in IOS. Crashes when I call sendOtpToPhone(); -> mobileAuth.initialAuth(); -> auth.verifyPhoneNumber();
I have know for sure that auth.verifyPhoneNumber(); is only causing the error, because if I comment that segment of code then no crash is happening.
Also have tried flutter clean and i am using firebase_auth: 3.3.16 . Also tried it with 3.3.14.

Related

Expo React Native app. Error using expo-secure-store methods [The method or property SecureStore.setItemAsync is not available on ios]

I've followed expo documentation to include this library to my expo managed react native application. SecureStore
I am using:
expo: 44.0.5
react-native: 0.64.3 (SDK 44)
expo-secure-store: 11.1.0
expo-dev-client: 0.8.6
react & react-dom 18.0.0
typescript
In my App.tsx:
import 'expo-dev-client'
import { deleteValueFor, getValueFor, save } from './src/core/infrastructure/storage/secureStore'
import { REFRESH_TOKEN } from './src/core/infrastructure/config/constants'
....
export default function App(): JSX.Element | null {
....
useEffect(() => {
;(async () => {
try {
const refreshToken = await getValueFor(REFRESH_TOKEN)
...
// things I do whit refreshToken
...
} catch (e) {
console.warn(e)
}
})()
}, [])
const login = async (authUser: AuthUser) => {
const { token, refreshToken, user } = authUser
if (!user) {
throw 'Error al obtener los datos del usuario desde el context'
}
setToken(token)
save({ key: REFRESH_TOKEN, value: refreshToken }) // <---- The error occurs here
}
}
In secureStore.ts
import * as SecureStore from 'expo-secure-store'
export async function save({ key, value }: { key: string; value: string }): Promise<void> {
await SecureStore.setItemAsync(key, value)
}
export async function getValueFor(key: string): Promise<string | null> {
try {
return await SecureStore.getItemAsync(key)
} catch (error) {
return null
}
}
export async function deleteValueFor(key: string): Promise<void> {
await SecureStore.deleteItemAsync(key)
}
export async function checkAvailability(): Promise<boolean> {
return SecureStore.isAvailableAsync()
}
I execute this command to run the app in simulator:
expo start --dev-client --ios
The application is running fine inside the simulator, no errors with that. And after I fill login credentials and press in login button, this is the error message I'm getting:
[Unhandled promise rejection: Error: The method or property SecureStore.setItemAsync is not available on ios, are you sure you've linked all the native dependencies properly?]
at http://192.168.1.3:8082/node_modules/expo/AppEntry.bundle?platform=ios&dev=true&hot=false&strict=false&minify=false:111339:321 in _createSuperInternal
at node_modules/expo-modules-core/build/errors/CodedError.js:10:8 in constructor
at http://192.168.1.3:8082/node_modules/expo/AppEntry.bundle?platform=ios&dev=true&hot=false&strict=false&minify=false:111384:321 in _createSuperInternal
at node_modules/expo-modules-core/build/errors/UnavailabilityError.js:9:42 in constructor
at node_modules/expo-secure-store/build/SecureStore.js:103:14 in setItemAsync
at node_modules/expo-secure-store/build/SecureStore.js:97:7 in setItemAsync
at src/core/infrastructure/storage/secureStore.ts:4:8 in save
at src/core/infrastructure/storage/secureStore.ts:3:7 in save
at App.tsx:87:4 in login
I don't know what's wrong. Please help.
If anybody is working on a similar issue.
According to this issue
https://github.com/expo/expo/issues/16906
I had to rebuild my application due to expo-dev-client lib I'd being using in order to generate a new artifact. After that I could save my token using the expo-secure-store functions without problem.
I've fixed the error with replacing the expo package with:
https://github.com/react-native-async-storage/async-storage
The other alternatives are:https://reactnative.directory/?search=storage

No payment sheet has been initialized yet

main.dart
WidgetsFlutterBinding.ensureInitialized();
Stripe.publishableKey = stripePublishableKey;
Stripe.merchantIdentifier = 'emailID';
await Stripe.instance.applySettings();
Initiate Payment
Future<void> initPaymentSheet({
required String? price,
}) async {
try {
await Stripe.instance.initPaymentSheet(
paymentSheetParameters: SetupPaymentSheetParameters(
// Main params
paymentIntentClientSecret: clientSecret,
customerId: customerId,
customerEphemeralKeySecret: ephemeralKey,
// Merchant Name
merchantDisplayName: 'TEST',
// Extra params
applePay: const PaymentSheetApplePay(
merchantCountryCode: 'US',
),
googlePay: const PaymentSheetGooglePay(
merchantCountryCode: 'US',
testEnv: true,
),
style: ThemeMode.system,
),
);
} catch (e) {
rethrow;
}
}
/// Display the payment sheet.
Future<void> confirmPayment({required String price}) async {
try {
await initPaymentSheet(price: price);
// Present Payment sheet to user for payment
await Stripe.instance.presentPaymentSheet();
// Book the request.
bookingRequest();
} on Exception catch (e) {
if (e is StripeException) {
// displaySnackBar(
// 'Error!', 'Error from Stripe: ${e.error.localizedMessage}');
log('Error from Stripe: ${e.error.localizedMessage}');
print('Error from Stripe: ${e.error.localizedMessage}');
displaySnackBar('Error!', 'Something went wrong!, \nPlease try again.');
} else {
log('Error from Stripe: $e');
displaySnackBar('Error!', 'Something went wrong!, \nPlease try again.');
}
}
}
This confirmPayment() is called on Button click.
It will wait for Init the payment sheet.
After that presentPaymentSheet called to present the Payment sheet.
In Android, It's working fine.
In iOS, it's showing error like: No payment sheet has been initialized yet
Already Raised the Issue on the plugin Repo.
https://github.com/flutter-stripe/flutter_stripe/issues/850
✅ Solved:
Okay, the problem was in our backend response
when we were generating EphemeralKey, our backend dev was returning ephemeralKey["id"] instead of ephemeralKey["secret"] as a ephemeralKey.
I changed the EphemeralKey
from this
paymentIntentDTO.setEphemeralKey(ephemeralKey.getId());
to this
paymentIntentDTO.setClientSecret(paymentIntent.getClientSecret());
see ephemeralKey is different.
ephemeralKey["id"] is work fine in android app for stripe payment but on IOS ephemeralKey["id"] will not working
it was showing Error from Stripe: No payment sheet has been initialised yet
i changed ephemeralKey["id"] to ephemeralKey["secret"] as a ephemeralKey and now it working fine on both device.

Flutter Firebase Sign In With Apple Not Working ios

I am trying to set up with apple sign in with the following code. When tapping the button nothing happens.
I get the following error:
NoSuchMethodError (NoSuchMethodError: The method '[]' was called on null.
Receiver: null
Tried calling: []("User"))
The new user appears in firebase authentication but other than that the app does not work.
I have enabled sign in with apple in xcode and on developer.apple.com. I have also tried redownloading my provisioning profiles in xcode but no luck.
I have enabled apple sign in in firebase.
Does anyone know how to fix this?
mixin AuthenticationApple {
static String generateNonce([int length = 32]) {
const charset =
'0123456789ABCDEFGHIJKLMNOPQRSTUVXYZabcdefghijklmnopqrstuvwxyz-._';
final random = Random.secure();
return List.generate(length, (_) => charset[random.nextInt(charset.length)])
.join();
}
/// Returns the sha256 hash of [input] in hex notation.
static String sha256ofString(String input) {
final bytes = utf8.encode(input);
final digest = sha256.convert(bytes);
return digest.toString();
}
static Future<User> signInWithApple({BuildContext context}) async {
User user;
// To prevent replay attacks with the credential returned from Apple, we
// include a nonce in the credential request. When signing in with
// Firebase, the nonce in the id token returned by Apple, is expected to
// match the sha256 hash of `rawNonce`.
final rawNonce = generateNonce();
final nonce = sha256ofString(rawNonce);
// Request credential for the currently signed in Apple account.
final appleCredential = await SignInWithApple.getAppleIDCredential(
scopes: [
AppleIDAuthorizationScopes.email,
AppleIDAuthorizationScopes.fullName,
],
nonce: nonce,
);
// Create an `OAuthCredential` from the credential returned by Apple.
final oauthCredential = OAuthProvider('apple.com').credential(
idToken: appleCredential.identityToken,
rawNonce: rawNonce,
);
try {
// Sign in the user with Firebase. If the nonce we generated earlier does
// not match the nonce in `appleCredential.identityToken`, sign in will fail.
final UserCredential userCredential =
await FirebaseAuth.instance.signInWithCredential(oauthCredential);
user = userCredential.user;
} on FirebaseAuthException catch (e) {
if (e.code == 'account-exists-with-different-credential') {
ScaffoldMessenger.of(context).showSnackBar(
AppWidget.customSnackBar(
content: 'The account already exists with a different credential.',
),
);
} else if (e.code == 'invalid-credential') {
ScaffoldMessenger.of(context).showSnackBar(
AppWidget.customSnackBar(
content: 'Error occurred while accessing credentials. Try again.',
),
);
}
} catch (e) {
ScaffoldMessenger.of(context).showSnackBar(
AppWidget.customSnackBar(
content: 'Error occurred using Apple Sign-In. Try again.',
),
);
}
return user;
}
}
I just surpassed this issue by using iOS 13.0 for simulator. It seems there's an issue with higher versions when using the simulator but not with physical devices.
You can download and install simulators all the way back to iOS 13.0 (which is the minimum version for Apple Sign-In. In Xcode:
Xcode > Preferences.
Select the "Components" tab.
Mark the simulators you want.
Press "Check and Install Now".

Flutter-Firebase phone Auth always returns Token mismatch on iOS

I'm trying to use phone Authentication and it's working as expected on Android, but on iOS I always get Token mismatch and don't receive a code.
other Firebase services like cloud firestore and email Auth are working fine on iOS.
I made sure of the following:
-APN key is added in Firebase
-Google Services file is updated
-Background Modes and Push Notification capabilities are on
the error message is from PhoneVerificationFailed
Future<void> _verifyPhoneNumber() async {
setState(() {
_message = '';
});
final PhoneVerificationCompleted verificationCompleted =
(AuthCredential phoneAuthCredential) async {
await _auth.signInWithCredential(phoneAuthCredential);
setState(() {
_message = 'Received phone auth credential: $phoneAuthCredential';
});
};
final PhoneVerificationFailed verificationFailed =
(AuthException authException) {
setState(() {
_message = '********************\n\n'
'Phone number verification failed. Code: ${authException.code}.'
'\n Message: ${authException.message}'
'\n\n********************';
});
};
final PhoneCodeSent codeSent =
(String verificationId, [int forceResendingToken]) async {
_verificationId = verificationId;
setState(() {
_message = 'waiting for code';
//waitingCode = true;
});
};
final PhoneCodeAutoRetrievalTimeout codeAutoRetrievalTimeout =
(String verificationId) {
_verificationId = verificationId;
};
try {
await _auth.verifyPhoneNumber(
phoneNumber: number,
timeout: const Duration(seconds: 30),
verificationCompleted: verificationCompleted,
verificationFailed: verificationFailed,
codeSent: codeSent,
codeAutoRetrievalTimeout: codeAutoRetrievalTimeout);
} catch (e) {
print('Error is $e');
}
}
and I'm getting these messages from log
Userinfo {
"com.google.firebase.auth" = {
warning = "This fake notification should be forwarded to Firebase Auth.";
};
}
UserDate : {
"com.google.firebase.auth" = {
warning = "This fake notification should be forwarded to Firebase Auth.";
};
}
UserDate Json : {
"com.google.firebase.auth" : {
"warning" : "This fake notification should be forwarded to Firebase Auth."
}
}
flutter:
TRUE
flutter: Call Back {
"com.google.firebase.auth" : {
"warning" : "This fake notification should be forwarded to Firebase Auth."
}
}
I understand it's too late in answering this. But I also faced the same error recently. I fixed the issue on iOS. Your entire configuration must be valid. There are two settings you need to make.
Remove any method swizzling variable from GoogleService-info.plist
i.e. remove FirebaseAppDelegateProxyEnabled property from plist
In AppDelegate.swift, override this method and set the following
func application(application: UIApplication,
didRegisterForRemoteNotificationsWithDeviceToken deviceToken: NSData) {
Messaging.messaging().apnsToken = deviceToken
}
It is mentioned at https://firebase.google.com/docs/cloud-messaging/ios/client#token-swizzle-disabled
I am using firebase_messaging: ^6.0.16 and the above settings worked
Changing the Firebase Auth version from 0.14.0 to
firebase_auth:
git:
url: https://github.com/collinjackson/plugins.git
ref: 441417c2fed0ff26bf84a49ab2c5ffd2aa5487de
path: packages/firebase_auth
fixed my issue.
see https://github.com/flutter/flutter/issues/35267 for more details

send verification mail in flutter/dart development

I'm New to flutter and dart mobile app development. how to implement forgot password and send verification mail in flutter/dart development or is there any way to implement to send mail.
I don't think there is any way to send an email from your flutter application. This is something I would definitely implement on a backend server.
I would implement a 'forgot password' button in flutter, which triggers a http call to the backend which then triggers the password generation and email sending.
Yes there are some ways. The most common would be to use firebase as a backend server handling these requests.
You could do it like this
Add these packages to your flutter apps pubspec.yaml file
// latest version
firebase_core: ^1.17.0
firebase_auth: ^3.3.18
On forgot password button click
once you've completed the logic necessary before making the request, call this function
sendResetEmail(String email, BuildContext context) async {
final FirebaseAuth _auth = FirebaseAuth.instance;
try {
await _auth.sendPasswordResetEmail(email: email);
Timer(
const Duration(seconds: 3),
() => CustomWidgets().moveToPage(
page: const Home(), context: context, replacement: true),
);
} catch (e) {
// error handling here
}
}
This will send an email from firebase to the selected email to reset password.
On email verification request
Once the logic is over, call this function.
bool _isEmailVerified = false;
Timer? timer;
final FirebaseAuth _auth = FirebaseAuth.instance;
the initstate method
#override
void initState() {
_isEmailVerified = _auth.currentUser!.emailVerified;
if (!_isEmailVerified) {
sendEmailVerificationForUser();
timer = Timer.periodic(const Duration(seconds: 5), (timer) {
emailVerificationStatus(context);
});
}
email verification check function
emailVerificationStatus(BuildContext context) async {
try {
await _auth.currentUser!.reload();
setState(() {
_isEmailVerified = _auth.currentUser!.emailVerified;
});
} catch (e) {
// handle the error here
}
setState(() {
_isEmailVerified = _auth.currentUser!.emailVerified;
});
if (_isEmailVerified) {
timer?.cancel();
// and move to next page
}}
send email verification function
Future sendEmailVerificationForUser() async {
try {
await FirebaseAuth.instance.currentUser!.sendEmailVerification();
} catch (e) {
// error handling}

Resources