是否有可能知道,如果应用程序发起/从一个推送通知开的呢?
我猜射事件可以被抓到这里来:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
if (launchOptions != nil) {
// Launched from push notification
NSDictionary *notification = [launchOptions objectForKey:UIApplicationLaunchOptionsRemoteNotificationKey];
}
}
但是,我怎么可以检测到它是从一个推送通知时,打开该应用程序在后台?
Answer 1:
看到这个代码:
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
{
if ( application.applicationState == UIApplicationStateInactive || application.applicationState == UIApplicationStateBackground )
{
//opened from a push notification when the app was on background
}
}
与...一样
-(void)application:(UIApplication *)application didReceiveLocalNotification (UILocalNotification *)notification
Answer 2:
晚,但也许有用
当应用程序没有运行
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
叫做 ..
其中u需要检查推送通知
NSDictionary *notification = [launchOptions objectForKey:UIApplicationLaunchOptionsRemoteNotificationKey];
if (notification) {
NSLog(@"app recieved notification from remote%@",notification);
[self application:application didReceiveRemoteNotification:notification];
} else {
NSLog(@"app did not recieve notification");
}
Answer 3:
我们有这个问题是正确更新应用程序启动后的视图。 还有这里的生命周期中的方法会比较混乱复杂的顺序。
生命周期方法
我们对iOS的10测试显示的生命周期方法的各种情况如下序列:
DELEGATE METHODS CALLED WHEN OPENING APP
Opening app when system killed or user killed
didFinishLaunchingWithOptions
applicationDidBecomeActive
Opening app when backgrounded
applicationWillEnterForeground
applicationDidBecomeActive
DELEGATE METHODS WHEN OPENING PUSH
Opening push when system killed
[receiving push causes didFinishLaunchingWithOptions (with options) and didReceiveRemoteNotification:background]
applicationWillEnterForeground
didReceiveRemoteNotification:inactive
applicationDidBecomeActive
Opening push when user killed
didFinishLaunchingWithOptions (with options)
didReceiveRemoteNotification:inactive [only completionHandler version]
applicationDidBecomeActive
Opening push when backgrounded
[receiving push causes didReceiveRemoteNotification:background]
applicationWillEnterForeground
didReceiveRemoteNotification:inactive
applicationDidBecomeActive
问题
好了,现在我们需要:
- 确定用户是否是从推开启应用程式
- 更新基于按压状态视图
- 清除状态,以便随后打开不要将用户返回到相同的位置。
棘手的一点是,更新视图具有当应用程序实际上变成有效,这是在所有情况下相同的生命周期方法的情况发生。
我们的解决方案的草图
以下是我们的解决方案的主要组件:
- 存储
notificationUserInfo
在AppDelegate的实例变量。 - 设置
notificationUserInfo = nil
两applicationWillEnterForeground
和didFinishLaunchingWithOptions
。 - 设置
notificationUserInfo = userInfo
在didReceiveRemoteNotification:inactive
- 从
applicationDidBecomeActive
总是调用自定义的方法openViewFromNotification
并通过self.notificationUserInfo
。 如果self.notificationUserInfo
是零则返回早,否则打开基于中找到的通知状态视图self.notificationUserInfo
。
说明
当来自一键打开didFinishLaunchingWithOptions
或applicationWillEnterForeground
总是前马上打电话didReceiveRemoteNotification:inactive
,所以我们首先重置notificationUserInfo在这些方法中,所以没有失效状态。 然后,如果didReceiveRemoteNotification:inactive
叫我们知道我们是从推打开,所以我们设定self.notificationUserInfo
,然后拾起applicationDidBecomeActive
转发用户的右视图。
有一个是用户是否具有该应用的应用切换器,然后接收推送通知(通过双击主页按钮而应用程序是在前台IE)内打开最后一种情况。 在这种情况下,只有didReceiveRemoteNotification:inactive
叫,也不WillEnterForeground也不didFinishLaunching被调用,所以你需要一些特殊的状态,以处理这种情况。
希望这可以帮助。
Answer 4:
这是一个很好佩戴后...但它仍然缺少一个实际的解决问题的方法(如各种评论指出)。
原来的问题是关于检测时,应用程序被发射 /从推送通知打开 , 例如 ,用户点击该通知。 答案都不实际上涵盖这种情况。
究其原因可以在呼叫流程可以看出,当一个通知到达时, application:didReceiveRemoteNotification...
当接到通知时再通知是由用户点击被调用。 正因为如此,你不能只盯着告诉UIApplicationState
羯羊的用户点击它。
此外,您不再需要处理的应用程序的“冷启动”的情况application:didFinishLaunchingWithOptions...
作为application:didReceiveRemoteNotification...
在iOS版推出后,再次调用9+(也许8为好)。
那么,你怎么能告诉我们,如果用户水龙头开始的一连串事件? 我的解决办法是,以纪念在该应用程序开始走出背景或冷启动,然后检查当时的时间application:didReceiveRemoteNotification...
。 如果是小于0.1S,那么你可以相当肯定的水龙头触发启动。
斯威夫特2.X
class AppDelegate: UIResponder, UIApplicationDelegate {
var wakeTime : NSDate = NSDate() // when did our application wake up most recently?
func applicationWillEnterForeground(application: UIApplication) {
// time stamp the entering of foreground so we can tell how we got here
wakeTime = NSDate()
}
func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject], fetchCompletionHandler completionHandler: (UIBackgroundFetchResult) -> Void) {
// ensure the userInfo dictionary has the data you expect
if let type = userInfo["type"] as? String where type == "status" {
// IF the wakeTime is less than 1/10 of a second, then we got here by tapping a notification
if application.applicationState != UIApplicationState.Background && NSDate().timeIntervalSinceDate(wakeTime) < 0.1 {
// User Tap on notification Started the App
}
else {
// DO stuff here if you ONLY want it to happen when the push arrives
}
completionHandler(.NewData)
}
else {
completionHandler(.NoData)
}
}
}
斯威夫特3
class AppDelegate: UIResponder, UIApplicationDelegate {
var wakeTime : Date = Date() // when did our application wake up most recently?
func applicationWillEnterForeground(_ application: UIApplication) {
// time stamp the entering of foreground so we can tell how we got here
wakeTime = Date()
}
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
// ensure the userInfo dictionary has the data you expect
if let type = userInfo["type"] as? String, type == "status" {
// IF the wakeTime is less than 1/10 of a second, then we got here by tapping a notification
if application.applicationState != UIApplicationState.background && Date().timeIntervalSince(wakeTime) < 0.1 {
// User Tap on notification Started the App
}
else {
// DO stuff here if you ONLY want it to happen when the push arrives
}
completionHandler(.newData)
}
else {
completionHandler(.noData)
}
}
}
我测试了这两种情况在iOS(应用程序在后台,应用程序不运行)9+和它的作品就像一个魅力。 0.1秒是相当保守太,实际值〜0.002s所以0.01是罚款为好。
Answer 5:
雨燕2.0对于“未运行”状态(本地及远程通知)
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
// Handle notification
if (launchOptions != nil) {
// For local Notification
if let localNotificationInfo = launchOptions?[UIApplicationLaunchOptionsLocalNotificationKey] as? UILocalNotification {
if let something = localNotificationInfo.userInfo!["yourKey"] as? String {
self.window!.rootViewController = UINavigationController(rootViewController: YourController(yourMember: something))
}
} else
// For remote Notification
if let remoteNotification = launchOptions?[UIApplicationLaunchOptionsRemoteNotificationKey] as! [NSObject : AnyObject]? {
if let something = remoteNotification["yourKey"] as? String {
self.window!.rootViewController = UINavigationController(rootViewController: YourController(yourMember: something))
}
}
}
return true
}
Answer 6:
在application:didReceiveRemoteNotification:
检查您是否已经收到通知,当您的应用程序是在前台或后台。
如果它在后台收到的,自通知启动应用程序。
-(void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo {
if ([UIApplication sharedApplication].applicationState == UIApplicationStateActive) {
NSLog(@"Notification received by running app");
} else {
NSLog(@"App opened from Notification");
}
}
Answer 7:
当应用程序被终止,并且用户轻敲推送通知
public func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
if launchOptions?[UIApplicationLaunchOptionsRemoteNotificationKey] != nil {
print("from push")
}
}
当应用程序在后台,而用户轻敲推notificaion
如果用户打开从系统显示的警告你的应用程序时,系统可能会当你的应用程序即将进入前台 ,让您可以更新您的用户界面,并显示与通知信息再次调用此方法。
public func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject], fetchCompletionHandler completionHandler: (UIBackgroundFetchResult) -> Void) {
if application.applicationState == .Inactive {
print("from push")
}
}
根据您的应用程序,它也可以给你无声推送与content-available
内部aps
,所以要意识到这一点,以及:)见https://stackoverflow.com/a/33778990/1418457
Answer 8:
对于SWIFT:
func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject]) {
PFPush.handlePush(userInfo)
if application.applicationState == UIApplicationState.Inactive || application.applicationState == UIApplicationState.Background {
//opened from a push notification when the app was on background
}
}
Answer 9:
是的,你可以通过在此的appDelegate方法检测:
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
{
/* your Code*/
}
对于本地通知:
- (void)application:(UIApplication *)application
didReceiveLocalNotification:(UILocalNotification *)notification
{
/* your Code*/
}
Answer 10:
发布本作Xamarin用户。
如果所述应用程序是经由推送通知发起检测的关键是AppDelegate.FinishedLaunching(UIApplication app, NSDictionary options)
的方法,而这在通过选择字典。
选项字典将在它这个关键,如果它是一个本地通知: UIApplication.LaunchOptionsLocalNotificationKey
。
如果它是一个远程通知,这将是UIApplication.LaunchOptionsRemoteNotificationKey
。
当密钥是LaunchOptionsLocalNotificationKey
,对象的类型是UILocalNotification
。 然后你可以看一下该通知,并确定它是具体的通知。
亲尖端: UILocalNotification
不具有标识符它,以相同的方式UNNotificationRequest
一样。 放入用户信息包含的requestId字典键,以便测试时UILocalNotification
,你必须提供一个具体的requestId立足于一些逻辑。
我发现,即使是在创建一个使用位置通知时的iOS 10+设备UNUserNotificationCenter
的AddNotificationRequest
& UNMutableNotificationContent
,当应用程序没有运行(我杀了它),并通过点击通知中心的通知发布,该字典仍然包含UILocalNotificaiton
对象。
这意味着,我的代码,用于检查通知基于将推出iOS8上和iOS设备10+工作
public override bool FinishedLaunching (UIApplication app, NSDictionary options)
{
_logger.InfoFormat("FinishedLaunching");
if(options != null)
{
if (options.ContainsKey(UIApplication.LaunchOptionsLocalNotificationKey))
{
//was started by tapping a local notification when app wasn't previously running.
//works if using UNUserNotificationCenter.Current.AddNotificationRequest OR UIApplication.SharedApplication.PresentLocalNotificationNow);
var localNotification = options[UIApplication.LaunchOptionsLocalNotificationKey] as UILocalNotification;
//I would recommended a key such as this :
var requestId = localNotification.UserInfo["RequestId"].ToString();
}
}
return true;
}
Answer 11:
如果有人想在SWIFT 3回答
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any]) {
switch application.applicationState {
case .active:
//app is currently active, can update badges count here
break
case .inactive:
//app is transitioning from background to foreground (user taps notification), do what you need when user taps here
break
case .background:
//app is in background, if content-available key of your notification is set to 1, poll to your backend to retrieve data and update your interface here
break
default:
break
}
}
Answer 12:
只有一种可靠的方法,并且它仅适用于iOS的10+:
使用UNUserNotificationCenter
实施UNUserNotificationCenterDelegate
方法:
- (void) userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void (^)(void))completionHandler {
//Here you can get your original push if you need to
NSDictionary* pusDict = response.notification.request.content.userInfo;
if ([response.actionIdentifier isEqualToString: UNNotificationDefaultActionIdentifier]) {
//User tapped the notification
} else if ([response.actionIdentifier isEqualToString: UNNotificationDismissActionIdentifier]) {
//User dismissed the notification
} else if ([response.actionIdentifier isEqualToString: MYCustomActionId]) {
//User chose my custom defined action
}
...
}
Answer 13:
:我会,我创造了我自己用更准确地进行可视化,并考虑所有其它状态的状态图开始https://docs.google.com/spreadsheets/d/e/2PACX-1vSdKOgo_F1TZwGJBAED4C_7cml0bEATqeL3P9UKpBwASlT6ZkU3iLdZnOZoevkMzOeng7gs31IFhD-L/pubhtml ?GID = 0&单=真
使用该图表中,我们可以看到什么是为了建立一个强大的处理通知系统,它工作在几乎所有可能的用例实际需要。
完整的解决方案↓
- 在didReceiveRemoteNotification商店通告的负载
- 在applicationWillEnterForeground和didFinishLaunchingWithOptions 清除存储的通知
- 为了解决其中控制中心/通知中心拉,你可以使用一个标志willResignActiveCalled和它最初设置为false的情况下,在applicationWillResignActive方法设置为true,
- 在didReceiveRemoteNotification方法,保存通知(USERINFO)仅当willResignActiveCalled是假的。
- 重置willResignActiveCalled在 applicationDidEnterBackground和applicationDidBecomeActive方法错误 。
注意:类似的答案,建议在Eric的答复意见,但是,状片有助于找出所有可能的情况,因为我在我的应用程序一样。
请从下面的完整代码,如果任何特定的情况下,不处理如下评论:
AppDelegate中
class AppDelegate: UIResponder, UIApplicationDelegate {
private var willResignActiveCalled = false
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
NotificationUtils.shared.notification = nil
return true
}
func applicationWillResignActive(_ application: UIApplication) {
willResignActiveCalled = true
}
func applicationDidEnterBackground(_ application: UIApplication) {
willResignActiveCalled = false
}
func applicationWillEnterForeground(_ application: UIApplication) {
NotificationUtils.shared.notification = nil
}
func applicationDidBecomeActive(_ application: UIApplication) {
willResignActiveCalled = false
NotificationUtils.shared.performActionOnNotification()
}
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
if !willResignActiveCalled { // Check if app is in inactive by app switcher, control center, or notification center
NotificationUtils.shared.handleNotification(userInfo: userInfo)
}
}
}
NotificationUtils:这是你可以写所有的代码,以导航到应用程序的不同部分,处理数据库(CoreData /领域),并做到这一点需要在收到通知时做所有其他的东西。
class NotificationUtils {
static let shared = NotificationUtils()
private init() {}
var notification : [AnyHashable: Any]?
func handleNotification(userInfo : [AnyHashable: Any]){
if UIApplication.shared.applicationState == UIApplicationState.active {
self.notification = userInfo //Save Payload
//Show inApp Alert/Banner/Action etc
// perform immediate action on notification
}
else if UIApplication.shared.applicationState == UIApplicationState.inactive{
self.notification = userInfo
}
else if UIApplication.shared.applicationState == UIApplicationState.background{
//Process notification in background,
// Update badges, save some data received from notification payload in Databases (CoreData/Realm)
}
}
func performActionOnNotification(){
// Do all the stuffs like navigating to ViewControllers, updating Badges etc
defer {
notification = nil
}
}
}
Answer 14:
直接从该文档
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo:nil
如果应用程序正在运行并且接收到远程通知时,应用程序调用该方法来处理该通知。
你的这个方法的实现应该使用的通知采取适当的行动过程。
一点点后
如果在推送通知到达时,应用程序没有运行,该方法启动应用程序,并提供了在启动选项字典中的相应信息。
应用程序不调用此方法来处理推送通知。
相反,你的执行
application:willFinishLaunchingWithOptions:
要么
application:didFinishLaunchingWithOptions:
方法需要得到推送通知的有效载荷数据,并作出适当的反应。
Answer 15:
您可以使用:
-(void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
处理远程推送通知。
检查这里的文档
Answer 16:
我还没有尝试过,但也许你可以给自己发送通知? http://nshipster.com/nsnotification-and-nsnotificationcenter/
Answer 17:
// shanegao's code in Swift 2.0
func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject])
{
if ( application.applicationState == UIApplicationState.Inactive || application.applicationState == UIApplicationState.Background ){
print("opened from a push notification when the app was on background")
}else{
print("opened from a push notification when the app was on foreground")
}
}
Answer 18:
这个问题的问题是,“打开”应用程序不明确。 一个应用程序或者是冷启动从不运行的状态,或者它是从非活动状态重新激活(例如,从其他应用程式切换回它)。 这里是我的解决方案来区分所有这些可能的状态:
typedef NS_ENUM(NSInteger, MXAppState) {
MXAppStateActive = 0,
MXAppStateReactivated = 1,
MXAppStateLaunched = 2
};
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// ... your custom launch stuff
[[MXDefaults instance] setDateOfLastLaunch:[NSDate date]];
// ... more custom launch stuff
}
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
// Through a lot of trial and error (by showing alerts), I can confirm that on iOS 10
// this method is only called when the app has been launched from a push notification
// or when the app is already in the Active state. When you receive a push
// and then launch the app from the icon or apps view, this method is _not_ called.
// So with 99% confidence, it means this method is called in one of the 3 mutually exclusive cases
// 1) we are active in the foreground, no action was taken by the user
// 2) we were 'launched' from an inactive state (so we may already be in the main section) by a tap
// on a push notification
// 3) we were truly launched from a not running state by a tap on a push notification
// Beware that cases (2) and (3) may both show UIApplicationStateInactive and cant be easily distinguished.
// We check the last launch date to distinguish (2) and (3).
MXAppState appState = [self mxAppStateFromApplicationState:[application applicationState]];
//... your app's logic
}
- (MXAppState)mxAppStateFromApplicationState:(UIApplicationState)state {
if (state == UIApplicationStateActive) {
return MXAppStateActive;
} else {
NSDate* lastLaunchDate = [[MXDefaults instance] dateOfLastLaunch];
if (lastLaunchDate && [[NSDate date] timeIntervalSinceDate:lastLaunchDate] < 0.5f) {
return MXAppStateLaunched;
} else {
return MXAppStateReactivated;
}
}
return MXAppStateActive;
}
而MXDefaults
仅仅是一个小包装NSUserDefaults
。
Answer 19:
对于swift
func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject]){
++notificationNumber
application.applicationIconBadgeNumber = notificationNumber;
if let aps = userInfo["aps"] as? NSDictionary {
var message = aps["alert"]
println("my messages : \(message)")
}
}
Answer 20:
当应用程序在后台,你可以使用shanegao
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
{
if ( application.applicationState == UIApplicationStateInactive || application.applicationState == UIApplicationStateBackground )
{
//opened from a push notification when the app was on background
}
}
但是,如果你要启动的应用程序,当应用程序被关闭,并要调试您的应用程序,你可以去修改方案 ,并在左侧菜单中选择运行 ,然后在启动选择等待可执行文件来启动 ,然后你的应用程序启动时,你点击推送通知
编辑方案>运行>等待可执行上马
Answer 21:
func application(_ application: UIApplication, didReceiveRemoteNotification data: [AnyHashable : Any]) {
print("Push notification received: \(data)")
if let info = data["aps"] as? Dictionary<String, AnyObject> {
let alertMsg = info["alert"] as! String
print(alertMsg)
switch application.applicationState {
case .active:
print("do stuff in case App is active")
case .background:
print("do stuff in case App is in background")
// navigateToChatDetailViewControler(pushdata: data)
case .inactive:
print("do stuff in case App is inactive")
// navigateToChatDetailViewControler(pushdata: data)
}
}
}
Answer 22:
对于SWIFT用户:
如果你想从推或类似的东西开盘推出不同的页面,你需要检查它在didFinishLaunchingWithOptions
这样的:
let directVc: directVC! = directVC(nibName:"directVC", bundle: nil)
let pushVc: pushVC! = pushVC(nibName:"pushVC", bundle: nil)
if let remoteNotification = launchOptions?[UIApplicationLaunchOptionsRemoteNotificationKey] as? NSDictionary {
self.navigationController = UINavigationController(rootViewController: pushVc!)
} else {
self.navigationController = UINavigationController(rootViewController: directVc!)
}
self.window!.rootViewController = self.navigationController
Answer 23:
斯威夫特:
我跑推送通知(背景取)。 当我的应用程序是在后台,我收到一个推送通知,我发现在这的appDelegate将didReceiveRemoteNotification两次调用; 一旦当接收和通知的通知提醒其他当用户点击。
为了检测是否被点击通知提醒,只检查是否applicationState原始值== 1内didReceiveRemoteNotification中的appDelegate。
func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject: AnyObject]) {
// If not from alert click applicationState(1)
if (application.applicationState.rawValue != 1) {
// Run your code here
}
}
我希望这有帮助。
Answer 24:
雨燕3.0
在AppDelegate中,在函数“didFinishLaunchingWithOptions”处理远程通知,一些延迟,并打开您的ViewController。 您可以使用延迟加载成功后,应用程序来处理通知。
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
if let remoteNotification = launchOptions?[UIApplicationLaunchOptionsKey.remoteNotification] as! [NSObject : AnyObject]? {
AppHelper.delay(0.8, closure: {
self.handelNotification(dic: remoteNotification as! [String : Any])
})
}
文章来源: Detect if the app was launched/opened from a push notification