React Native Ios Push Notification Not Working - ios

I use '#react-native-firebase/messaging' module to send notifications. On Android everything works fine, Following is the error log I get when I try const fcmToken = await firebase.messaging().getToken(); on ios device.
NativeFirebaseError: [messaging/unknown] The operation couldn’t be completed. (com.firebase.iid error 1001.)
I have already implemented "react-native-permissions" to grant notification permission.
My AppDelegate.m contains :
if ([FIRApp defaultApp] == nil) {
[FIRApp configure];
}
Should I add anything else to it?
Any help or suggestion will be very helpful.
Thanks in advance

You need to check and ask messaging permission before get the fcm token in iOS
/**
* Check is notification showing permission enabled if not ask the permission.
*/
async checkFcmPermission() {
firebase
.messaging()
.hasPermission()
.then(enabled => {
if (enabled) {
// User has permissions
this.getFcmToken(); // const fcmToken = await firebase.messaging().getToken();
} else {
// User doesn't have permission
firebase
.messaging()
.requestPermission()
.then(() => {
// User has authorized
this.getFcmToken(); // const fcmToken = await firebase.messaging().getToken();
})
.catch(error => {
// User has rejected permissions
console.log(
'PERMISSION REQUEST :: notification permission rejected',
);
});
}
});
}

There are a lot of solutions to this issue. I post my answer since some StackOverflow users requested.
Here is my code
const sleep = ms => {
return new Promise(resolve => setTimeout(resolve, ms));
};
async function requestPermissionForNotification() {
try {
const permission = await requestNotifications(["alert", "badge", "sound"]);
if (permission.status === "granted") {
setupNotification();
}
} catch (e) {
console.log(e)
}
};
async function setupNotification() {
try {
await sleep(5000)
// TODO no need token for now, Will be used for future releases
const enabled = await firebase.messaging().hasPermission();
await requestNotifications(['alert', 'badge', 'sound']);
await firebase.messaging().registerForRemoteNotifications();
const token = await firebase.messaging().getToken();
firebase.messaging().onMessage(async (remoteMessage) => {
});
} catch (e) {
console.log(e)
}
}
And Also I have added following to Info.plist
<key>UIBackgroundModes</key>
<array>
<string>remote-notification</string>
</array>
To sum up, I use react permissions to grant permission and the sleep method is to wait for firebase to be ready. Finally uninstalled app couple time to get a result.
When It started working, I couldn't dare to touch the code since I spent days on this.

Related

Ionic - How to request permission again after user rejected once?

Currently, I can request permission for microphone with the following code if the user has not rejected granting permissions:
permission = await this.diagnostic.isMicrophoneAuthorized();
if (!permission) {
permission = await this.diagnostic.requestMicrophoneAuthorization()
.then(async () => {
console.log('this.diagnostic.requestMicrophoneAuthorization succeed.');
return await this.diagnostic.isMicrophoneAuthorized();
})
.catch((err) => {
console.error('this.diagnostic.requestMicrophoneAuthorization failed, error: ', err);
return false;
})
}
But once they reject the request, the requestMicrophoneAuthorization is still triggered, but no dialog pop up and the result always returns false.
Is there a way to request the authorization again with Ionic 3?
To do this, you will need to use the cordova-diagnostic-plugin to check the current microphone authorization status and request authorization again if it has been denied.
import { Diagnostic } from '#ionic-native/diagnostic/ngx';
constructor(private diagnostic: Diagnostic) {}
async requestMicrophoneAuthorization() {
// Check the current microphone authorization status
let authorizationStatus = await this.diagnostic.getMicrophoneAuthorizationStatus();
if (authorizationStatus === this.diagnostic.permissionStatus.DENIED_ALWAYS) {
// If the authorization has been denied always, we need to ask the user to grant
// microphone permission again.
try {
// Request microphone authorization
authorizationStatus = await this.diagnostic.requestMicrophoneAuthorization();
console.log('Microphone authorization status: ', authorizationStatus);
} catch (error) {
console.error('Error requesting microphone authorization: ', error);
}
}
}

expo-notifications - Error encountered while updating the device push token with the server

I'm using Expo's bare-workflow for my react-native project. I'm using expo's push notification service. I keep getting the following error whenever I try to get my expo push token:
[expo-notifications] Error encountered while updating the device push token with the server: {"error":"invalid_token","error_description":"The bearer token is invalid"}
I'm running the app directly on my device so should be able to get notifications.
I'm using basically the same registerForPushNotificationsAsync() that is provided in the documentation.
import Constants from 'expo-constants';
import * as Notifications from 'expo-notifications';
import { Platform } from 'react-native';
export const registerForPushNotificationsAsync = async () => {
try {
if (Constants.isDevice) {
const experienceId = '#{username}/{slug}';
const {
status: existingStatus
} = await Notifications.getPermissionsAsync();
let finalStatus = existingStatus;
if (existingStatus !== 'granted') {
const { status } = await Notifications.requestPermissionsAsync();
finalStatus = status;
}
if (finalStatus !== 'granted') {
alert('Failed to get push token for push notification!');
return;
}
const token = (
await Notifications.getExpoPushTokenAsync({ experienceId })
).data;
console.log(' 🏷 🏷 Token :', token);
return token;
} else {
alert('Must use physical device for Push Notifications');
}
if (Platform.OS === 'android') {
Notifications.setNotificationChannelAsync('default', {
name: 'default',
importance: Notifications.AndroidImportance.MAX,
vibrationPattern: [0, 250, 250, 250],
lightColor: '#FF231F7C'
});
}
return undefined;
} catch (error) {
console.error('Error in registerForPushNotificationsAsync()', error);
return undefined;
}
};
Expo packages in package.json
"expo": "~40.0.0",
"expo-analytics": "^1.0.16",
"expo-app-loading": "^1.0.1",
"expo-font": "~8.4.0",
"expo-image-manipulator": "~8.4.0",
"expo-image-picker": "~9.2.0",
"expo-intent-launcher": "~8.4.0",
"expo-notifications": "~0.8.2",
"expo-splash-screen": "~0.8.0",
"expo-updates": "~0.4.0",
I can't see anything about setting a bearer token, so I'm unsure what it could be after or where to even set it assuming I was able to determine what bearer token it is after.
Does anyone know what might be causing the problem?
So we figured it out.
We were using fetch-token-intercept which was adding our bearer token to calls going to expo, which meant validation was failing.
We modified the function to exclude calls to expo from including our bearer token and now the token is being retrieved successfully.

React Native Notification IOS - APN Configuration

I have a problem with the configuration of push notification in IOS. I followed all the steps of the tutorial in the Invertase documentation (https://invertase.io/oss/react-native-firebase/v6/messaging/ios-configure-apns), but it didn't work. I read this article, and followed the steps up to the part of generating a development certificate (https://www.codementor.io/#uokesita/react-native-push-notifications-with-firebase-2019-10on0z19t6#generate-a-development-certificate). My JS code is as follows:
export default class App extends React.Component {
async componentDidMount() {
await messaging().registerForRemoteNotifications()
await messaging().requestPermission().then(async granted =>{
if (granted) {
console.log('User granted messaging permissions!');
if(Platform.OS === "ios"){
console.log("Token: " + await messaging().getToken())
}
} else {
console.log('User declined messaging permissions :(');
}
});
}
render() {
return (<AppContainer />)
}
}
Would anyone know to tell me why the notification does not want to appear? And when I request the Token as shown in the code below, the following error also appears:
[messaging/unknown] The operation couldn’t be completed. (com.firebase.iid error 1001.)

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

Notifications.getExpoPushTokenAsync not working on Stand Alone iOS

I'm trying to my expo/react-native project to send push notifications to my server. It works on standalone Android, but not stand alone iPhone.
The standalone iPhone app never sends the token.
Since the app sends nothing without error, I tried removing:
if (finalStatus !== 'granted') { return; }
This didn't work either.
export async function registerForPushNotificationsAsync(token) {
const { status: existingStatus } = await Permissions.getAsync(
Permissions.NOTIFICATIONS
);
let finalStatus = existingStatus;
// Only ask if permissions have not already been determined, for iOS.
if (existingStatus !== 'granted') {
const { status } = await Permissions.askAsync(Permissions.NOTIFICATIONS);
finalStatus = status;
}
// Stop here if the user did not grant permissions
if (finalStatus !== 'granted') {
return;
}
// Get the push token that uniquely identifies this device
let expoToken = await Notifications.getExpoPushTokenAsync();
// Post new push token to backend for user
return axios({
method: 'POST',
url: `${str.ROOT_URL}/account/push/`,
headers: {
Authorization: `Token ${token}`
},
data: {
"token": expoToken,
"status": finalStatus
}
});
}
I expected the token to get sent to the backend, but nothing is sent on the standalone iOS app.
Please let me know if you know a workaround or had this issue before. Thanks!
I think it's too late to give an answer, but I spent 2 days to resolve it... I hope it helps somebody.
Instead this:
import * as Notifications from "expo-notifications";
Try this:
import { Notifications } from "expo";

Resources