Notification is not navigating to a screen when pressed on foreground - android

I am using react-native-notifee and react-native-firebase v11.2.0
The problem is, when I press the notification during the app is in foreground, it is not navigating to the required screen. It is working fine while my app is in background.
notification.js
import notifee, {
AndroidCategory,
AndroidImportance,
AndroidStyle,
EventType
} from '#notifee/react-native';
import messaging from '#react-native-firebase/messaging';
import { requestNotificationPermission } from '../helpers/permissions';
import * as RootNavigator from '../navigator/NavigationRef';
const createChannel = async () => {
try {
const channel = await notifee.createChannel({
id: 'default_channel',
name: 'Default Channel',
description: 'Default notification channel',
sound: 'default',
importance: AndroidImportance.HIGH,
vibration: false
});
return channel;
} catch (error) {
console.log('Error in creating notification channel', error);
return 'default_channel';
}
};
export const requestPermissionForNotifications = async () => {
const hasPermission = await messaging().hasPermission();
if (!hasPermission) {
// checking for ios notification permission;
const isGranted = await requestNotificationPermission();
if (isGranted < 1) return false;
}
// always request permisssion even if it is granted
return messaging()
.requestPermission()
.then(() => console.log('granted'))
.catch(err => console.log('error in granted', err));
};
export const displayNotification = async (
title,
body,
notificationId,
imageUrl = null
) => {
try {
// always check permisssion even if it has access to register the app to
// receive the push notification as stated in documentation
await requestPermissionForNotifications();
const channel = await createChannel();
let notificationObj = {
title,
body,
id: notificationId,
android: {
channelId: channel,
smallIcon: 'ic_launcher',
sound: 'default',
category: AndroidCategory.ALARM,
importance: AndroidImportance.HIGH,
pressAction: {
id: 'default'
},
timestamp: Date.now(),
showTimestamp: true
},
ios: {
sound: 'default',
attachments: [
{
url: imageUrl
}
]
}
};
await notifee.displayNotification(notificationObj);
} catch (error) {
console.log('Error in displaying notification', error);
}
};
export const onMessageReceived = async message => {
const { messageId, notification } = message;
return displayNotification(
notification.title,
notification.body,
messageId,
notification.image
);
};
export const notificationPressActionEventListener = async ({
type,
detail
}) => {
try {
const { navigate } = RootNavigator.navigationRef.current;
switch (type) {
case EventType.PRESS:
navigate('SampleStackScreen');
break;
default:
break;
}
} catch (error) {
console.log('Error in navigation', error);
}
return null;
};
export const getDeviceToken = async () => {
const token = await messaging().getToken();
if (token) return token;
return null;
};
NavigationRef.js
import * as React from 'react';
export const navigationRef = React.createRef();
Listeners in Home.js
componentDidMount() {
this.notificationListener = messaging().onMessage(onMessageReceived);
this.notificationActionEventListener = notifee.onForegroundEvent(
notificationPressActionEventListener
);
}
Listeners in index.js
/** #format */
import messaging from '#react-native-firebase/messaging';
import notifee from '#notifee/react-native';
import { AppRegistry } from 'react-native';
import { name as appName } from './app.json';
import App from './src/App';
import {
notificationPressActionEventListener,
onMessageReceived
} from './src/firebase/notification';
notifee.onBackgroundEvent(notificationPressActionEventListener);
messaging().setBackgroundMessageHandler(onMessageReceived);
AppRegistry.registerComponent(appName, () => App);

Related

How can I save firebase push notification device local when app closed in flutter?

I use Hive_flutter and flutter_local_notifications: ^13.0.0. And I don't have any about saving notifications device local idea when app closed. Can you help me? thanks for your insteresting.
int badgesCount = 0;
FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin =
FlutterLocalNotificationsPlugin();
FirebaseMessaging messaging = FirebaseMessaging.instance;
class PushNotificationsService {
Future initialise() async {
iOSPermission();
messaging.getToken().then((token) async {
print('token is $token');
});
const AndroidInitializationSettings initializationSettingsAndroid =
AndroidInitializationSettings('#drawable/ic_stat_name');
DarwinInitializationSettings initializationSettingsIOS =
DarwinInitializationSettings(
onDidReceiveLocalNotification: onDidReceiveIos);
InitializationSettings initializationSettings = InitializationSettings(
android: initializationSettingsAndroid,
iOS: initializationSettingsIOS,
);
flutterLocalNotificationsPlugin.initialize(
initializationSettings,
onDidReceiveNotificationResponse: (payload) async {
if (payload != "") {
log(payload.toString());
}
},
);
FirebaseMessaging.onMessage.listen(
(RemoteMessage message) async {
if (message.notification != null) {
badgeCount += 1;
final remoteModel = RemoteMessageModel.fromJson(message.toMap());
await StorageHiveHelper().save(remoteModel);
var data = message.notification;
var title = data?.title.toString();
var body = data?.body.toString();
var image = message.data['image'] ?? '';
var type = message.data['type'] ?? '';
var id = '';
id = message.data['type_id'] ?? '';
if (Platform.isIOS) return;
if (image != null && image != 'null' && image != '') {
return await generateImageNotication(
title ?? "", body ?? "", image, type, id);
}
}
},
);
messaging.getInitialMessage().then((RemoteMessage? message) {
if (message != null) {
log("Initial Message: " + (message.data.toString()));
pushToNavigate(message);
}
});
FirebaseMessaging.onMessageOpenedApp
.listen((RemoteMessage message) => pushToNavigate(message));
FirebaseMessaging.onBackgroundMessage(getBackGroundMessage);
}
pushToNavigate(RemoteMessage? message) async {
var type = await message?.data['type'] ?? '';
log("OnDidReceiveIOS: " + (message?.data.toString() ?? "null ios payload"));
log(type);
if (type == 'products') {
navService.pushNamed("product/detail", args: 631509);
}
}
void iOSPermission() async {
await messaging.setForegroundNotificationPresentationOptions(
alert: true,
badge: true,
sound: true,
);
}
void onDidReceiveIos(
int id, String? title, String? body, String? payload) async {
log("OnDidReceiveIOS: " + (payload?.toLowerCase() ?? "null ios payload"));
try {
var iosDetail = const DarwinNotificationDetails(
presentBadge: true,
presentAlert: false,
presentSound: true,
sound: "cash.caf");
var platformChannelSpecifics = NotificationDetails(iOS: iosDetail);
await flutterLocalNotificationsPlugin.show(
id, title, title, platformChannelSpecifics,
payload: jsonEncode(payload ?? {}));
} on Exception catch (e) {
debugPrint(e.toString());
}
}
I tried saving the message to hive here. It working when app is on but it was not working when the app was totally closed
Future<void> getBackGroundMessage(RemoteMessage message) async {
badgeCount += 1;
await FlutterAppBadger.updateBadgeCount(badgeCount);
final remoteModel = RemoteMessageModel.fromJson(message.toMap());
await StorageHiveHelper().save(remoteModel);
}
}
const String _sound = "notification_sound";
void display(
RemoteMessage message,
NotificationDetails notificationDetails,
) async {
try {
await flutterLocalNotificationsPlugin.show(
message.hashCode,
message.notification?.title,
message.notification?.body,
notificationDetails,
payload: jsonEncode(message.data),
);
} on Exception catch (e) {
debugPrint(e.toString());
}
}
Future<void> generateSimpleNotication(
String title, String msg, String type, String id, RemoteMessage pay) async {
try {
if (Platform.isIOS) return;
log("Payload" + (pay.toMap().toString()));
final id = DateTime.now().millisecondsSinceEpoch ~/ 1000;
var androidPlatformChannelSpecifics = const AndroidNotificationDetails(
'high_importance_channels',
'High Importance Notifications',
playSound: true,
sound: RawResourceAndroidNotificationSound(_sound),
largeIcon: DrawableResourceAndroidBitmap('#drawable/ic_stat_name'),
importance: Importance.max,
priority: Priority.max, );
var iosDetail = const DarwinNotificationDetails(
presentAlert: true, presentSound: true, sound: "cash.caf");
var platformChannelSpecifics = NotificationDetails(
android: androidPlatformChannelSpecifics, iOS: iosDetail);
await flutterLocalNotificationsPlugin.show(
id, title, msg, platformChannelSpecifics,
payload: jsonEncode(pay.data));
} on Exception catch (e) {
debugPrint(e.toString());
}
}
I don't understand the main problem. You just want to display the notifications when app is closed or in background? Or you really need to save them to the local database? Anyways, try using this class
import 'dart:async';
import 'package:firebase_core/firebase_core.dart';
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
class PushNotificationService {
static FirebaseMessaging messaging = FirebaseMessaging.instance;
static final FlutterLocalNotificationsPlugin notificationPlugin =
FlutterLocalNotificationsPlugin();
static const AndroidNotificationChannel channel = AndroidNotificationChannel(
'high_importance_channel', // id
'High Importance Notifications', // title
description:
'This channel is used for important notifications.', // description
importance: Importance.high,
);
static String? idPush;
static StreamController<RemoteMessage> _messageStream =
StreamController.broadcast();
static Stream<RemoteMessage> get messagesStream => _messageStream.stream;
static Future _backgroundHandler(RemoteMessage message) async {
_messageStream.add(message);
// implement your actions here
}
static Future _onMessageHandler(RemoteMessage message) async {
_messageStream.add(message);
// implement your actions here, if you want to use flutter_local_notifications, use the display() method.
}
static Future _onMessageOpenApp(RemoteMessage message) async {
_messageStream.add(message);
// implement your actions here
}
// iniciar firebase i notificacions locals
static Future initializeApp() async {
//Push notifications
await Firebase.initializeApp();
idPush = await FirebaseMessaging.instance.getToken();
print('idPush: $idPush');
//Handler
FirebaseMessaging.onBackgroundMessage(_backgroundHandler);
FirebaseMessaging.onMessage.listen(_onMessageHandler);
FirebaseMessaging.onMessageOpenedApp.listen(_onMessageOpenApp);
//local notifications initialization
const InitializationSettings initializationSettings =
InitializationSettings(
iOS: DarwinInitializationSettings(),
android: AndroidInitializationSettings("#mipmap/ic_notification"),
);
notificationPlugin.initialize(initializationSettings);
}
// mètode per obrir una notificació local (només amb l'app oberta)
static void display(RemoteMessage message) async {
try {
await notificationPlugin.show(
message.notification!.hashCode,
message.notification!.title,
message.notification!.body,
NotificationDetails(
android: AndroidNotificationDetails(
channel.id,
channel.name,
channelDescription: channel.description,
color: Colors.blue,
icon: '#mipmap/ic_notification',
),
iOS: const DarwinNotificationDetails(
presentAlert: true, presentBadge: true, presentSound: true),
),
);
} on Exception catch (e) {
print(e);
}
}
// demanar permisos
Future<void> requestPermission() async {
NotificationSettings settings = await messaging.requestPermission(
alert: true,
announcement: false,
badge: true,
carPlay: false,
criticalAlert: false,
provisional: false,
sound: true,
);
if (settings.authorizationStatus == AuthorizationStatus.authorized) {
print('User granted permission');
} else if (settings.authorizationStatus ==
AuthorizationStatus.provisional) {
print('User granted provisional permission');
} else {
print('User declined or has not accepted permission');
}
}
static closeStreams() {
_messageStream.close();
}
}
This class will show notifications when app is closed or in background. And if you need to display them with the app opened, you can throught the display method. If you want to save them to hive, just implement that part on the Handlers.
Finally initialize the class in your main:
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await PushNotificationService.initializeApp();
runApp(const MyApp());
}

expo-notification on Sumni V2 device not working

I recently purchased a Sunmi V2 device for a client, and I am trying to print something when I receive a notification from expo-notification using react-native. I have successfully implemented this in another application, but I am having difficulty getting it to work on the Sunmi V2 device.
Here is the approach I took: On my StackNavigator.js component, I have...
const { user } = useAuth();
const { registerForPushNotificationsAsync, handleNotifications, handleNotificationsResponse } = useNotifications();
useEffect(() => {
registerForPushNotificationsAsync();
Notifications.setNotificationHandler({
handleNotification: async () => ({
shouldShowAlert: true,
shouldPlaySound: true,
shouldSetBadge: false,
}),
});
const responseListener =
Notifications.addNotificationResponseReceivedListener(
handleNotificationsResponse
);
return () => {
if (responseListener)
Notifications.removeNotificationSubscription(responseListener)
}
}, [user])
Here is the useNotification component:
export const useNotifications = () => {
const { user } = useAuth();
const registerForPushNotificationsAsync = async () => {
if (Device.isDevice) {
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!');
// console.log('Failed to get push token for push notification!')
return;
}
try {
const token = (await Notifications.getExpoPushTokenAsync()).data;
Alert.alert("TOKEN: ", token);
if (user) {
const useRef = doc(db, "users", user.uid);
if (token !== undefined) {
updateDoc(useRef, {
pushTokenExpo: token
});
}
}
} catch (error) {
Alert.alert(error)
}
} else {
if (user) {
alert('Must use physical device for Push Notifications', user.uid)
}
alert('Must use physical device for Push Notifications');
console.log('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',
});
}
};
const handleNotifications = (notification: Notifications.Notification) => {
console.log('NEW NOTIFICACTION')
};
const handleNotificationsResponse = (
response: Notifications.NotificationResponse
) => {
console.log(response.notification.request.content.data)
// HERE DO WHAT YOU WHAT AFTER CLICK ON NOTIF
}
return { registerForPushNotificationsAsync, handleNotifications, handleNotificationsResponse }
}
When I run this code on my device, it either crashes the app or does not update the Firebase collection 'user'. How can I fix this issue?

Push Notification Action Button Not Displaying - Background and Kill State - React Native

I have implemented firebase push notifications using Firebase and react-native-push-notification package.
Currently, I have implemented action buttons according to the click_action of each push notification. Once the app is in the foreground it works and once the app is killed state or background action buttons are not displaying.
My FCM helper file
class FCMServiceHelper {
register = (onRegister, onNotification, onOpenNotification) => {
this.checkPermission(onRegister);
this.createNotificationListeners(
onRegister,
onNotification,
onOpenNotification,
);
};
registerAppWithFCM = async () => {
if (Platform.OS === 'ios') {
await messaging().registerDeviceForRemoteMessages();
await messaging().setAutoInitEnabled(true);
}
};
checkPermission = (onRegister) => {
messaging()
.hasPermission()
.then((enabled) => {
if (enabled) {
// User has permissions
this.deleteToken()
this.getToken(onRegister);
} else {
// User doesn't have permission
this.requestPermission(onRegister);
}
})
.catch((error) => {
console.log('[FCMService] Permission rejected ', error);
});
};
getToken = (onRegister) => {
messaging()
.getToken(undefined,'*')
.then((fcmToken) => {
if (fcmToken) {
onRegister(fcmToken);
} else {
console.log('[FCMService] User does not have a device token');
}
})
.catch((error) => {
console.log('[FCMService] getToken rejected ', error);
});
};
requestPermission = (onRegister) => {
messaging()
.requestPermission()
.then(() => {
this.deleteToken()
this.getToken(onRegister);
})
.catch((error) => {
console.log('[FCMService] Request Permission rejected ', error);
});
};
deleteToken = () => {
console.log('[FCMService] deleteToken ');
messaging()
.deleteToken(undefined,'*')
.catch((error) => {
console.log('[FCMService] Delete token error ', error);
});
};
unregisterDeviceFromNotifications = () => {
console.log('[FCMService] unreg ');
messaging()
.unregisterDeviceForRemoteMessages()
.catch((error) => {
console.log('[FCMService] Unreg device ', error);
});
};
createNotificationListeners = (
onRegister,
onNotification,
onOpenNotification,
) => {
// When the application is running, but in the background
messaging().onNotificationOpenedApp((remoteMessage) => {
console.log(
'[FCMService] onNotificationOpenedApp Notification caused app to open from background state:',
remoteMessage,
);
if (remoteMessage) {
let notification = null;
let data = remoteMessage.data;
let openFromKilling = {"checked" : true}
notification = remoteMessage.notification;
notification.data = data;
notification.checking = openFromKilling;
onOpenNotification(notification);
}
});
// When the application is opened from a quit state.
messaging()
.getInitialNotification()
.then((remoteMessage) => {
console.log(
'[FCMService] getInitialNotification Notification caused app to open from quit state:',
remoteMessage,
);
if (remoteMessage) {
let notification = null;
let data = remoteMessage.data;
let openFromKilling = {"checked" : true}
notification = remoteMessage.notification;
notification.data = data;
notification.checking = openFromKilling;
onOpenNotification(notification);
}
});
// Foreground state messages
this.messageListener = messaging().onMessage(async (remoteMessage) => {
console.log(
'[FCMService] A new FCM message arrived! foreground',
remoteMessage,
);
if (remoteMessage) {
let notification = null;
let data = remoteMessage.data;
if (Platform.OS === 'ios') {
notification = remoteMessage.notification;
} else {
notification = remoteMessage.notification;
}
notification.data = data;
onNotification(notification);
// onOpenNotification(remoteMessage.data);
}
});
// Triggered when have new token
// messaging().onTokenRefresh((fcmToken) => {
// alert('REFRESH TOKEN');
// console.log('[FCMService] New token refresh: ', fcmToken);
// onRegister(fcmToken);
// });
};
unRegister = () => {
// if(this.messageListener){
this.messageListener();
// }
};
}
My notification Handler file
fcmService.registerAppWithFCM();
fcmService.register(onRegister, onNotification, onOpenNotificaion , onAction);
localNotificationService.configure(onOpenNotificaion,onAction);
function onRegister(token) {
saveFCMToken(token);
}
if (Platform.OS == 'android') {
localNotificationService.createChannelAndroid('wapp');
}
function onNotification(notify) {
var RandomNumber = Math.floor(Math.random() * 100) + 1;
let actionData = [];
if(Platform.OS == 'android'){
if(notify.data.click_action == 'alert_dashboard'){
actionData = ["Update contact number"]
}else if(notify.data.click_action == 'account_edit'){
actionData = ["Update Email"]
}
}
const options = {
soundName: 'default',
playSound: true,
};
localNotificationService.showNotification(
RandomNumber,
notify.title,
Platform.OS == 'android' ? notify.body : notify.body,
notify,
options,
'wapp',
actionData
);
}
function onAction(notification) {
console.log ('Notification action received:');
console.log(notification.action);
console.log(notification);
}
Notification Helper File
class NotificationHelper {
configure = (onOpenNotification) => {
PushNotification.configure({
onRegister: function (token) {
console.log('[NotificationManager] onRegister token:', token.token);
},
onNotification: function (notification) {
console.log('[NotificationManager] onNotification:', notification);
if (Platform.OS === 'ios') {
if (notification.data.openedInForeground) {
notification.userInteraction = true;
}
}
if (notification.userInteraction) {
onOpenNotification(notification);
} else {
onNotification(notification);
}
if (Platform.OS === 'android') {
notification.userInteraction = true;
}
// Only call callback if not from foreground
if (Platform.OS === 'ios') {
if (!notification.data.openedInForeground) {
notification.finish('backgroundFetchResultNoData');
}
} else {
notification.finish('backgroundFetchResultNoData');
}
},
onAction: function (notification) {
// alert(notification)
console.log("ACTION:", notification.action);
console.log("NOTIFICATION:", notification);
// notification.userInteraction = true;
// PushNotification.invokeApp(notification);
},
});
};
unregister = () => {
PushNotification.unregister();
};
createChannelAndroid = (channel) => {
PushNotification.createChannel(
{
channelId: channel, // (required)
channelName: 'My channel', // (required)
channelDescription: 'A channel to categorise your notifications', // (optional) default: undefined.
playSound: false, // (optional) default: true
soundName: 'default', // (optional) See `soundName` parameter of `localNotification` function
importance: 4, // (optional) default: 4. Int value of the Android notification importance
vibrate: true, // (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.
);
};
showNotification = (id, title, message, data = {}, options = {}, channel , testData) => {
PushNotification.localNotification({
/* Android Only Properties */
...this.buildAndroidNotification(
id,
title,
message,
data,
options,
channel,
testData
),
/* iOS and Android properties */
...this.buildIOSNotification(id, title, message, data, options),
/* iOS and Android properties */
title: title || '',
message: message || '',
playSound: options.playSound || true,
soundName: options.soundName || 'default',
userInteraction: true, // BOOLEAN: If the notification was opened by the user from the notification area or not
});
};
buildAndroidNotification = (
id,
title,
message,
data = {},
options = {},
channel,
testData
) => {
console.log('TEST DATA -> ',data)
return {
showWhen: true, // This is probably not needed, since default value is TRUE.
when: new Date().getTime(),
group: "wapp",
groupSummary: true,
channelId: channel,
id: id,
autoCancel: true,
largeIcon: options.largeIcon || 'ic_launcher',
smallIcon: options.smallIcon || 'ic_launcher',
bigText: message || '',
subText: title || '',
vibrate: options.vibrate || true,
vibration: options.vibration || 300,
priority: options.priority || 'high',
importance: options.importance || 'high', // (optional) set notification importance, default: high,
data: data,
actions:testData,
// invokeApp:false,
};
};
buildIOSNotification = (id, title, message, data = {}, options = {}) => {
return {
alertAction: options.alertAction || 'view',
alertBody: message || '',
category: options.category || '',
userInfo: {
id: id,
item: data,
},
};
};
cancelAllLocalNotifications = () => {
if (Platform.OS === 'ios') {
PushNotificationIOS.removeAllDeliveredNotifications();
} else {
PushNotification.cancelAllLocalNotifications();
}
};
removeDeliveredNotificationByID = (notificationId) => {
console.log(
'[LocalNotificationService] removeDeliveredNotificationByID: ',
notificationId,
);
PushNotification.cancelLocalNotifications({id: `${notificationId}`});
};
}
My app index.js file
/**
* #format
*/
import React from 'react';
import 'react-native-gesture-handler';
import { AppRegistry, LogBox, YellowBox } from 'react-native';
import App from './app/Entrypoint';
import { name as appName } from './app.json';
import { enableScreens } from 'react-native-screens';
import messaging from '#react-native-firebase/messaging';
import { backgroundGeo, checkLocationLogics } from './app/helpers/backgroundLocationTracking';
import env from 'react-native-config';
enableScreens();
messaging().setBackgroundMessageHandler(async (remoteMessage) => {
console.log('Message handled in the background!', remoteMessage);
});
function HeadlessCheck({ isHeadless }) {
if (isHeadless) {
// App has been launched in the background by iOS, ignore
return null;
}
return <App />;
}
AppRegistry.registerComponent(appName, () => HeadlessCheck);
Try calling the showNotification method inside setBackgroundMessageHandler , this gets called when the app is not in foreground or killed state
messaging().setBackgroundMessageHandler(async (remoteMessage) => {
console.log('Message handled in the background!', remoteMessage);
const options = {
soundName: 'default',
playSound: true,
};
const {title, body, data} = remoteMessage;
localNotificationService.showNotification(
title,
body,
data,
options,
}
});

How to create React Native Firebase v7 push notification Channel

I have install the react native firebase notificaiton ,notifications are working fine but when i try to send custom sound it wont work.
I find out that on Android version > 7 we have to create firebase channel in order to play custom sound but i dont know how to and where to create notification channel.
I have created two files inside the src folder of the root folder of my project where i handle notificatons.
1.LocalNotificationService.js
2.FcmService.js
Code for LocalNotificationService.js
import PushNotification from 'react-native-push-notification';
import {Platform} from 'react-native';
// import { notifications } from "react-native-firebase";
class LocalNotificationService {
configure = (onOpenNotification) => {
PushNotification.configure({
onRegister: function (token) {
console.log('[LocalNotificationService] onRegister', token);
},
onNotification: function (notification) {
console.log('[LocalNotificationService] onNotification', notification);
if (!notification?.data) {
return;
}
notification.userInteraction = true;
onOpenNotification(
Platform.OS === 'ios' ? notification.data.item : notification.data,
);
//Only call callback if not from foreground
if (Platform.OS === 'ios') {
notification.finish(PushNotificationIOS.FetchResult.NoData);
}
},
// IOS ONLY (optional): default: all - Permissions to register.
permissions: {
alert: true,
badge: true,
sound: true,
},
// Should the initial notification be popped automatically
// default: true
popInitialNotification: true,
/**
* (optional) default: true
* - Specified if permissions (ios) and token (android and ios) will requested or not,
* - if not, you must call PushNotificationsHandler.requestPermissions() later
* - if you are not using remote notification or do not have Firebase installed, use this:
* requestPermissions: Platform.OS === 'ios'
*/
requestPermissions: true,
});
};
unregister = () => {
PushNotification: this.unregister();
};
showNotification = (id, title, message, data = {}, options = {}) => {
PushNotification.localNotification({
...this.buildAndroidNotification(id, title, message, data, options),
title: title || '',
message: message || '',
playSound: options.playSound || true,
soundName: options.soundName || 'default',
// sound:'test',
userInteracsstion: false, /// boolean if the condition was opened by the user from the notification
});
};
buildAndroidNotification = (id, title, message, data = {}, options = {}) => {
return {
id: id,
// sound:"test",
autoCancel: true,
largeIcon: options.largeIcon || 'icon',
smallIcon: options.smallIcon || 'test_icon',
bigText: message || '',
subText: title || '',
color: 'green',
vibrate: options.vibrate || true,
vibration: options.vibration || 1000,
priority: options.priority || ' high',
importance: options.importance || 'high', // (options) set notification importance , default high
// data : data,
};
};
cancelAllLocalNotification = () => {
if (Platform.OS === 'ios') {
PushNotificationIOS.removedAllDeliveredNotification();
} else {
PushNotification.cancelAllLocalNotification();
}
};
removedDeliveredNotificationById = (notificationId) => {
console.log(
'[LocalNotificationService] removeDeliveredNotificationById: ',
notificationId,
);
PushNotification.cancelLocalNotfication({id: `${notificationId}`});
};
}
export const localNotificationService = new LocalNotificationService();
Code for FcmService.js
import messaging from '#react-native-firebase/messaging'
// import type {Notification,NotificationOpen} from 'react-native-firebase'
import { Platform } from 'react-native'
class FCMService {
register = (onRegister,onNotification,onOpenNotification) => {
this.checkPermission(onRegister)
this.createNotificationListeners(onRegister,onNotification,onOpenNotification)
}
registerAppWithFCM = async() => {
if(Platform.OS === "ios"){
await messaging().registerDeviceForRemoteMessages();
await messaging().setAutoInitEnabled(true)
}
}
checkPermission = (onRegister) => {
messaging().hasPermission()
.then(enabled => {
if(enabled) {
//User has permission
this.getToken(onRegister)
}
else{
//User Dont have permission
this.requestPermission(onRegister)
}
}).catch(error => {
console.log("Permission Rejected",error)
})
}
getToken = (onRegister) => {
messaging().getToken()
.then(fcmToken => {
if(fcmToken) {
onRegister(fcmToken)
}
else{
console.log("User Dont ave a Device Token")
}
}).catch(error => {
console.log("get token rejected", error)
})
}
requestPermission = (onRegister) => {
messaging().requestPermission()
.then(() => {
this.getToken(onRegister)
}).catch(error => {
console.log("Request Permission Rejected",error)
})
}
deleteToken = () => {
console.log("Delete Token")
messaging().deleteToken()
.catch(error => {
console.log("Delete token error",error)
})
}
createNotificationListeners = (onRegister, onNotification,onOpenNotification) => {
messaging().onNotificationOpenedApp(remoteMessage => {
console.log("onNotificationOpenedApp notification caused to open app")
if(remoteMessage){
const notification = remoteMessage.notification
onOpenNotification(notification)
}
});
//When the application is opened from a quite state.
messaging().getInitialNotification().then(remoteMessage => {
console.log("getInitialNotification notification caused to open app")
if(remoteMessage){
const notification = remoteMessage.notification
onOpenNotification(notification)
}
})
//Foreground state messages
this.messageListner = messaging().onMessage(async remoteMessage => {
console.log("A new FCM Message Arrived",remoteMessage)
if(remoteMessage){
let notification = null
if(Platform.OS === "ios") {
notification = remoteMessage.data.notification
}else{
notification = remoteMessage.notification
}
onNotification(notification)
}
})
}
unRegister = () => {
}
export const fcmService = new FCMService()
App.js
import React , {useEffect,useState} from 'react'
import {View,StyleSheet,Text,Button,TextInput} from 'react-native'
import {fcmService} from './src/FCMService'
import {localNotificationService} from './src/LocalNotificationService'
import auth from '#react-native-firebase/auth';
export default function App() {
useEffect(() => {
fcmService.registerAppWithFCM()
fcmService.register(onRegister,onNotification,onOpenNotification)
localNotificationService.configure(onOpenNotification)
function onRegister(token) {
console.log("[App] onRegister: ",token)
setTokenwa(token)
}
function onNotification(notify) {
console.log("[App] onNotification: ",notify)
const options = {
soundName : 'test',
playSound : true
}
localNotificationService.showNotification(
0,
notify.title,
notify.body,
notify,
options
)
}
function onOpenNotification(notify) {
console.log("[App] onOpenNotification : " , notify)
alert("Open Notification" + notify.body)
}
return () => {
console.log("[App] unRegister")
fcmService.unRegister()
localNotificationService.unregister()
}
}, [])
const [confirm, setConfirm] = useState(null);
const [code, setCode] = useState('');
const [tokenwa, setTokenwa] = useState('');
// Handle the button press
async function signInWithPhoneNumber(phoneNumber) {
const confirmation = await auth().signInWithPhoneNumber(phoneNumber);
setConfirm(confirmation);
}
async function confirmCode() {
try {
console.log("code send")
await confirm.confirm(code);
} catch (error) {
console.log('Invalid code.');
}
}
if (!confirm) {
return (
<Button
title="Phone Number Sign In"
onPress={() => signInWithPhoneNumber('+91 7769948296')}
/>
);
}
return (
<>
<Text>{tokenwa}</Text>
<View style={styles.container}>
<Text>Sample React Native Firebase </Text>
<Button title="Press Me" onPress={() => localNotificationService.cancelAllLocalNotification}></Button>
<TextInput value={code} placeholder="test" onChangeText={text => setCode(text)} />
<Button title="Confirm Code" onPress={() => confirmCode()} />
</View>
</>
)
}
const styles = StyleSheet.create({
container : {
flex : 1,
alignItems : 'center',
justifyContent : 'center'
}
})

Redux-Thunk: Actions must be plain objects. Use custom middleware for async actions

Can't solve this problem, using react-native and redux-thunk.
I am trying to post data to firebase.io and repeatedly get the same error: Actions must be plain objects. Use custom middleware for async actions.
reducers/index.js
import { createStore, combineReducers, compose, applyMiddleware } from 'redux';
import thunk from 'redux-thunk'
import PlacesReducer from './placesReducer'
const rootReducer = combineReducers({
places : PlacesReducer,
});
let composeEnhancers = compose;
if (__DEV__) {
composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
}
const configureStore = () => {
return createStore(rootReducer, applyMiddleware(thunk));
};
export default configureStore;
actions/index.js
export const addPlace = (placeName, location, image) => {
return dispatch => {
const placeData = {
name: placeName,
location: location
};
fetch("https://awesome-places-b592c.firebaseio.com/placesReducer.json", {
method: "POST",
body: JSON.stringify(placeData)
})
.catch(err => console.log(err))
.then(res => res.json())
.then(parsedRes => {
console.log(parsedRes);
});
};
};
reducers/placesReducer.js
const initialState = {
places: []
};
const reducer = (state = initialState, action) => {
switch (action.type) {
case "ADD_PLACE":
return {
...state,
places: state.places.concat({
key: Math.random(),
name: action.placeName,
image: {
uri: action.image.uri,
location: action.location
}
})
};
default:
return state;
}
};
export default reducer;
All help is appreciated, thank you.
UPDATE
Added initialState argument to the createStore() function in reducers/index.js
const configureStore = () => {
return createStore(rootReducer, {places: []}, applyMiddleware(thunk));
};
Still receiving the same error
You need to dispatch the actions after the async request is completed
.then(parsedRes => {
console.log(parsedRes);
dispatch({
type: YOUR_REDUCER_TYPE,
parsedRes
})
});
Also as mentioned in the createStore docs, you need to add the initialState
(reducer, preloadedState, enhancer)
Try updating the code as follows:
export const addPlace = (placeName, location, image) => {
//return dispatch => {
const placeData = {
name: placeName,
location: location
};
fetch("https://awesome-places-b592c.firebaseio.com/placesReducer.json", {
method: "POST",
body: JSON.stringify(placeData)
})
.catch(err => console.log(err))
.then(res => res.json())
.then(parsedRes => {
console.log(parsedRes);
// you may tweak this
// use ...parsedRes following the reducer code you paste,
// I assume location, placeName and image are inside parsedRes
dispatch({ type:"ADD_PLACE", ...parsedRes })
});
//};
};
Then in the reducer:
const reducer = (state = initialState, action) => {
switch (action.type) {
case "ADD_PLACE":
// check the action content
console.log(action)
return {
...state,
places: state.places.concat({
key: Math.random(),
name: action.placeName,
image: {
uri: action.image.uri,
location: action.location
}
})
};
default:
return state;
}
};

Categories

Resources