2015-12-17 161 views
13

Detect if the app was launched/opened from a push notification描述了如何通过用户点击推送通知来检测本机iOS应用程序是否已打开(即启动或仅启用)。检测是否通过推送通知打开了React Native iOS应用程序

如何在React Native中执行同样的操作? PushNotificationIOS让我附上通知监听...

PushNotificationIOS.addEventListener('notification', function (notification) { 
    console.log('got a notification', notification); 
}); 

但这触发时都在前台的应用程序时收到推送通知,当我通过推送通知打开应用程序。

如何检测第二种情况?

回答

30

这里有两种情况需要以不同的方式被检测:

  1. 的应用已经完全终止(重新启动手机,例如,或者通过双攻的家,然后滑动它关闭名单应用程序在后台运行),并通过用户点击推送通知正在启动。这可以通过React.PushNotificationIOS.getInitialNotification方法检测(并获取通知的数据)。
  2. 该应用程序已被暂停,并通过用户点击推送通知再次激活。只需like in a native app,你可以知道这是因为iOS在打开时(即使它是一个旧通知)向你的应用程序传递挖掘通知,并导致你的通知处理程序在你的应用程序处于UIApplicationStateInactive状态(或'background'状态,因为React Native的AppStateIOS类调​​用它)。

代码来处理这两种情况下(你可以把这个在您的index.ios.js或其他地方,对应用程序启动运行):

import React from 'react'; 
import { PushNotificationIOS, AppState } from 'react-native'; 

function appOpenedByNotificationTap(notification) { 
    // This is your handler. The tapped notification gets passed in here. 
    // Do whatever you like with it. 
    console.log(notification); 
} 

PushNotificationIOS.getInitialNotification().then(function (notification) { 
    if (notification != null) { 
    appOpenedByNotificationTap(notification); 
    } 
}); 

let backgroundNotification; 

PushNotificationIOS.addEventListener('notification', function (notification) { 
    if (AppState.currentState === 'background') { 
    backgroundNotification = notification; 
    } 
}); 

AppState.addEventListener('change', function (new_state) { 
    if (new_state === 'active' && backgroundNotification != null) { 
    appOpenedByNotificationTap(backgroundNotification); 
    backgroundNotification = null; 
    } 
}); 
+1

作为一个补充,你可能想要在状态中存储对你的处理程序的引用,并调用'componentWillUnmount'中的'removeEventListener'(如果你在一个组件中这样做) – ComethTheNerd

+0

@ mark-amery在这种情况下应该使用哪种方法? componentWillMount? –

+0

@NimilaHiranya它不一定需要任何方法;你可以把它放在你的'index.ios.js'文件中。但是像根视图的'componentWillMount'这样的生命周期函数也可能是一个合理的地方。 –

0

我发现这个解决方案有点怪异,并且依赖于我注意到的有关事件处理程序触发顺序的一些潜在的奇怪行为。我一直在努力的应用程序需要相同的功能,特别是当我通过推送通知打开应用程序时进行检测。

我发现这又是处理程序之前PushNotificationIOS火的AppStateIOS这是什么意思的处理程序是,如果我坚持前台/后台状态记忆/ AsyncStorage,我可以检查它像这样在PushNotification事件处理程序:if (activity === 'background')如果这是真的,那么我知道我刚刚从推送通知中打开了应用程序。

我总是在内存和磁盘上保留AppStateIOS前景/后台活动(分别使用redux和redux-persist),所以我只需检查一次我需要知道的内容。

对于您的目的而言,这可能会太冒昧,而且这种行为可能会在未来发生变化,或者它可能仅限于本地化。试着看看这个解决方案,看看你的想法。

+0

谢谢,这指出我在正确的方向。我认为这个效果已经很好了,最糟糕的情况是,与原生iOS应用程序的等效解决方案相比,它的功能已经不再那么糟了(http://stackoverflow.com/a/16393957/1709587),它完全一样。但是,您可能没有意识到的一个缺点是,这并不处理应用程序已被完全终止并且实际上是通过点击推送通知而被启动*(不仅仅是激活)的情况; 'popInitialNotification'是需要的。我会自我回答一些涵盖两种情况的代码。 –

+0

@MarkAmery谢谢你指出后一种情况。这真是这个黑客的一大缺点。我现在必须依赖用户从后台打开应用程序,我绝对不喜欢它。我很高兴看到你的解决方案,我将不得不适应你的想法! –

8

对于本地通知

getInitialNotification不与本地通知工作。

不幸的是,从0开始。28 React Native,使用PushNotificationIOS.getInitialNotification()始终会返回一个null值,该值由本地推送。

因此,您需要将AppDelegate.m中的推送通知作为launchOption,并将其作为appProperty传递到React Native。

以下是您需要从冷启动从背景/非活动状态接收本地推送通知的全部内容。

AppDelegate.m(机iOS代码)

// Inside of your didFinishLaunchingWithOptions method... 

// Create a Mutable Dictionary to hold the appProperties to pass to React Native. 
NSMutableDictionary *appProperties = [NSMutableDictionary dictionary]; 

if (launchOptions != nil) { 
    // Get Local Notification used to launch application. 
    UILocalNotification *notification = [launchOptions objectForKey:UIApplicationLaunchOptionsLocalNotificationKey]; 

    if (notification) { 
    // Instead of passing the entire Notification, we'll pass the userInfo, 
    // where a Record ID could be stored, for example. 
    NSDictionary *notificationUserInfo = [notification userInfo]; 

    [ appProperties setObject:notificationUserInfo forKey:@"initialNotificationUserInfo" ]; 
    } 
} 

// Your RCTRootView stuff... 

rootView.appProperties = appProperties; 

index.ios.js(阵营母语)

componentDidMount() { 
    if (this.props.initialNotificationUserInfo) { 
    console.log("Launched from Notification from Cold State"); 
    // This is where you could get a Record ID from this.props.initialNotificationUserInfo 
    // and redirect to the appropriate page, for example. 
    } 

    PushNotificationIOS.addEventListener('localNotification', this._onLocalNotification); 
} 

componentWillUnmount() { 
    PushNotificationIOS.removeEventListener('localNotification', this._onLocalNotification); 
} 

_onLocalNotification(notification) { 
    if (AppState.currentState != 'active') { 
    console.log("Launched from Notification from Background or Inactive state."); 
    } 
    else { 
    console.log("Not Launched from Notification"); 
    } 
} 

确保从react-native进口PushNotificationIOSAppState

我还没有使用远程推送通知进行测试。也许@ MarkAmery的方法在远程推送通知中工作得很好,但不幸的是,就目前的React Native状态而言,这是我能够从冷态下获取本地推送通知的唯一方式。

这在React Native中是非常没有记录的,所以我在他们的GitHub仓库上创建了an issue以吸引注意力并希望纠正它。如果你正在处理这个问题,那么去那里给它竖起大拇指,让它渗透到顶端。

https://github.com/facebook/react-native/issues/8580

+1

除非在发布我的答案后更新中有什么改变(恐怕我无法检查),这是错误的。通知事件处理程序将触发,如果应用程序在被添加后被暂停*,然后通过点击通知重新激活*,但是如果应用程序被*终止*并且然后*通过轻敲在通知上 - 这种情况需要通过不同的方式来检测。我已经在[我的回答](http://stackoverflow.com/a/34343226/1709587)中介绍了这一点。 –

+0

@MarkAmery哦,很好,赶上!你绝对正确。现在只需运行一些测试...我会让你知道我找到了什么。 –

+1

@MarkAmery经过大约一天的调试,我能够正确处理来自冷启动的本地推送通知。我尝试了你的方法,但至少对于本地推送通知,它不起作用。我现在也打开一个React Native的问题。谢谢你的帮助。 –

相关问题