我正在使用react-navigation
和react-native-push-notification
。如何在回调中打开某个StackNavigator's
屏幕onNotification
?应该在以下情况下工作:
- 应用已关闭
- 应用位于前台
- 应用程序在后台
我现在只需要它在安卓上工作。
我尝试将回调函数传递给组件中的通知:
_handleClick() {
PushNotification.localNotification({
foreground: false
userInteraction: false
message: 'My Notification Message'
onOpen: () => { this.props.navigation.navigate("OtherScreen") },
})
}
并在PushNotification
配置中触发onOpen
:
onNotification: function(notification) {
notification.onOpen()
}
但似乎函数不能传递给通知,除非值是字符串,否则它会被忽略,从而导致onOpen
未定义。
好的,似乎我必须发布我自己的解决方案:)
// src/services/push-notification.js
const PushNotification = require('react-native-push-notification')
export function setupPushNotification(handleNotification) {
PushNotification.configure({
onNotification: function(notification) {
handleNotification(notification)
},
popInitialNotification: true,
requestPermissions: true,
})
return PushNotification
}
// Some notification-scheduling component
import {setupPushNotification} from "src/services/push-notification"
class SomeComponent extends PureComponent {
componentDidMount() {
this.pushNotification = setupPushNotification(this._handleNotificationOpen)
}
_handleNotificationOpen = () => {
const {navigate} = this.props.navigation
navigate("SomeOtherScreen")
}
_handlePress = () => {
this.pushNotification.localNotificationSchedule({
message: 'Some message',
date: new Date(Date.now() + (10 * 1000)), // to schedule it in 10 secs in my case
})
}
render() {
// use _handlePress function somewhere to schedule notification
}
}
我在Firebase的官方网站上找到了这个解决方案,这似乎是最好的示例/示例工作。下面是示例片段以及随附的链接。希望它能帮助别人。
import React, { useState, useEffect } from 'react';
import messaging from '@react-native-firebase/messaging';
import { NavigationContainer, useNavigation } from '@react-navigation/native';
import { createStackNavigator } from '@react-navigation/stack';
const Stack = createStackNavigator();
function App() {
const navigation = useNavigation();
const [loading, setLoading] = useState(true);
const [initialRoute, setInitialRoute] = useState('Home');
useEffect(() => {
// Assume a message-notification contains a "type" property in the data payload of the screen to open
messaging().onNotificationOpenedApp(remoteMessage => {
console.log(
'Notification caused app to open from background state:',
remoteMessage.notification,
);
navigation.navigate(remoteMessage.data.type);
});
// Check whether an initial notification is available
messaging()
.getInitialNotification()
.then(remoteMessage => {
if (remoteMessage) {
console.log(
'Notification caused app to open from quit state:',
remoteMessage.notification,
);
setInitialRoute(remoteMessage.data.type); // e.g. "Settings"
}
setLoading(false);
});
}, []);
if (loading) {
return null;
}
return (
<NavigationContainer>
<Stack.Navigator initialRouteName={initialRoute}>
<Stack.Screen name="Home" component={HomeScreen} />
<Stack.Screen name="Settings" component={SettingsScreen} />
</Stack.Navigator>
</NavigationContainer>
);
}
链接: https://rnfirebase.io/messaging/notifications#handling-interaction
看到我如何使用旧版react-native-firebase
,我想 id 发布了我针对此问题的解决方案,因为它与上述使用 RN-firebase V6 的答案之一略有不同。我的解决方案只是略有不同,此解决方案适用于 react-native-firebase
v5.x 的通知处理:
import * as React from 'react';
import { Text, TextInput } from 'react-native';
import AppNavigation from './src/navigation';
import { Provider } from 'react-redux';
import { store, persistor } from './src/store/index.js';
import 'react-native-gesture-handler';
import firebase from 'react-native-firebase';
import { PersistGate } from 'redux-persist/integration/react';
export default class App extends React.Component {
constructor(props) {
super(props);
if (firebase.apps.length === 0) {
firebase.initializeApp({});
}
}
async componentDidMount() {
// Initialize listener for when a notification has been displayed
this.removeNotificationDisplayedListener = firebase.notifications().onNotificationDisplayed((notification) => {
// process notification as required... android remote notif's do not have a "channel ID".
});
// Initialize listener for when a notification is received
this.removeNotificationListener = firebase.notifications().onNotification((notification) => {
// Process notification
});
// Listener for notification tap if in FOREGROUND & BACKGROUND
this.removeNotificationOpenedListener = firebase.notifications().onNotificationOpened((notificationOpen) => {
// get the action trigger by the notification being opened
const action = notificationOpen.action;
// get info about the opened notification
const info = notificationOpen.notification;
// log for testing
console.log('ACTION => ' + action + 'nNOTIFICATION INFO => ' + JSON.stringify(info));
});
// Listener for notification tap if app closed
const notificationOpen = await firebase.notifications().getInitialNotification();
if (notificationOpen) {
// App was opened by notification
const action = notificationOpen.action;
const info = notificationOpen.notification;
// log for testing:
console.log('ACTION => ' + action + 'nNOTIFICATION INFO => ' + JSON.stringify(info));
}
}
componentWillUnmount() {
// Invoke these functions to un-subscribe the listener
this.removeNotificationDisplayedListener();
this.removeNotificationListener();
this.removeNotificationOpenedListener();
}
render() {
return (
<Provider store={store}>
<PersistGate loading={null} persistor={persistor}>
<AppNavigation />
</PersistGate>
</Provider>
);
}
}
此信息可能对某人有用。
在我的方案中,如果用户收到通知但尚未登录,则应用不应将他们重定向到所需的屏幕。
如果用户不在登录屏幕上,并且用户按下通知,我们应该重定向他们(在我的例子中是 Screen2(。
为此,我将导航参考发送到我的NotificationHelper
用:
@react-navigation/native: 6.X
@react-native-firebase/messaging: 17.x
@notifee/react-native: 7.x
法典:
MainScreen.tsx
import { createNavigationContainerRef } from '@react-navigation/native';
import { createNativeStackNavigator } from '@react-navigation/native-stack';
const MainScreen: React.FC = () => {
const Stack = createNativeStackNavigator();
const navigationRef = createNavigationContainerRef();
return (
<NavigationContainer ref={navigationRef}>
<Stack.Navigator screenOptions={{ headerShown: false }}>
<Stack.Screen name="Login" component={LoginScree} />
<Stack.Screen name="Screen1" component={Screen1} />
<Stack.Screen
name="Screen2"
component={Screen2}
/>
</Stack.Navigator>
<NotificationHelper navigationRef={navigationRef} />
</NavigationContainer>
);
};
NotificationHelper.tsx
import messaging, {
FirebaseMessagingTypes,
} from '@react-native-firebase/messaging';
import { NavigationContainerRefWithCurrent } from '@react-navigation/native';
import { FC, useCallback, useEffect } from 'react';
type PropsType = {
navigationRef: NavigationContainerRefWithCurrent<ReactNavigation.RootParamList>;
};
const NotificationHelper: FC<PropsType> = (props: PropsType) => {
const redirectToScreen = useCallback(
(notification: any) => {
if (props.navigationRef) {
const currentRoute = props.navigationRef.getCurrentRoute()?.name;
if (currentRoute) {
if (currentRoute !== 'Login') {
props.navigationRef.navigate('Screen2', {
param1: notification.property1,
param2: notification.property2,
});
}
}
}
},
[props.navigationRef],
);
useEffect(() => {
const unsubscribeOpenedApp = messaging().onNotificationOpenedApp(
async (remoteMessage) => {
if (remoteMessage.data) {
console.debug('User pressed notification');
redirectToScreen(remoteMessage.data);
}
},
);
const unsubscribeForegroundOpenApp = notifee.onForegroundEvent(
({ type, detail }) => {
switch (type) {
case EventType.PRESS:
console.debug('User pressed notification');
if (detail.notification && detail.notification.data) {
redirectToScreen(
detail.notification.data,
);
}
break;
}
},
);
return () => {
unsubscribeOpenedApp();
unsubscribeForegroundOpenApp();
};
}, [redirectToScreen]);
return null;
};
export default NotificationHelper;