Using the PushNotificationIOS library, I am able to get the deviceToken on the register event:
const registerPN = PushNotificationIOS.addEventListener('register', deviceToken => {
console.log("Registering Push Notification Token", deviceToken);
store.dispatch(setPushNotificationToken(userPushNotificationToken));
});
However, if the user initially rejects the notification question, we push them to update the settings through:
Alert.alert(
'Action Required',
`To turn notifications on, you'll need to update your settings`,
[
{
text: 'Go to settings',
onPress: () => {
Linking.openURL('app-settings:');
}
},
{
text: 'Cancel',
style: 'cancel'
}
]
)
If the user then goes to the settings panel, and returns, the 'register' event does not seem to be called, so I'm not sure how to get the device token.
How can I add a listener for the 'settings' update so that I can store the token for pushes from the server?
Figured it out.
With a PushNotificationIOS.checkPermissions() call, you can check if they have changed. If so, fire off a PushNotificationIOS.requestPermissions() call that will automatically fire the listener with the correct token.
Related
I am calling forgotPassword api in the app and once its response comes from and state changes in reducer i get callback as i have useEffect in my component. I want to show user an alert that his password is reset successfully, but it shows only for 1 sec and goes away, i think whole view renders again. How can i make alert to staty until use taps on the button in alert.
useEffect(() => {
if (forgotPasswordData != null) {
Alert.alert('Success',forgotPasswordData.message, [{
text: 'OKAY',
onPress: () => {
dispatch({
type: authActions.RESET_FORGOT_PASSWORD_DATA,
});
console.log("Hello")
setEmail('');
setselectedAssociation(null);
setAssociationName('');
}
}]
);
}
}, [forgotPasswordData]);
When forgotPasswordData reset, useEffect will rerender again so the best option to alert the user is where you're getting a response.
You can create a callback function and define Alert in it and pass this callback to action and in Saga where you get a result, you can trigger this callback so It will Alert on view.
I am new to react native and I have react native app for android and I am using Navigation 5 for navigating to the next page. The application workflow is loginScreen -> HomeScreen -> ExistingStockScreen -> ScanSkidBarcodeScreen -> ScanItemsScreen.
I am handling backbutton press with this code on ScanItemScreen.
navigation.addListener('beforeRemove', (e) => {
// Prevent default behavior of leaving the screen
e.preventDefault();
if (this.state.items[0].barCode !== "" && this.state.items[5].barCode !== "") {
Alert.alert(
'Error!',
'You can only scan six items at a time.',
[
{ text: "OK", style: 'cancel', onPress: () => { } },
]
);
}
else if (this.state.items[0].barCode !== "") {
Alert.alert(
'Attention!',
'You have unsaved items. Please click on UPDATE STATUS first and go back.',
[{ text: "OK", style: 'cancel', onPress: () => { } },
{
text: 'Go Back',
style: 'destructive',
// If the user confirmed, then we dispatch the action we blocked earlier
// This will continue the action that had triggered the removal of the screen
onPress: () => navigation.dispatch(e.data.action),
},]
);
} else {
navigation.dispatch(e.data.action)
}
})
}
However navigation.dispatch(e.data.action) code is going to back screen but it logs out the user for some reason.
So I am thinking to use navigation.goBack() instead.
What's the difference between navigation.goBack() and navigation.dispatch(e.data.action) ?
The beforeRemove event is triggerred when the screen is being removed, which can happen because of various reasons (such as a reset or another action). While going back is one of the ways to trigger it, it's not the only way.
From the docs:
The user pressed back button on a screen in a stack
The user performed a swipe back gesture
Some action such as pop or reset was dispatched which removes the screen from the state
The object in e.data.action refers to the action which triggered that event. By dispatching that action again with navigation.dispatch(e.data.action), you continue the action after performing whatever check you needed e.g. prompting the user.
If you don't dispatch the event again and instead try to goBack():
It'll be incorrect behaviour - if a reset triggered the event, you should continue the reset (or whaetver triggered the event), not perform a different action entirely
It won't work anyway, because goBack will just trigger the event, so you'll be stuck in a loop of prompts
However navigation.dispatch(e.data.action) code is going to back screen but it logs out the user for some reason
React Navigation doesn't interact with your app state. If your user is being logged out on navigation, that's a bug in your code that you need to debug and fix.
I'm using this package for implementing local push notification:
https://github.com/zo0r/react-native-push-notification
I'm using action button like this to show buttons in my notification along with a text and a title:
PushNotification.localNotification({
...
actions: '["Yes", "No"]'
})
I wanted to know how I can call a function when user clicks on of these actions and app becomes visible?
I've tried PushNotification.configure in my componentDidMount method in my home screen like this but nothing comes up in the console:
PushNotification.configure({
// (required) Called when a remote or local notification is opened or received
onNotification: function(notification) {
console.log("NOTIFICATION:", notification);
if (notification.userInteraction) {
console.log("NOTIFICATION:");
}
// process the notification
}
});
I got it working.
In your App.js you need to set popInitialNotification to true. Something like this:
async componentDidMount() {
PushNotification.configure({
// (required) Called when a remote or local notification is opened or received
onNotification: function(notification) {
console.log("NOTIFICATION:", notification.action);
},
// 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
*/
requestPermissions: true
});
}
notification.action will gibe you the label of the button clicked.
In your button/app active event you forgot to call to schedule the notification and actually set when it will arise, so you need to
PushNotification.localNotificationSchedule(details: Object)
Schedule it for now with the same id, then your notification will come up immediately.
See all options for scheduling here
import PushNotificationAndroid from 'react-native-push-notification'
(function() {
// Register all the valid actions for notifications here and add the action handler for each action
PushNotificationAndroid.registerNotificationActions(['Accept','Reject','Yes','No']);
DeviceEventEmitter.addListener('notificationActionReceived', function(action){
console.log ('Notification action received: ' + action);
const info = JSON.parse(action.dataJSON);
if (info.action == 'Accept') {
// Do work pertaining to Accept action here
} else if (info.action == 'Reject') {
// Do work pertaining to Reject action here
}
// Add all the required actions handlers
});
})();
DO NOT USE .configure() INSIDE A COMPONENT, EVEN App
If you do, notification handlers will not fire, because they are not loaded. Instead, use .configure() in the app's first file, usually index.js.
It's mentioned in the documentation.
Try to follow their example for implementation It will help you to setup in your project.
I am using react-native-fcm library for android device. I am getting notification properly when my application is running, but when my application is in the background or killed then I am getting notification data in JSON format similarly in an image I shared here.
componentDidMount() {
// iOS: show permission prompt for the first call. later just check permission in user settings
// Android: check permission in user settings
FCM.requestPermissions().then(()=>console.log('granted')).catch(()=>console.log('notification permission rejected'));
/*FCM.getFCMToken().then(token => {
console.log('Token',token)
// store fcm token in your server
});*/
this.notificationListener = FCM.on(FCMEvent.Notification, async(notif) => {
console.log('FCM notification', notif)
this.sendRemote(notif)
});
// initial notification contains the notification that launchs the app. If user launchs app by clicking banner, the banner notification info will be here rather than through FCM.on event
// sometimes Android kills activity when app goes to background, and when resume it broadcasts notification before JS is run. You can use FCM.getInitialNotification() to capture those missed events.
// initial notification will be triggered all the time even when open app by icon so send some action identifier when you send notification
/*FCM.getInitialNotification().then(notif => {
console.log('FCM', notif)
this.sendRemote(notif)
//console.log('Initial Notification',notif)
});*/
FCM.getInitialNotification().then((notif: any) => {
// for android/ios app killed state
console.log("ifAny",notif)
if (notif) {
console.log("Any",notif)
// there are two parts of notif. notif.notification contains the notification payload, notif.data contains data payload
}
});
}
sendRemote(notif) {
var data = notif.fcm.body;
var title = notif.fcm.title;
FCM.presentLocalNotification({
title: 'App Name',
body: title,
big_text: title,
large_icon: 'ic_launcher',
priority: 'high',
sound: "default",
click_action: this.clickActions(notif),
show_in_foreground: true,
wake_screen: true,
local: true,
param: notif.notify_about,
paramData: data
});
}
notify_about:'',
fcm:{action:null,
body:"{data:'',time:''}",
color:null,
icon: '',
tag:null,
title:"Notification title"}
this is my data format which I am sending from the server.
Here I want to show only data body. But when the app is killed or in the background, it shows the complete body in the notification.And Its working fine when the app is running.
I am using react native v0.45.1.
How can I add to my application notification (no matter if the app is in the background or foreground) that the user can remove only after click an acknowledge button.
I don't want the user to swipe the notification aside without notice it.
how can it be done?
I am not sure https://github.com/wix/react-native-notifications will do what I need.
Edit
I want to have a notification that will act like:
'USB debugging connected
'Touch to disable USB debugging'
The notification can't be removed unless the user actively do something, in my case it will be 'click' on a button
after a lot of digging the solution I implemented was:
setting repeat interval for the notification.
for android:
repeatType: 'time',
repeatTime: timeSpan,
for iOS:
repeatType: 'minute',
when the user click the notification (decided its not the right approached to add actions - buttons - to notification):
PushNotification.configure({
onNotification: (notification) => {
console.log('NOTIFICATION:', notification);
const clicked = notification.userInteraction;
if (clicked) {
if (Platform.OS === 'ios') {
PushNotification.cancelLocalNotifications({ id: notification.data.id });
} else {
PushNotification.cancelLocalNotifications({ id: notification.id });
}
}
},
});
I am aware that this might not be the exact answer to this question. However,
I was looking for a similar solution earlier; how to remove notifications that hasn't been dismissed or opened by a user.
Sometimes the user might open the application / screen, without clicking on the notification. The notification will still be displayed in that case.
Using React Native with Expo, this is the solution I created for removing old notifications created using their Push Notification API.
import * as Notifications from "expo-notifications";
//...
// Remove notifications that exists for this conversation!
useEffect(() => {
Notifications.getPresentedNotificationsAsync().then(res => {
for (let k in res) {
if (
res[k].request.content.data &&
res[k].request.content.data.screen === "Conversations" &&
res[k].request.content.data.conversationId === conversationId
) {
Notifications.dismissNotificationAsync(res[k].request.identifier);
console.log("removed a notification for this conversation");
}
}
});
}, []);
By using the data sent to the Push Notification API, we can determine which notifications should be removed. in this case all notifications containing a conversationId matching the current value from the route are dismissed.