我正在尝试使用本机应用程序和此插件react-native-push-notifications 来实现推送通知。我成功的是在应用程序运行时(在前台)收到通知,但我想做的是在应用程序关闭(后台)而不是运行时以及当我收到进入应用程序的通知时获得本地通知。
这是我的代码 -
PushNotification.createChannel({
channelId: "alarm-channel",
channelName: "Alarm Channel",
importance: 4,
vibrate: true,
});
};
const [selectedDate, setSelectedDate] = useState(new Date());
const handleDatePicker = (dateTime) => {
const fireDate = dateTime;
PushNotification.localNotificationSchedule({
channelId: "alarm-channel",
title: 'title',
id: alarmNotifData.id,
message: 'message',
date: fireDate ,
soundName: "Default",
actions: ["Snooze", "Stop Reminder"],
importance: Importance.HIGH,
playSound: true,
allowWhileIdle: true,
invokeApp: false,
priority: "high",
timeoutAfter: 50000,
autoCancel: false,
vibrate: true,
vibration: 500,
});
};
handleDatePicker(selectedDate);
如果您想在后台实现通知。我强烈建议采用
@notifee/react-native
包。
您可以使用 React Native AppState 来检查您当前是在应用程序的前台还是后台。
对于iOS,我个人喜欢使用
AppState.current === "inactive"
,因为它的生命周期始终是活动->非活动->后台。
对于 Android,我使用
AppState.current === "background"
,因为 Android 只有活动 -> 背景
// Outside of your Functional Component, Create a type called NotificationType.
// This will make it easy for you to choose between which in app notification you send
export enum NotificationType {
Eating = "EATING",
Sleeping = "SLEEPING",
}
// Notification ID is used for Android, I only need one personally
export enum NotificationID {
DefaultID = "default",
}
接下来,对于您要通知的文件,导入 AppState 和 notifee
import {AppState} from "react-native"
import notifee from "@notifee/react-native";
在应用程序设置代码中为 appState 创建一个状态变量并设置 AppState 监听器
const [appState, setAppState] = useState(AppState.currentState);
// This is used as a callback function whenever AppState changes
const handleAppStateChange = useCallback(
(newState: any) => {
console.log(`AppState changed to ${newState}`);
setAppState(newState);
},
[]
);
// Initial useEffect to set things up
useEffect(() => {
let isActive = true;
let appStateSubscriber: NativeEventSubscription;
const loadNavSubscriber = async () => {
if (isActive) {
// Adding the listener for whether the user leaves the app
console.log(`Adding AppState event listener`);
appStateSubscriber = AppState.addEventListener("change",
handleAppStateChange);
}
};
loadNavSubscriber();
// It's always good practice to ask the user for notification permissions
const getNotificationPermissions = async () => {
if (isActive) {
const settings = await notifee.requestPermission();
}
};
getNotificationPermissions();
return () => {
isActive = false;
if (appStateSubscriber) appStateSubscriber.remove();
};
}, []);
现在创建一个handleNotification方法。这适用于 Android 和 iOS
const handlePushNotification = useCallback(
async (
enabled: boolean, // I simply pass in the appState state variable or AppState.current
notificationID: string,
notificationType: NotificationType
) => {
// Display a notification
if (!enabled) {
return;
}
const channelId = await notifee.createChannel({
id: notificationID,
name: "APP_NAME_TO_DISPLAY",
visibility: AndroidVisibility.PUBLIC,
importance: AndroidImportance.HIGH,
// This adds vibration but I personally don't like vibration
// vibration: false,
// vibrationPattern: [100, 200, 100, 200],
});
if (notificationType === NotificationType.EATING) {
await notifee.displayNotification({
title: "Eating = YUMMY",
body: `I love to eat food`,
ios: { categoryId: "eating_category" },
android: {
channelId,
smallIcon: "ic_icon", //read docs if you want an icon
importance: AndroidImportance.HIGH,
pressAction: {
id: "androidOpenApp",
launchActivity: "default",
launchActivityFlags: [AndroidLaunchActivityFlag.SINGLE_TOP],
},
actions: [
{
title: "Stop Eating", //this will show if you long press the notification. Read docs to set up actions
pressAction: {
id: "stop-eating",
},
},
],
},
});
} else if (notificationType === NotificationType.SLEEP) {
await notifee.displayNotification({
title: "SLEEP - Time for bed",
body: `It's time to go to sleep!`,
ios: { categoryId: "sleep_category" },
android: {
channelId,
smallIcon: "ic_icon",
importance: AndroidImportance.HIGH,
pressAction: {
id: "androidOpenApp",
launchActivity: "default",
launchActivityFlags: [AndroidLaunchActivityFlag.SINGLE_TOP],
},
// You may have the same actions or different ones depending on your app
actions: [
{
title: "Stop Sleeping",
pressAction: {
id: "stop-sleeping",
},
},
],
},
});
}
},
[... whatever deps you need]
);
然后,您可以在代码中的某个地方说。
if (nextCustomerActivity === "sleeping") {
// Notify them that they need to go to sleep
handlePushNotification(
// Only notify if the app is in the background
Platform.OS === "ios" && appState === "inactive" || Platform.OS === "android" && appState === "background",
NotificationID.DefaultID,
NoticationType.Sleeping
);
} else if (nextCustomerActivity === "eating) {
// notify them they need to start eating
handlePushNotification(
Platform.OS === "ios" && appState === "inactive" || Platform.OS === "android" && appState === "background", // Only notify if the app is in the background
NotificationID.DefaultID,
NoticationType.Eating
);
} else {
// no need to notify
}
在 Android 中,如果您在打开通知时遇到应用程序的新实例被创建的情况,请确保检查您的
AndroidManifest.xml
。过去这需要我几个小时才能解决。
android:windowSoftInputMode="adjustPan"
android:launchMode="singleTask"
android:exported="true"
整个活动涉及
AndroidManifest.xml
<activity
android:name=".MainActivity"
android:configChanges="keyboard|keyboardHidden|orientation|screenSize|uiMode"
android:windowSoftInputMode="adjustPan"
android:launchMode="singleTask"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="YOUR_APP_NAME" />
</intent-filter>
</activity>
祝你好运!
应用程序关闭时使用后台服务运行代码。对于 Android,react-native 有 Headless.js,但要做到这一点,您需要编写一些本机代码。不幸的是,react-native 目前没有适用于 IOS 的文档。
对于Android:https://reactnative.dev/docs/headless-js-android
适用于 IOS 和 Android 的库:https://www.npmjs.com/package/react-native-background-actions
您遇到的问题可能是由于
android\app\build.gradle
文件中缺少依赖项,我的问题通过添加以下设置解决:
dependencies {
// ...
implementation 'com.google.firebase:firebase-analytics:17.3.0'
implementation platform('com.google.firebase:firebase-bom:31.0.0')
implementation 'com.google.firebase:firebase-functions'
implementation 'com.google.firebase:firebase-messaging'
implementation 'com.google.firebase:firebase-iid:21.1.0'
// ...
}
Firebase 提供多种服务,例如 Firebase Functions、Firebase Messaging 和 Firebase Instance ID,供推送通知系统使用。确保包含这些依赖项
此外,react-native-push-notification 需要为推送通知指定通知通道。这可以通过在
AndroidManifest.xml
文件的应用程序标签内添加特定的元数据标签来完成:
<application>
<meta-data
android:name="com.dieam.reactnativepushnotification.notification_channel_name"
android:value="PUSH_NOTIFICATION_CHANNEL" />
<meta-data
android:name="com.dieam.reactnativepushnotification.default_notification_channel_id"
android:value="PUSH_NOTIFICATION_CHANNEL" />
<meta-data
android:name="com.dieam.reactnativepushnotification.notification_channel_description"
android:value="Channel for push notification events" />
</application>
这些元数据标签定义通知通道的名称、ID 和描述。您可以从 Android 开发者指南了解有关通知渠道的更多信息。
此外,我听说最好为打开链接提供延迟,以确保应用程序正常运行并能够处理它。但是,我不确定这是否属实,所以我修改了
onNotification
中的 PushNotification.configure
,以在应用程序位于前台时添加延迟:
onNotification: async function (notification) {
if (notification.userInteraction) {
const { link = null } = notification?.data || {};
if (!link) return
if (notification.foreground === false) {
// The app was in the background or closed, delay the link opening
setTimeout(() =>
Linking.openURL(link).catch(e => console.log(e))
, 1000);
} else
Linking.openURL(link).catch(e => console.log(e));
}
},
请注意,我已将链接保存在通知数据中;您可以根据自己的喜好自由修改。