RN OneSignal _open 事件

Posted

技术标签:

【中文标题】RN OneSignal _open 事件【英文标题】:RN OneSignal _open Event 【发布时间】:2021-07-14 13:38:25 【问题描述】:

OneSignal on notification open 事件在主屏幕启动后触发,然后导航到所需的屏幕。我想检测应用程序是否在主屏幕呈现之前按通知启动,以便我可以直接导航到第二个屏幕并避免不必要地调用 api。

“react-native-onesignal”:“^3.9.3” “反应导航”:“^4.0.0”

代码

   const _opened = openResult => 
      const  additionalData, body  = openResult.notification.payload;
     // how to navigate or set the initial screen depending on the payload
   

    useEffect(() => 

        onesignal.init();
        onesignal.addEventListener('received', _received);
        onesignal.addEventListener('opened', _opened);
        SplashScreen.hide();

      return () => 
        // unsubscriber
        onesignal.removeEventListener('received', _received);
        onesignal.removeEventListener('opened', _opened);
      
   , []);

调试

【问题讨论】:

【参考方案1】:

您的问题是如何导航或设置初始屏幕取决于打开的通知负载?

1) - 根据打开的通知负载设置initial screen

根据class LifecycleuseEffect在组件输出被渲染后运行,所以useEffect中的监听器直到组件数量才被监听,这也是在useEffect之前登录主屏幕显示的原因,看到这个解释。

//this the problem (NavigationContainer called before useEffect).
function App() 
  useEffect(() => ); //called second.
  return <NavigationContainer>; //called first.


//this the solution (useEffect called Before NavigationContainer).
function App() 
  const [ready, setReady] = useState(false);

  //called second.
  useEffect(() =>  
    //listen here
    setReady(true);
    SplashScreen.hide();
  );

  //called first
  //no function or apis run before useEffect here it just view.
  if(!ready) return <></>;// or <LoadingView/>

   //called third.
  return <NavigationContainer>;

你的代码可能是这样的。
function App() 
    const [ready, setReady] = useState(false);

    const openedNotificationRef = useRef(null);
    
    const _opened = openResult => 
        openedNotificationRef.current = openResult.notification.payload;
    

    const getInitialRouteName = () => 
        if (openedNotificationRef.current) 
            return "second"; //or what you want depending on the notification.
        
        return "home";
    


    useEffect(() => 
        onesignal.addEventListener('opened', _opened);
        //setTimeout(fn, 0) mean function cannot run until the stack on the main thread is empty.
        //this ensure _opened is executed if app is opened from notification
        setTimeout(() => 
            setReady(true);
        , 0)
    );


    if(!ready) return <LoadingView/>


    return (
        <NavigationContainer initialRouteName=getInitialRouteName()>
        </NavigationContainer>
    );


首先你需要知道

需要渲染导航器才能处理操作如果您 尝试在不呈现导航器的情况下或在导航器之前导航 完成安装,如果不处理,它将抛出并崩溃您的应用程序。所以 您需要添加额外的检查来决定要做什么,直到您 应用挂载。

阅读docs


function App() 

    const navigationRef = React.useRef(null);
    
    const openedNotificationRef = useRef(null);
    
    const _opened = openResult => 
        openedNotificationRef.current = openResult.notification.payload;
        //remove loading screen and start with what you want.
        const routes = [
            name : 'home', //recommended add this to handle navigation go back
            name : 'orders', //recommended add this to handle navigation go back
            name : 'order', params : id : payload.id,
        ]
        navigationRef.current.dispatch(
            CommonActions.reset(
                routes : routes,
                index: routes.length - 1,
            )
        )
    

    useEffect(() => 
        //don't subscribe to `opened` here
        
        //unsubscribe
        return () => 
            onesignal.removeEventListener('opened', _opened);
        
    , []);

    //subscribe to `opened` after navigation is ready to can use navigate
    const onReady = () => 
        onesignal.addEventListener('opened', _opened);
        //setTimeout(fn, 0) mean function cannot run until the stack on the main thread is empty.
        //this ensure _opened is executed if app is opened from notification
        setTimeout(() => 
            if (!openedNotificationRef.current) 
                //remove loading screen and start with home 
                navigationRef.current.dispatch(
                    CommonActions.reset(
                        routes : [name : 'home'],
                        index: 0,
                    )
                )
            
        , 0)
    ;


    return (
        <NavigationContainer
            ref=navigationRef
            onReady=onReady
            initialRouteName="justLoadingScreen">
        </NavigationContainer>
    );



setTimeout、CommonActions 的引用。

【讨论】:

以上是关于RN OneSignal _open 事件的主要内容,如果未能解决你的问题,请参考以下文章

Ionic3 OneSignal 如何检查应用程序是不是由于通知打开事件而启动

RN 绑定双击事件

RN性能优化及事件监听

js 阻止事件冒泡和默认行为 preventDefaultstopPropagationreturn false

从 Onesignal (Phonegap) 获取附加数据

Tips——RN canvas缩放处理