React-native-onesignal: 如何获得初始通知?

创建于 2017-10-02  ·  22评论  ·  资料来源: OneSignal/react-native-onesignal

React Native PushNotificationIOS模块有一个getInitialNotification()方法,允许获取被点击以打开应用程序的通知(如果有的话)。 这个库有类似的功能吗?

当我在应用程序关闭时向我的设备发送测试通知时,我在控制台打开时收到了Device info:日志,但我没有看到任何其他用于接收通知的事件日志。

编辑3:
出于某种原因,我不再能够看到初始通知的onOpened事件,尽管我的代码没有任何变化。

编辑2:
通过在侦听器周围移动,我能够看到onOpened事件的日志,但是作为被动侦听器意味着我无法在启动时主动检查我的应用程序是否已通过通知打开,我只需要等待一段时间才能看到该事件是否被触发? 有没有办法主动检查应用是否通过推送通知打开?

编辑:
我发现一篇使用OneSignal.configure()onNotificationOpened引用的文章,但是查看源代码似乎OneSignal.configure()不再接受参数了?

Documentation

最有用的评论

我有同样的问题,似乎很多其他人也有这个问题。 我发现的一些相关/重复问题包括https://github.com/geektimecoil/react-native-onesignal/issues/206https://github.com/geektimecoil/react-native-onesignal/issues/195https://github.com/geektimecoil/react-native-onesignal/issues/191,https://github.com/geektimecoil/react-native-onesignal/issues/336,https://github.com/geektimecoil/ _ _ react-native-onesignal/issues/334https: //github.com/geektimecoil/react-native-onesignal/issues/264,https://github.com/geektimecoil/react-native-onesignal/issues/279。

这些问题似乎都与当您点击推送通知以打开应用程序并且应用程序当时运行时未调用opened事件侦听器的问题有关。 从我在这些问题中读到的内容和我所做的测试来看,这个问题的原因似乎是事件侦听器的注册以任何方式被延迟(即OneSignal.addEventListener('opened', this.onOpened);在应用程序本身已加载)。 这可能是因为您在 React 组件中有此代码(例如,在constructorcomponentWillMountcomponentDidMount函数中),或者因为在您配置/重新水化之前它不会被调用您的 Redux 商店等。由于这种延迟,事件本身(通知已打开)在事件侦听器注册之前由 react-native-onesignal 触发,此时您已经错过了该事件并拥有没有办法知道它发生了。 附带说明一下,同样的问题会影响其他事件侦听器,例如ids事件侦听器。

如果您移动此代码以使其尽早发生,则似乎事件侦听器将在事件触发之前注册,因此您的事件处理函数将被调用。 例如,您应该将事件侦听器注册代码移动到您的index.ios.js文件中,或者在index.ios.js文件只是导入的情况下移动到App.js文件的开头App组件并注册它(通过AppRegistry.registerComponent )。

设置完成后,您现在可以捕获打开通知的事件以及如何处理它,这取决于您的应用程序的设置方式(例如,您是否正在使用Redux,或者您是否使用 redux-persist 等)。

我当前的解决方案是将通知保存到在我的App.js文件本身的顶层定义的变量中(在我什至声明我的App组件之前),然后一旦我完成初始化我的 Redux 商店(包括等待 redux-persist 对我的商店进行补水),我将通知作为有效负载发送操作(如果有通知打开),然后我还删除我的顶级事件侦听器并添加新事件我的App组件本身上的侦听器(这些事件侦听器也只是简单地将操作发送到我的 Redux 存储,并将通知、设备 ID 等作为操作有效负载)。

这个解决方案显然非常hacky,并且可能存在一些边缘情况,这不会按预期工作。 但是,在 react-native-onesignal 中实施适当的解决方案之前,这似乎是一个不错的解决方法。

我认为需要发生的是更新 react-native-onesignal 以便它等到您设置了事件处理程序后再触发事件。 一种可能的解决方案是,当事件发生时(例如opened事件),将事件放入队列中,然后 react-native-onesignal 检查当前是否注册了相应的事件侦听器。 如果没有,它会将事件留在队列中。 然后,一旦注册了事件侦听器,该事件侦听器将接收到的事件就会被触发并从队列中删除。 这样,您可以随时在应用程序中添加事件侦听器(例如,在等待您的 Redux 存储配置和重新水化之后,这可能是在应用程序本身加载后 1-2 秒),然后尽快注册事件监听器后,您的事件处理函数将被调用并接收发生的事件(例如打开通知的事件)。

另一种可能的解决方案,至少对于专门检测应用程序已打开是因为用户点击了推送通知,将是执行类似于getInitialNotification() from PushNotificationIOS的操作,如您建议的那样,您可以随时调用该函数,它将返回用户点击打开应用程序的推送通知(如果没有发生,则返回null )。 但即使这是在 react-native-onesignal 中实现的,它也无法解决这个影响其他事件侦听器(例如ids事件侦听器)的问题。

所以我认为确实需要一个解决方案来解决在注册任何相应的事件侦听器之前触发事件的核心问题,从而导致应用程序错过事件。

所有22条评论

我有同样的问题,似乎很多其他人也有这个问题。 我发现的一些相关/重复问题包括https://github.com/geektimecoil/react-native-onesignal/issues/206https://github.com/geektimecoil/react-native-onesignal/issues/195https://github.com/geektimecoil/react-native-onesignal/issues/191,https://github.com/geektimecoil/react-native-onesignal/issues/336,https://github.com/geektimecoil/ _ _ react-native-onesignal/issues/334https: //github.com/geektimecoil/react-native-onesignal/issues/264,https://github.com/geektimecoil/react-native-onesignal/issues/279。

这些问题似乎都与当您点击推送通知以打开应用程序并且应用程序当时运行时未调用opened事件侦听器的问题有关。 从我在这些问题中读到的内容和我所做的测试来看,这个问题的原因似乎是事件侦听器的注册以任何方式被延迟(即OneSignal.addEventListener('opened', this.onOpened);在应用程序本身已加载)。 这可能是因为您在 React 组件中有此代码(例如,在constructorcomponentWillMountcomponentDidMount函数中),或者因为在您配置/重新水化之前它不会被调用您的 Redux 商店等。由于这种延迟,事件本身(通知已打开)在事件侦听器注册之前由 react-native-onesignal 触发,此时您已经错过了该事件并拥有没有办法知道它发生了。 附带说明一下,同样的问题会影响其他事件侦听器,例如ids事件侦听器。

如果您移动此代码以使其尽早发生,则似乎事件侦听器将在事件触发之前注册,因此您的事件处理函数将被调用。 例如,您应该将事件侦听器注册代码移动到您的index.ios.js文件中,或者在index.ios.js文件只是导入的情况下移动到App.js文件的开头App组件并注册它(通过AppRegistry.registerComponent )。

设置完成后,您现在可以捕获打开通知的事件以及如何处理它,这取决于您的应用程序的设置方式(例如,您是否正在使用Redux,或者您是否使用 redux-persist 等)。

我当前的解决方案是将通知保存到在我的App.js文件本身的顶层定义的变量中(在我什至声明我的App组件之前),然后一旦我完成初始化我的 Redux 商店(包括等待 redux-persist 对我的商店进行补水),我将通知作为有效负载发送操作(如果有通知打开),然后我还删除我的顶级事件侦听器并添加新事件我的App组件本身上的侦听器(这些事件侦听器也只是简单地将操作发送到我的 Redux 存储,并将通知、设备 ID 等作为操作有效负载)。

这个解决方案显然非常hacky,并且可能存在一些边缘情况,这不会按预期工作。 但是,在 react-native-onesignal 中实施适当的解决方案之前,这似乎是一个不错的解决方法。

我认为需要发生的是更新 react-native-onesignal 以便它等到您设置了事件处理程序后再触发事件。 一种可能的解决方案是,当事件发生时(例如opened事件),将事件放入队列中,然后 react-native-onesignal 检查当前是否注册了相应的事件侦听器。 如果没有,它会将事件留在队列中。 然后,一旦注册了事件侦听器,该事件侦听器将接收到的事件就会被触发并从队列中删除。 这样,您可以随时在应用程序中添加事件侦听器(例如,在等待您的 Redux 存储配置和重新水化之后,这可能是在应用程序本身加载后 1-2 秒),然后尽快注册事件监听器后,您的事件处理函数将被调用并接收发生的事件(例如打开通知的事件)。

另一种可能的解决方案,至少对于专门检测应用程序已打开是因为用户点击了推送通知,将是执行类似于getInitialNotification() from PushNotificationIOS的操作,如您建议的那样,您可以随时调用该函数,它将返回用户点击打开应用程序的推送通知(如果没有发生,则返回null )。 但即使这是在 react-native-onesignal 中实现的,它也无法解决这个影响其他事件侦听器(例如ids事件侦听器)的问题。

所以我认为确实需要一个解决方案来解决在注册任何相应的事件侦听器之前触发事件的核心问题,从而导致应用程序错过事件。

@jordanmkoncz ,您可以分享您向其发送操作的文件的代码吗? 我和你有相同的 react-native 设置(redux-persist 等)

@ccoeder当然,这是我当前的App.js文件。

import React, { Component } from 'react';
import { Provider } from 'react-redux';
import OneSignal from 'react-native-onesignal';
import isNil from 'lodash/isNil';
import configureStore from '../redux/configureStore';
import {
  pushNotificationIdsReceived,
  pushNotificationOpened,
  pushNotificationReceived,
  pushNotificationRegistered,
} from '../redux/actionCreators';
import AppNavigator from './AppNavigator';
import Blank from './Blank';

let openedPushNotificationResult = null;
let receivedPushNotification = null;
let receivedNotificationUserInfo = null;
let receivedIds = null;

const onOpened = openResult => {
  openedPushNotificationResult = openResult;
};

const onReceived = notification => {
  receivedPushNotification = notification;
};

const onRegistered = notificationUserInfo => {
  receivedNotificationUserInfo = notificationUserInfo;
};

const onIds = ids => {
  receivedIds = ids;
};

OneSignal.addEventListener('opened', onOpened);
OneSignal.addEventListener('received', onReceived);
OneSignal.addEventListener('registered', onRegistered);
OneSignal.addEventListener('ids', onIds);

class App extends Component {
  constructor() {
    super();

    this.state = {
      isStoreInitialised: false,
    };

    this.store = null;

    this.onOpened = this.onOpened.bind(this);
    this.onReceived = this.onReceived.bind(this);
    this.onRegistered = this.onRegistered.bind(this);
    this.onIds = this.onIds.bind(this);
  }

  componentDidMount() {
    this.store = configureStore(store => {
      if (!isNil(openedPushNotificationResult)) {
        store.dispatch(pushNotificationOpened(openedPushNotificationResult));
      }

      if (!isNil(receivedPushNotification)) {
        store.dispatch(pushNotificationReceived(receivedPushNotification));
      }

      if (!isNil(receivedNotificationUserInfo)) {
        store.dispatch(pushNotificationRegistered(receivedNotificationUserInfo));
      }

      if (!isNil(receivedIds)) {
        store.dispatch(pushNotificationIdsReceived(receivedIds));
      }

      OneSignal.addEventListener('opened', this.onOpened);
      OneSignal.addEventListener('received', this.onReceived);
      OneSignal.addEventListener('registered', this.onRegistered);
      OneSignal.addEventListener('ids', this.onIds);

      OneSignal.removeEventListener('opened', onOpened);
      OneSignal.removeEventListener('received', onReceived);
      OneSignal.removeEventListener('registered', onRegistered);
      OneSignal.removeEventListener('ids', onIds);

      this.setState({ isStoreInitialised: true });
    });
  }

  componentWillUnmount() {
    OneSignal.removeEventListener('opened', this.onOpened);
    OneSignal.removeEventListener('received', this.onReceived);
    OneSignal.removeEventListener('registered', this.onRegistered);
    OneSignal.removeEventListener('ids', this.onIds);
    OneSignal.removeEventListener('opened', onOpened);
    OneSignal.removeEventListener('received', onReceived);
    OneSignal.removeEventListener('registered', onRegistered);
    OneSignal.removeEventListener('ids', onIds);
  }

  onOpened(openResult) {
    this.store.dispatch(pushNotificationOpened(openResult));
  }

  onReceived(notification) {
    this.store.dispatch(pushNotificationReceived(notification));
  }

  onRegistered(notificationUserInfo) {
    this.store.dispatch(pushNotificationRegistered(notificationUserInfo));
  }

  onIds(ids) {
    this.store.dispatch(pushNotificationIdsReceived(ids));
  }

  render() {
    if (!this.state.isStoreInitialised) {
      return <Blank />;
    }

    return (
      <Provider store={this.store}>
        <AppNavigator />
      </Provider>
    );
  }
}

export default App;

注意: configureStore是一个创建我的 Redux 存储的函数(即它调用createStore() ),然后设置 redux-persist(即它调用persistStore() )。 configureStore将回调函数作为参数,在persistStore函数的onComplete回调中我调用了传递给configureStore的回调函数并传递了store对象作为此回调的参数。 最后, configureStore返回 store 对象。

所以基本上,我等到我的商店建立并重新水化,然后我根据我的初始事件侦听器接收到的事件调度操作,然后添加新的事件侦听器并删除初始事件侦听器。

@jordanmkoncz感谢您分享您的代码。 起初我以为我和你有同样的错误,但我意识到我的问题与静默通知有关。 如果在应用程序关闭时收到通知,我需要采取措施。 我猜你的代码对我不起作用。

不用担心@ccoeder。 是的,在应用关闭实际对通知采取行动的问题是另一回事。 此问题与在应用程序中检测到用户在启动应用程序时(之前根本没有运行时)点击通知打开应用程序有关。

看看react-native-fcm是怎么做的,有一个方法叫getInitialNotification

@jordanmkoncz感谢您的发帖。

我有类似的问题。 当应用程序收到推送通知时,屏幕导航到所需的屏幕。
但是当打开通知时,它不适用于导航推送功能。
例子:
组件WillMount() {
OneSignal.addEventListener('received', this._onReceived);
OneSignal.addEventListener('opened', this._onOpened);
}
组件WillUnmount() {
OneSignal.removeEventListener('received', this.__onReceived);
OneSignal.removeEventListener('opened', this._onOpened);
}
_onRecevied(通知){
console.log('收到通知:',通知); // 运行良好
this.props.navigator.push({ pushSreen, passProps : { params } }); // 运行良好
}
_onOpened(openResult) {
console.log('通知正文:', openResult.notification.payload.body); // 运行良好
this.props.navigator.push({ pushSreen, passProps : { params } }); // 不工作
}

你怎么看待这件事? 如果你能帮助我,希望请在这里回复。 谢谢

嗯.. 我的PushNotificationHelper组件是我的 Redux Provider的子组件,它仅在store重新水化后才呈现。

componentWillMount() {
    AppState.addEventListener("change", this.handleAppStateChange);
    OneSignal.configure({
      onNotificationOpened: this.handleOpenNotification
    });
    OneSignal.addEventListener("received", this.onReceived);
    OneSignal.addEventListener("opened", this.onOpened);
    OneSignal.addEventListener("registered", this.onRegistered);
    OneSignal.addEventListener("ids", this.onIds);

    if (!IOS) {
      OneSignal.inFocusDisplaying(0);
    }
  }

  componentWillUnmount() {
    AppState.removeEventListener("change", this.handleAppStateChange);
    OneSignal.removeEventListener("received", this.onReceived);
    OneSignal.removeEventListener("opened", this.onOpened);
    OneSignal.removeEventListener("registered", this.onRegistered);
    OneSignal.removeEventListener("ids", this.onIds);
  }

handleOpenNotification = (message, data, isActive) => {
    console.log("Notification", message, data, isActive);

    if (isActive) {
      // touchable banner displaying info from push notification
    } else {
      // act on data received from push notification
    }
  };

onReceived = notification => {
    console.log("Notification received: ", notification);
  };

onOpened = openResult => {
    console.log("Message: ", openResult.notification.payload.body);
    console.log("Data: ", openResult.notification.payload.additionalData);
    console.log("isActive: ", openResult.notification.isAppInFocus);
    console.log("openResult: ", openResult);
  };

即使我的应用程序关闭——不是在background AppState 中,而是完全关闭——如果我点击推送通知, onOpened方法也会使用openResult调用对象和相关数据,我可以自由地进行适当的dispatch redux 操作。

@wkoutre很有趣,你能发布一下你目前正在使用的react-nativereact-native-onesignal等版本吗? 你在 iOS 和 Android 上都测试过吗? 您是否对通过点击推送通知打开应用程序进行了广泛的测试,在点击推送通知时应用程序完全关闭,并发现您的onOpened方法被 100% 调用?

如果您人为地进一步延迟PushNotificationHelper的加载,例如通过设置延迟大约 5 秒的 setTimeout,您能否进行一些测试,看看它是否仍然 100% 有效,之后您更改状态以允许挂载PushNotificationHelper并使用 OneSignal 注册其事件侦听器?

@jordanmkoncz

"react-native": "0.50.4"
"react-native-onesignal": "^3.0.7"

我已经在 iOS 和 Android 上进行了测试,是的。 在这两种情况下,100% 的时间:

  • 应用程序完全关闭
  • 收到推送通知
  • 推送通知被点击
  • 应用加载
  • 使用来自推送通知的数据调用onOpened ,并且openResult.notification.isAppInFocus === false

我会做setTimeout并回复你。


EDIT1:我完全没有改变,现在它在 Android 上 100% 的时间都失败了。


EDIT2:执行setTimeout延迟导致onOpened不会通过点击推送通知来触发应用程序加载。 但是,我将所有内容都移到了App.js的生命周期方法中——我的根组件在index.ios.jsindex.android.js中注册——并且onOpened被称为 100%的时间是 iOS,大约 50% 的时间是在 Android 上。

不知道为什么Android不一致,但这显然是一个问题。 在 Android 上,当应用程序完全关闭并收到通知时,调试器会清除并且我的App.js中的所有内容都会加载,直到我自己创建类。

const IOSX = HEIGHT === 812 && PLATFORM === "ios";

const wrapperStyle = [Styles.flex1];
if (IOSX) wrapperStyle.push(Styles.backgroundDarkGray);

let SPLASH_TIME;

console.log(`Change to TRUE below to reset store state`);

const PURGE = DEV ? false : false;

if (DEV) SPLASH_TIME = 4000;
else SPLASH_TIME = 4000;

// const composeEnhancers = composeWithDevTools({
//   realtime: true,
//   port: 8000
// });

const composeEnhancers =
  typeof window === "object" &&
  window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ &&
  DEV
    ? window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({
        // Specify extension’s options like name, actionsBlacklist, actionsCreators, serialize...
      })
    : compose;

const middlewares = [ReduxThunk];

// debugging tooling
// if (DEV) {
//   // add logger
// middlewares.push(logger)

//   // middlewares = [...middlewares, logger];
//   middlewares = [...middlewares];

// replace these transient reducers when they've been created

export const store = createStore(
  Reducers,
  {},
  composeEnhancers(
    applyAppStateListener(),
    applyMiddleware(...middlewares),
    autoRehydrate()
  )
);

// if (module.hot) {
//   // Enable hot module replacement for reducers
//   module.hot.accept(() => {
//     const nextRootReducer = require("./reducers/index").default;
//     store.replaceReducer(nextRootReducer);
//   });
// }

console.log(`right before APP`);

// Debugger logs everything before this line.

export default class App extends Component {
    ...
}

@jordanmkoncz好奇你是否尝试过这个库: https ://github.com/wix/react-native-notifications

好吧,我有一个解决方法,它在 iOS 和 Android 上 100% 的时间都有效。

在我的App.js中,但在我声明我的 App 组件之前,我有:

const handleOnOpened = openResult => {
  store.dispatch(setInitialNotification(openResult));
};

OneSignal.configure({});
OneSignal.addEventListener("opened", handleOnOpened);

...其中setInitialNotification是动作创建者。

然后,当我的(现在安装的)应用程序完成补液时,我调用:

this.setState({ rehydrated: true }, () => {
          OneSignal.removeEventListener("opened", handleOnOpened);
        });

我的应用程序——用 redux Provider包装——然后在render方法中返回,看起来像......

<Provider store={store}>
        <IphoneXAwareView style={wrapperStyle}>
          <StatusBar hidden={false} barStyle="light-content" />
          <MyAlert />
          <Loading />
          <ConnectedAppWithNavigationState />
          <PushNotificationHelper />
        </IphoneXAwareView>
      </Provider>

从那里, PushNotificationHelper组件处理侦听和处理所有推送通知。

@bhoop已经几个月了,所以不确定你是否还在寻找修复,但是......如果是这样,试试这个。

@wkoutre你能否设置一个 PR 更新自述文件,其中包括这个 redux 的解决方法?

@avishayil当然。 我会在今晚之前完成

avishayil公关制作。

我正面临一个听起来像这样的问题。 当应用程序打开时,所有回调都运行正常,当应用程序处于后台时也是如此。 但是,如果我收到推送,我的应用程序图标会增加 +1,并且系统会显示带有通知内容的横幅但是如果我忽略横幅并通过图标(而不是通知横幅)打开应用程序,则回调将被忽略 =[ 如何处理这个(事情 ?

  • 世博分离应用
  • 反应 16.3.1
  • 一个信号 3.2.5
  • 世博会 27.0.1

@brunoandradebr这是预期的行为。 从应用程序图标打开应用程序永远不会考虑您可能收到的任何通知。 它只是打开应用程序。

如果您想根据用户是否收到通知来更改应用启动时的行为,您需要在启动时自行检查。

这不是真的。 当应用程序在后台运行时通过图标打开应用程序时,它会根据需要处理推送通知。 只有当我从内存中删除它(滑动),然后我按图标打开时,什么都没有发生。 我正在调查,我认为这是 XCode 停止应用程序并关闭 oonesignal lib 链接。

@brunoandradebr我可能误解了您遇到的问题,以及您指的是哪个回调。
如果应用程序在后台运行,它能够处理received事件。 但是如果应用程序被杀死,它就无法监听任何事件。 通知与应用程序交互的唯一方式(至少对于 iOS),是以任何方式与通知交互。

当我杀死应用程序并收到通知时,如果我通过图标打开应用程序,则应用程序无法处理回调事件,但是如果应用程序在后台运行并且我通过图标打开,回调会按预期触发。 知道了 ?

@brunoandradebr我想我明白了,如果我没记错的话,这就是我在之前的评论中描述的行为。 无论如何,我觉得这是题外话,如果你认为你有这个问题,你应该在 repo 上打开一个单独的问题。

@jordanmkoncz您似乎对本机单信号问题的反应非常了解。 我使用 react-native-onesignal 的版本:^3.2.8 和 react-native:0.56.0。 我能够在后台和前台实现处理通知,但是当应用程序关闭并点击通知时,我现在遇到了问题。 该应用程序仅显示一个空白的白色屏幕,除非您关闭并重新启动它,否则它不会消失。 我不确定如何处理这种情况,因为我在 OneSignal 的网站上找不到任何文档。 这很令人沮丧,因为我花了时间学习和实现这个库,现在我不确定它是否能够处理这个极其重要的用例。 我在上面阅读了一个可能的解决方法,它在 index.js 中实现事件侦听器,但我正在使用反应导航,并且需要从我在 App.js 中声明的主导航器获取引用,以便导航到嵌套堆栈屏幕。 我真的很感激有人在处理这个问题以及他们如何解决这个问题时提供的任何建议。 提前致谢。

此页面是否有帮助?
0 / 5 - 0 等级