反应本机推送通知不在后台运行

问题描述 投票:0回答:3

我正在尝试使用本机应用程序和此插件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);
react-native push-notification localnotification react-native-push-notification
3个回答
2
投票

如果您想在后台实现通知。我强烈建议采用

@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>

祝你好运!


0
投票

应用程序关闭时使用后台服务运行代码。对于 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


0
投票

您遇到的问题可能是由于

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));
  }
},

请注意,我已将链接保存在通知数据中;您可以根据自己的喜好自由修改。

© www.soinside.com 2019 - 2024. All rights reserved.