I'm trying to integrate react-native-freshchat-sdk to react native app, but when firebase remote message is coming, freshchatNotification is 0, but it should be 1. Even if I pass notification to Freshchat.handlePushNotification nothing happens. I assume Freshchat.handlePushNotification should navigate the user to the conversation
Actual result
freshchatNotification is 0 if it is fcm notification
Freshchat.handlePushNotification(notification) does nothing
Expected result:
freshchatNotification should be equal 1 if it is fcm notification
Freshchat.handlePushNotification(notification) should navigate the user to the chat
import messaging from '#react-native-firebase/messaging'
import { Freshchat} from 'react-native-freshchat-sdk'
//...
useEffect(() => {
const unsubscribe = messaging().onMessage(notification => {
Freshchat.isFreshchatNotification(notification, (freshchatNotification) => {
Freshchat.handlePushNotification(notification);
if (freshchatNotification) {
Freshchat.handlePushNotification(notification);
} else {//...}
})
});
return unsubscribe
}, [])
See push notification payload below:
Faced similar issue, worked by passing notification.data instead of direct notification object to Freshchat
useEffect(() => {
const unsubscribe = messaging().onMessage(notification => {
Freshchat.isFreshchatNotification(notification.data, (freshchatNotification) => {
Freshchat.handlePushNotification(notification);
if (freshchatNotification) {
Freshchat.handlePushNotification(notification.data);
} else {//...}
})
});
return unsubscribe
}, [])
Related
My app asks permission to use location services.
If a user denies permission, they can click a button to go to the settings page and grant permissions.
On ios, they are given the option to return directly to the app. on Android, I think they can do something similar.
Is there a way to detect arriving back at the app so I can check their permissions again?
I've tried with React Navigation's useFocusEffect hook:
useFocusEffect(
React.useCallback(() => {
console.log("navigated")
return () => getPosition()
}, [])
)
But unfortunately, that only works when navigating between screens/routes in the app.
Is there a way to detect the app transitioning from background to foreground?
You can track app state with https://reactnative.dev/docs/appstate
in pseudo-code: if previously 'background' and now 'active' then run your effects
Ciao, when I want to manage permission, I use react-native-permissions. In this way you can manage all permissions directly in your app without exit from it.
Works well for iOs and Android. In your case, you could something like:
import {check, PERMISSIONS, RESULTS} from 'react-native-permissions';
check(<permission you need>)
.then((result) => {
switch (result) {
case RESULTS.UNAVAILABLE:
console.log(
'This feature is not available (on this device / in this context)',
);
break;
case RESULTS.DENIED:
console.log(
'The permission has not been requested / is denied but requestable',
);
break;
case RESULTS.GRANTED:
console.log('The permission is granted');
break;
case RESULTS.BLOCKED:
console.log('The permission is denied and not requestable anymore');
break;
}
})
.catch((error) => {
// …
});
Use this hook:
// hooks/useAppIsActive.ts
import { useCallback, useEffect, useRef } from "react";
import { AppState } from "react-native";
export default (callback: Function) => {
const appStateRef = useRef(AppState.currentState);
const handleAppStateChange = useCallback((nextAppState) => {
if (
appStateRef.current.match(/inactive|background/) &&
nextAppState === "active"
) {
callback();
}
appStateRef.current = nextAppState;
}, []);
useEffect(() => {
AppState.addEventListener("change", handleAppStateChange);
return () => {
AppState.removeEventListener("change", handleAppStateChange);
};
}, []);
};
And from the component you want to detect "the come back", pass by parameter the callback you want to run:
const MyView = () => {
const requestLocationAccess = useCallback(() => {
// request permissions...
}, [])
useAppIsActive(() => requestLocationAccess());
}
I am implementing FCM notifications in an Ionic React application. I am having trouble navigating to another page to display the notification details.
I have created a FCMService class in my react App, and initialising this in the index.ts file.
// FCMService.ts
export default class FCMService {
public static Instance: FCMService;
private _store: Store<IAppState>;
constructor(store: Store<IAppState>) {
this._store = store;
}
public static Initalise(store: Store<IAppState>) {
if (!FCMService.Instance) {
FCMService.Instance = new FCMService(store);
FCMService.Instance.InitaliseFCM();
FCMService.Instance._store.subscribe(() => { console.log(store.getState()) });
} else {
console.debug("FCM service already intialised. Please use FCMService.Instance");
}
}
private InitaliseFCM() {
// Request permission to use push notifications
// iOS will prompt user and return if they granted permission or not
// Android will just grant without prompting
PushNotifications.requestPermission().then(result => {
console.log(result);
if (result.granted) {
// Register with Apple / Google to receive push via APNS/FCM
PushNotifications.register();
} else {
// Show some error
}
});
// On success, we should be able to receive notifications
PushNotifications.addListener('registration', (token: PushNotificationToken) => {
console.log(token);
localStorage.setItem("FCM_TOKEN", token.value);
}
);
// Some issue with our setup and push will not work
PushNotifications.addListener('registrationError',
(error: any) => {
console.log(error);
}
);
// Show us the notification payload if the app is open on our device
PushNotifications.addListener('pushNotificationReceived',
(notification: PushNotification) => {
console.log(notification);
let data = notification.notification.data as INotificationData;
}
);
// Method called when tapping on a notification
PushNotifications.addListener('pushNotificationActionPerformed',
(notification: PushNotificationActionPerformed) => {
console.log(notification);
let data = notification.notification.data as INotificationData;
this._store.dispatch(setNotificationActionCreator(data));
}
);
}
}
and then the index.ts
const store = configureStore();
interface MainProps {
store: Store<IAppState>;
}
FCMService.Initalise(store);
ReactDOM.render(<Provider store={store}><App /> </Provider>, document.getElementById('root'));
serviceWorker.unregister();
I even tried using the Redux store to save the notification on Tap - and then that would publish the notification change event (which might of worked - if I could access the useHistory() hook in the App.tsx file)
This was my attempt at navigating via Redux store in App.tsx
const App: React.FC<IProps> = ({ getCompanies, getUser, notification }) => {
console.log('app');
console.log(process.env);
const history = useHistory();
if(notification){
history.push(`/page/plot-position/{notification.id}`);
}
return (
<IonApp>
<IonReactRouter>
<IonSplitPane contentId="main" when="false">
<Menu />
<IonRouterOutlet id="main">
<Route path="/login" component={LoginPage} exact />
<PrivateRoute path="/page/plot-position/:notificationId/" component={PlotPositionPage} exact />
<Redirect from="/" to="/login" exact />
</IonRouterOutlet>
</IonSplitPane>
</IonReactRouter>
</IonApp>
);
};
const mapStateToProps = (store: IAppState) => {
return {
user: store.user.user as UserDTO,
notification: store.notificationState.notification
};
};
const mapDispatchToProps = (dispatch: any) => {
return {
getCompanies: () => dispatch(getCompaniesStartActionCreator()),
getUser: () => dispatch(getUserStartActionCreator())
}
};
export default connect(mapStateToProps, mapDispatchToProps)(App);
It looks like your navigation works, but you're having trouble passing the notification object through to the page? You can pass the object through history state.
To access the useHistory hook you would need to make your FCMService a custom hook.
const useFCMService = (): void => {
const history = useHistory();
React.useEffect(() => {
// Method called when tapping on a notification
PushNotifications.addListener('pushNotificationActionPerformed',
(action: PushNotificationActionPerformed) => {
const notification = action.notification.data as INotificationData;
history.push({ pathname: '/page/plot-position/', state: { notification } });
}
);
}, []);
}
And then include your useFCMService custom hook in your App component.
const App: React.FC<IProps> = ({ getCompanies, getUser }) => {
useFCMService();
...
};
Deep linking provides us a way to do this: Using both an action to open the application and an action at opening the application we can enroute the user to the correct destination.
Opening the application
Here we will create an action to open the url when the user taps on the push notification; to do this less use a listener:
const {PushNotifications, App} = Plugins
***
PushNotifications.addListener(
"pushNotificationActionPerformed",
(notification: PushNotificationActionPerformed) =>{
const data = notification.notification.data;
if (data.packageNumber) App.openUrl({url: `com.company.appname://tabs/package-details/${data.packageNumber}`})
else App.openUrl({url:'/tabs'})
}
)
com.company.app:// is of capital importance since the app must reach the application must reach an existing given url, otherwise the following action(catching the url) won't be triggers since it waits a complete true from the App.openUrl function; as we are opening an internal url, this must begin with the apps given name in the capacitor config page(see the following example where we can realize how use the local url).
In this way we are adding a function to open the application in an specific route.
Redirecting the user
Here, we will complete the application's part from the deep linking tutorial: we create a new listener component who handles the appOpenUrl events and redirects to the user and we will put it on the main App file inside of its respective IonRouter:
const AppUrlListener: React.FC<any> = () => {
let history = useHistory();
useEffect(() => {
App.addListener('appUrlOpen', (data: any) => {
const slug = data.url.split(':/').pop();
if (slug) {
history.push(slug);
}
});
}, []);
return null;
};
Don't forget the route in router must begin with /, and since the application url contains :/, we split the url here and we get the second part, the slug; we push it on the history, triggering the router and getting the normal behaviour when you entering in a new route.
We will add this component inside of the router:
<IonReactRouter>
<IonSplitPane contentId="main">
<Menu />
<AppUrlListener />
<IonRouterOutlet id="main">
Now, the application will be listening the appOpenUrl event, and when it gets a new of this events, it will push the gotten url to the history, redirecting the user to that route.
I am trying to send push notification using Expo, and I receive it. But there is no vibrate or sound and no pop up as well on my device. I am using Galaxy S9 with Android 9. I have not tried on Iphone yet.
Push notification is sent by nodejs and the user who installed the app will receive the push notification. User expo token is saved in firebase database. I succeed to save and fetch the token.
Below is from expo app
class App extends Component {
componentWillMount() {
firebase.initializeApp(config);
this.registerForPushNotificationsAsync();
}
async registerForPushNotificationsAsync(){
const { status: existingStatus } = await Permissions.getAsync(
Permissions.NOTIFICATIONS
);
let finalStatus = existingStatus;
if (Platform.OS === 'android') {
Notifications.createChannelAndroidAsync('chat-messages', {
name: 'Chat messages',
sound: true,
priority: 'high', // was max
vibrate: [0, 250, 250, 250],
});
}
if (existingStatus !== 'granted') {
const { status } = await Permissions.askAsync(Permissions.NOTIFICATIONS);
finalStatus = status;
}
Below is from nodejs server-side
function sendMessage(to, title, body) {
const expo = new Expo();
let messages = [];
messages.push({
to, // Expo user token
body,
data: { withSome: 'data' },
ios: {
sound: true
},
android: {
"channelId": "chat-messages" //and this
}
})
let chunks = expo.chunkPushNotifications(messages);
let tickets = [];
(async () => {
for (let chunk of chunks) {
try {
let ticketChunk = await expo.sendPushNotificationsAsync(chunk);
tickets.push(...ticketChunk);
} catch (error) {
console.error(error);
}
}
})();
}
Also could we redirect to web page when user click the push notification?
I see three problems on your backend code ( expo push notification docs for reference https://docs.expo.io/versions/latest/guides/push-notifications/):
According to the docs, there should be no ios or android properties on the request body;
sound should be either 'default' or null, instead of true;
You created the notification channel on the device, but when you send the notification, you forgot to tell which channel you are sending to.
All that said, your code that calls the expo push notifications api should look something like this:
messages.push({
to, // Expo user token
title: 'some title', //it is good practice to send title, and it will look better
body,
data: { withSome: 'data' },
priority: 'high', //to make sure notification is delivered as fast as possible. see documentation for more details
sound: true, //for iOS devices and android below 8.0
channelId: 'chat-messages', //for devices on android 8.0 and above
})
I hope this helps.
Is there a way on how to receive push notification payload in IOS? In android it works by doing it this way:
firebase.messaging().onMessage((message: RemoteMessage) => {
// Process your message as required
});
however it does not work in ios. It tried:
firebase.notifications().displayNotification((notification) => {
console.log(notification);
});
or
firebase.notifications().onNotification((notification) => {
console.log(notification);
});
still nothing works. Thanks
Nevermind, I sorted it out by call it this way:
firebase.notifications().onNotificationDisplayed((notification: Notification) => {
console.log(notification);
});
firebase.notifications().onNotification((notification: Notification) => {
console.log(notification);
});
reading from the expo docs:
For iOS, you would be wise to handle push notifications that are
received while the app is foregrounded, because otherwise the user
will never see them. Notifications that arrive while the app are
foregrounded on iOS do not show up in the system notification list. A
common solution is to just show the notification manually. For
example, if you get a message on Messenger for iOS, have the app
foregrounded, but do not have that conversation open, you will see the
notification slide down from the top of the screen with a custom
notification UI.
What I don't understand is what is the best approach for that? is there an Expo API for showing such messages? or should I create an alert component of my own? It is not really clear from the docs.
Thanks.
This answer is outdated as of February 20, 2020. Please see https://stackoverflow.com/a/60344280/2441420 for how to show iOS Notification when your application is in the Foreground
There isn't an Expo API for showing those messages. You can use any 'toast' library of your choosing and display the notification message, but that should be all your code.
For example, this is how we are doing right now:
export default class HomeScreen extends React.Component {
componentDidMount() {
this.notificationSubscription = Notifications.addListener(
(notification) => this.handlePushNotification(notification),
);
}
handlePushNotification(notification) {
const { navigation } = this.props;
PushNotificationsService.handleNotification(notification, navigation);
}
(...)
import Toast from 'react-native-root-toast';
export default class PushNotificationsService {
static handleNotification(notification, navigation) {
if (notification.data.screen && notification.origin === 'selected') {
navigation.navigate(notification.data.screen);
}
Toast.show(notification.data.message);
}
}
Toast libraries include:
react-native-root-toast
react-native-easy-toast
react-native-simple-toast
Now you can just add that in one of your app entry point. The shouldShowAlert is what you want here
import * as Notifications from 'expo-notifications';
Notifications.setNotificationHandler({
handleNotification: async () => ({
shouldShowAlert: true,
shouldPlaySound: false,
shouldSetBadge: false,
}),
});
App.json :
{
"expo": {
"notification": {
"iosDisplayInForeground": true
}
}
DEMO
I'm not sure exactly when this was added to Expo, but as of Expo version 36 is easily doable.
To show Expo Push Notifications on iOS when your app is in the foreground, please do the following:
import { Vibration } from "react-native";
import { Notifications } from "expo";
import * as Permissions from "expo-permissions";
import Constants from "expo-constants";
registerForPushNotificationsAsync = async () => {
if (Constants.isDevice) {
const { status: existingStatus } = await Permissions.getAsync(
Permissions.NOTIFICATIONS
);
let finalStatus = existingStatus;
if (existingStatus !== "granted") {
const { status } = await Permissions.askAsync(
Permissions.NOTIFICATIONS
);
finalStatus = status;
}
if (finalStatus !== "granted") {
alert("Failed to get push token for push notification!");
return;
}
let token = await Notifications.getExpoPushTokenAsync();
console.log("Go to https://expo.io/notifications and copy the token below to easily send yourself a notification.");
console.warn("Notifications on iOS (and I believe Android) ONLY WORK ON A PHYSICAL DEVICE, not a simulator or emulator!!!")
console.log(token);
this.setState({ expoPushToken: token });
} else {
alert("Must use physical device for Push Notifications");
}
};
componentDidMount() {
this.registerForPushNotificationsAsync();
this._notificationSubscription = Notifications.addListener(
this._handleNotification
);
}
_handleNotification = async notification => {
if (notification.remote) {
Vibration.vibrate();
const notificationId = Notifications.presentLocalNotificationAsync({
title: "Follow #technoplato",
body: "To learn yourself goodly (also follow PewDiePie)",
ios: { _displayInForeground: true } // <-- HERE'S WHERE THE MAGIC HAPPENS
});
}
};
Quick and Easy Sanity Check
1) Go here: https://expo.io/notifications
2) Copy the token that is output to the terminal when your application is run.
3) Open your application on iOS.
4) Send a notification to yourself from https://expo.io/notifications and observe that it shows up even when your app is foregrounded.
Notes
Notifications WILL NOT BE RECEIVED ON AN IOS SIMULATOR
Expo makes Notifications ridiculously easy. I honestly can't believe it.
No idea why displayInForeground is false by default and not more prominent in the documentation. I'll submit a PR for it if I can.
Code originally found at this Snack: https://snack.expo.io/#documentation/pushnotifications?platform=ios
LocalNotification.ios._displayInForeground found here: https://docs.expo.io/versions/v36.0.0/sdk/notifications/#localnotification