I have successfully managed to get remote messages from Firebase console to send messages when my app is in the QUIT state, FOREGREOUND state and in BACKGROUND state. So all the Firebase setup is working PERFECTLY in my React Native app (Android).
I managed to get Firebase Push Notifications working very well, using the latest Firebase messaging library.
The Version 5 'react-native-firebase' is deprecated and no longer supported, we have to use Version 6 '@react-native-firebase/messaging' for messaging and 'react-native-push-notification' (for the channel stuff and notification). This is good for the future in all React Native work, as the old version is becoming obsolete and Firebase isn't supporting it.
The google-services.json works fine and the push certificate is also successfully uploaded in the Voximplant panel.
I can already make calls when both Voximplant users are on the app (i.e. app states are in the FOREGROUND).
The MAIN reason for needing the push, is to allow another Voximplant user to receive a call from the app QUIT and BACKGROUND state.
What seems to be missing?
Here's my code:
package.json
"@react-native-firebase/app": "^15.2.0",
"@react-native-firebase/messaging": "^15.2.0",
"react-native-voximplant": "^1.28.0",
index.js
import {AppRegistry} from 'react-native';
import App from './App';
import {name as appName} from './app.json';
import messaging from '@react-native-firebase/messaging';
import PushBackground from './manager/PushBackground';
//Set handler
messaging().setBackgroundMessageHandler(PushBackground);
// NOT USING (but still works with pure firebase incoming push notifications)
//messaging().setBackgroundMessageHandler(async remoteMessage => {
// console.log('Message handled in the background!', remoteMessage);
//});
AppRegistry.registerComponent(appName, () => App);
App.js
import React, { useState, useEffect } from "react";
import { requestUserPermission, NotificationListener, CancelNotifications } from "./manager/PushManager";
function App() {
useEffect(() => {
//Firebase messaging/notifications
requestUserPermission(); //gets "fcmtoken"
NotificationListener(); //sets up firebase listeners for (QUIT, FOREGROUND, BACKGROUND App states)
CancelNotifications(); //Cancels notifications after received
}, []);
return(...all UI stuff...)
export default App;
}
loginScreen.js
import React, { Component, useEffect, useState, useContext } from "react";
import { Voximplant } from 'react-native-voximplant';
import { APP_NAME, ACC_NAME } from "../../constant/constants";
import AsyncStorage from '@react-native-async-storage/async-storage';
const LoginScreen = ({ navigation }) => {
const voximplant = Voximplant.getInstance();
useEffect(() => {
const connect = async() => {
const status = await voximplant.getClientState();
if(status == Voximplant.ClientState.DISCONNECTED){
await voximplant.connect();
console.log("Status: Voximplant Client DISCONNECTED: " + status);
}
else if (status == Voximplant.ClientState.LOGGED_IN) {
console.log("Status: Voximplant Client LOGGED IN: " + status);
}
const signIn = async () => {
try{
const fqUsername = `${username}@${APP_NAME}.${ACC_NAME}.voximplant.com`;
console.log(fqUsername);
let authResult = await voximplant.login(fqUsername, password);
const loginTokens = authResult.tokens;
console.log("Log In Successful. Token " + JSON.stringify(loginTokens, null, 2));
//We have fcmtoken (firebase) from App.js loading up, so now register it with Voximplant cloud
const fcmToken = await AsyncStorage.getItem("fcmtoken");
//Register it with Voximplant
if(fcmToken != null){
voximplant.registerPushNotificationsToken(fcmToken);
}
//Set fqUsername for Voximplant
await AsyncStorage.setItem("fqUsernameKey", fqUsername);
//Set accessToken for Voximplant
await AsyncStorage.setItem('accessTokenKey', authResult.tokens.accessToken);
}
catch(e) {
console.log("signIn issue: "+ e);
Alert.alert("Already Logged In", `Error code: ${e.code}`);
}
}
return(...UI stuff...)
}
export default LoginScreen;
PushBackground.js
'use strict';
import AsyncStorage from '@react-native-async-storage/async-storage';
import { Voximplant } from 'react-native-voximplant';
export default async (message) => {
console.log('PushBackground android: notification: ' + JSON.stringify(message));
const username = await AsyncStorage.getItem("fqUsernameKey"); //THIS IIS SET IN LOGINSCREEN.JS
const accessToken = await AsyncStorage.getItem("fcmtoken"); //THIS IS SET IN PUSHMANAGER.JS
const client = Voximplant.getInstance();
await client.loginWithToken(username, accessToken);
await client.handlePushNotification(message.data);
return Promise.resolve();
};
PushManager.js
import AsyncStorage from '@react-native-async-storage/async-storage';
import messaging from "@react-native-firebase/messaging";
import PushNotification, {Importance} from 'react-native-push-notification';
async function getFCMToken() {
let fcmtoken = await AsyncStorage.getItem("fcmtoken");
console.log(fcmtoken, "old token")
if(!fcmtoken){
try{
const fcmtoken = await messaging().getToken();
if(fcmtoken) {
console.log(fcmtoken, "new token");
await AsyncStorage.setItem("fcmtoken", fcmtoken);
}
}
catch (error) {
console.log(error, "error in fcmtoken")
}
}
}
//Create Push Notification channel
async function createVoximplantChannel() {
PushNotification.createChannel( //Haven't tried with Voximplant
{
channelId: "voximplant_channel_id", // "channel-id", // (required)
channelName: "Incoming call channel", //"My channel", // (required)
channelDescription: "Incoming call received", //"A channel to categorise your notifications", // (optional) default: undefined.
playSound: true, // (optional) default: true
soundName: "default", // (optional) See `soundName` parameter of `localNotification` function
importance: 5, // (optional) default: 4. Int value of the Android notification importance. importance: 2 <- SILENT NOTIFICATION CHANNEL & importance: 5 <- POPUP NOTIFICATION CHANNEL
vibrate: false, // (optional) default: true. Creates the default vibration patten if true.
},
(created) => console.log(`createChannel returned '${created}'`) // (optional) callback returns whether the channel was created, false means it already existed.
);
}
export async function requestUserPermission() {
const authStatus = await messaging().requestPermission();
const enabled =
authStatus === messaging.AuthorizationStatus.AUTHORIZED ||
authStatus === messaging.AuthorizationStatus.PROVISIONAL;
if (enabled) {
console.log('Authorization Status: ', authStatus);
getFCMToken();
createVoximplantChannel();
}
}
export const NotificationListener = () => {
//******** Notification from BACKGROUND state app ********
messaging().onNotificationOpenedApp((remoteMessage) => {
PushNotification.localNotification({
channelId: "voximplant_channel_id", //remoteMessage.notification.android.channelId, //Perhaps "voximplant_channel_id" ?
message: remoteMessage.notification.body,
title: remoteMessage.notification.title,
//bigPictureUrl: remoteMessage.notification.android.imageUrl,
//smallIcon: remoteMessage.notification.android.imageUrl,
vibrate: true,
data: remoteMessage.data,
})
});
//******** Notification from QUIT state app ********
messaging()
.getInitialNotification()
.then( (remoteMessage) => {
PushNotification.localNotification({
channelId: "voximplant_channel_id", //remoteMessage.notification.android.channelId, //Perhaps "voximplant_channel_id" ?
message: remoteMessage.notification.body,
title: remoteMessage.notification.title,
//bigPictureUrl: remoteMessage.notification.android.imageUrl,
//smallIcon: remoteMessage.notification.android.imageUrl,
vibrate: true,
data: remoteMessage.data,
})
});
//******** Notification from FOREGROUND state app ********
messaging().onMessage(async (remoteMessage) => {
PushNotification.localNotification({
channelId: "voximplant_channel_id", //remoteMessage.notification.android.channelId,
message: remoteMessage.notification.body,
title: remoteMessage.notification.title,
//bigPictureUrl: remoteMessage.notification.android.imageUrl,
//smallIcon: remoteMessage.notification.android.imageUrl,
vibrate: true,
data: remoteMessage.data,
})
});
}
//Cancel notifications (so hopefully no overlapping notificatons)
export const CancelNotifications = () => {
PushNotification.cancelAllLocalNotifications();
};