收到 iOS 推送通知时打开视图控制器

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/20757362/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-30 22:52:43  来源:igfitidea点击:

Open a view controller when a iOS push notification is received

ioscocoa-touchpush-notificationappdelegate

提问by cdsoft

I want to open a specific view controller when a user clicks on the received push notification message, but when I receive a push notification message and click the message, only the application opens, but it does not redirect to a specific view controller.

我想在用户单击收到的推送通知消息时打开特定的视图控制器,但是当我收到推送通知消息并单击该消息时,只有应用程序打开,但它不会重定向到特定的视图控制器。

My code is

我的代码是

-(void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo {
    if (applicationIsActive) {
        UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"Bildirim"
                                                            message:[NSString stringWithFormat:@"%@ ",[[userInfo objectForKey:@"aps"] objectForKey:@"alert"]]
                                                           delegate:self cancelButtonTitle:@"Ok" 
                                                  otherButtonTitles:nil];
        [alertView show];

        UIViewController *vc = self.window.rootViewController;
        PushBildirimlerim *pvc = [vc.storyboard instantiateViewControllerWithIdentifier:@"PushBildirimlerim "];

        [vc presentViewController:pvc animated:YES completion:nil];
     }
}

My question is related with the iOS push notifications.

我的问题与 iOS 推送通知有关。

回答by staticVoidMan

You may be having issues with the if (applicationIsActive)condition.

您的if (applicationIsActive)病情可能有问题。

Put a breakpoint on -didReceiveRemoteNotificationand see whether it executes in different scenarios and see if it goes within the if-condition.

把一个断点-didReceiveRemoteNotification,并看它是否在不同情况下执行,看看是否是不言而喻的范围内,如果-condition。

(unrelated to a certain extent but worth checking) this question:
didReceiveRemoteNotification when in background

在一定程度上无关但值得检查)这个问题:
didReceiveRemoteNotification when in background



Note:

笔记:

-didReceiveRemoteNotificationwill not execute if your app was (initially) closed and you clicked on the push notification to open the app.
This method executes when a push notification is received while the application is in the foreground or when the app transitions from background to foreground.

-didReceiveRemoteNotification如果您的应用程序(最初)关闭并且您单击推送通知以打开应用程序,则不会执行。
当应用程序在前台或应用程序从后台转换到前台时收到推送通知时,将执行此方法。

Apple Reference: https://developer.apple.com/documentation/uikit/uiapplicationdelegate

苹果参考:https: //developer.apple.com/documentation/uikit/uiapplicationdelegate

If the app is running and receives a remote notification, the app calls this method to process the notification. Your implementation of this method should use the notification to take an appropriate course of action.
...
If the app is not running when a push notification arrives, the method launches the app and provides the appropriate information in the launch options dictionary. The app does not call this method to handle that push notification. Instead, your implementation of the application:willFinishLaunchingWithOptions:or application:didFinishLaunchingWithOptions:method needs to get the push notification payload data and respond appropriately.

如果应用程序正在运行并收到远程通知,则应用程序调用此方法来处理通知。您对这个方法的实现应该使用通知来采取适当的行动。
...
如果推送通知到达时应用程序未运行,该方法将启动应用程序并在启动选项字典中提供适当的信息。应用程序不会调用此方法来处理该推送通知。相反,您的 application:willFinishLaunchingWithOptions:application:didFinishLaunchingWithOptions:方法的实现需要获取推送通知有效负载数据并做出适当的响应。



So... When the app is not runningand a push notification is received, when the user clicks on the push notification, the app is launched and now... the push notification contents will be available in the -didFinishLaunchingWithOptions:method in it's launchOptionsparameter.

所以......当应用程序没有运行并且收到推送通知时,当用户点击推送通知时,应用程序被启动,现在......推送通知内容将-didFinishLaunchingWithOptions:在其launchOptions参数的方法中可用。

In other words... -didReceiveRemoteNotificationwon't execute this time and you'll also need to do this:

换句话说......-didReceiveRemoteNotification这次不会执行,你还需要这样做:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    //...
    NSDictionary *userInfo = [launchOptions valueForKey:@"UIApplicationLaunchOptionsRemoteNotificationKey"];
    NSDictionary *apsInfo = [userInfo objectForKey:@"aps"];

    if(apsInfo) {
        //there is some pending push notification, so do something
        //in your case, show the desired viewController in this if block
    }
    //...
}

Also read Apple's Doc on Handling Local and Remote Notifications

另请阅读Apple 关于处理本地和远程通知的文档

回答by Toseef Khilji

There is an extra space in the identifier name. Remove it and try:

标识符名称中有一个额外的空格。删除它并尝试:

UIStoryboard *mainstoryboard = [UIStoryboard storyboardWithName:@"MainStoryboard" bundle:nil];
PushBildirimlerim* pvc = [mainstoryboard instantiateViewControllerWithIdentifier:@"PushBildirimlerim"];
[self.window.rootViewController presentViewController:pvc animated:YES completion:NULL];

回答by iShwar

I was having same problem that when app is suspended/terminated and push notification arrives my app was only opening and not redirecting to specific screen corresponding to that notification the solution is,

我遇到了同样的问题,当应用程序被暂停/终止并且推送通知到达时,我的应用程序只是打开而不是重定向到与该通知对应的特定屏幕,解决方案是,

in - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptionsthis method the parameter launchOptionstells us if it has the notification by checking that we need to call the method to redirect to specific screen

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions这个方法中,参数launchOptions通过检查我们是否需要调用重定向到特定屏幕的方法来告诉我们它是否有通知

the code is as below...

代码如下...

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    //your common or any code will be here at last add the below code..

    NSMutableDictionary *notification = [launchOptions objectForKey:UIApplicationLaunchOptionsRemoteNotificationKey];

    if (notification)
    {
//this notification dictionary is same as your JSON payload whatever you gets from Push notification you can consider it as a userInfo dic in last parameter of method -(void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
        NSLog(@"%@",notification);
        [self showOfferNotification:notification];
    }

     return YES;
}

then in the method showOfferNotification:notification you can redirect user to corresponding screen like...

然后在 showOfferNotification:notification 方法中,您可以将用户重定向到相应的屏幕,例如...

//** added code for notification
-(void)showOfferNotification:(NSMutableDictionary *)offerNotificationDic{
//This whole is my coding stuff.. your code will come here..
    NSDictionary *segueDictionary = [offerNotificationDic valueForKey:@"aps"];

    NSString *segueMsg=[[NSString alloc]initWithFormat:@"%@",[segueDictionary valueForKey:@"alert"]];

    NSString *segueID=[[NSString alloc]initWithFormat:@"%@",[offerNotificationDic valueForKey:@"id"]];

    NSString *segueDate=[[NSString alloc]initWithFormat:@"%@",[offerNotificationDic valueForKey:@"date"]];

    NSString *segueTime=[[NSString alloc]initWithFormat:@"%@",[offerNotificationDic valueForKey:@"time"]];

    NSLog(@"Show Offer Notification method : segueMsg %@ segueDate %@ segueTime %@ segueID %@",segueMsg,segueDate,segueTime,segueID);

    if ([segueID isEqualToString:@"13"]){

        NSString *advertisingUrl=[[NSString alloc]initWithFormat:@"%@",[offerNotificationDic valueForKey:@"advertisingUrl"]];

        NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
        [defaults setObject:segueMsg forKey:@"notificationMsg"];
        [defaults setObject:segueDate forKey:@"notifcationdate"];
        [defaults setObject:segueTime forKey:@"notifcationtime"];
        [defaults setObject:advertisingUrl forKey:@"advertisingUrl"];
        [defaults synchronize];

        navigationController = (UINavigationController *)self.window.rootViewController;
        UIStoryboard *mainStoryboard = [UIStoryboard storyboardWithName:@"Main_iPhone" bundle: nil];
        FLHGAddNotificationViewController *controller = (FLHGAddNotificationViewController*)[mainStoryboard instantiateViewControllerWithIdentifier: @"offerViewController"];
        [navigationController pushViewController:controller animated:YES];
    }
}

回答by Nishigandha Ahire

In Swift 4

在斯威夫特 4

If you need to achieve the above case you have to handle 2 cases

如果您需要实现上述情况,则必须处理2种情况

  1. When your app is in the background/Foreground state(if push notification is not silenced)
  2. When your app is in the inactive state
  1. 当您的应用处于后台/前台状态时(如果推送通知未静音)
  2. 当您的应用处于非活动状态时

Here I am using category(built in parameter in the payload of push notification to identify the type of notification) if there are more than 1 type of notifications. In case you have only 1 type of notification then no need to check for the category.

如果有超过 1 种类型的通知,我在这里使用 category(推送通知有效负载中的内置参数来识别通知类型)。如果您只有一种类型的通知,则无需检查类别。

So for handling the first case, the code is as follows in AppDelegate File

所以对于第一种情况的处理,AppDelegate File中的代码如下

     func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {  
     let userInfo = response.notification.request.content.userInfo  
     let title = response.notification.request.content.title 

  //Method- 1 -- By using NotificationCenter if you want to take action on push notification on particular View Controllers
     switch response.notification.request.content.categoryIdentifier  
     {  
      case "Second":  
       NotificationCenter.default.post(name: NSNotification.Name(rawValue: "SecondTypeNotification"), object: title, userInfo: userInfo)  
       break  
      case "Third":  
       NotificationCenter.default.post(name: NSNotification.Name(rawValue: "ThirdTypeNotification"), object: title, userInfo: userInfo)  
       break  
       default:  
        break  
     }

///Method -2 --- Check the view controller at the top and then push to the required View Controller


            if let currentVC = UIApplication.topViewController() {
                //the type of currentVC is MyViewController inside the if statement, use it as you want to
                if response.notification.request.content.categoryIdentifier == "Second"
                {
                    let storyboard = UIStoryboard(name: "Main", bundle: nil)
                    let vc: SecondViewController = storyboard.instantiateViewController(withIdentifier: "SecondViewController") as! SecondViewController
                    currentVC.navigationController?.pushViewController(vc, animated: true)
                }
                else if response.notification.request.content.categoryIdentifier == "Third"
                {
                    let storyboard = UIStoryboard(name: "Main", bundle: nil)
                    let vc: ThirdViewController = storyboard.instantiateViewController(withIdentifier: "ThirdViewController") as! ThirdViewController
                    currentVC.navigationController?.pushViewController(vc, animated: true)
                }

            }



     completionHandler()  }  

For Method 1- After which you have to add the observers in the default view controller as follows in viewDidLoad

对于方法 1- 之后,您必须在默认视图控制器中添加观察者,如下所示在 viewDidLoad

     NotificationCenter.default.addObserver(self,selector: #selector(SecondTypeNotification),  
                     name: NSNotification.Name(rawValue: "SecondTypeNotification"),  
                     object: nil)
     NotificationCenter.default.addObserver(self,selector:#selector(ThirdTypeNotification),  
                     name: NSNotification.Name(rawValue: "ThirdTypeNotification"),  
                     object: nil) 

For Method 1- And also need two add the Notification observer function for adding actions to be executed with the same name used in Observer.

对于方法 1- 并且还需要两个添加通知观察者功能,用于添加与观察者中使用的名称相同的要执行的动作。

    // Action to be taken if push notification is opened and observer is called while app is in background or active
     @objc func SecondTypeNotification(notification: NSNotification){  
 DispatchQueue.main.async  
   {  
     //Land on SecondViewController  
     let storyboard = UIStoryboard(name: "Main", bundle: nil)  
     let vc: SecondViewController = storyboard.instantiateViewController(withIdentifier: "SecondViewController") as! SecondViewController  
     self.navigationController?.pushViewController(vc, animated: true)  
   }   
    }
     @objc func ThirdTypeNotification(notification: NSNotification){  
 DispatchQueue.main.async  
   {  
     //Land on SecondViewController  
     let storyboard = UIStoryboard(name: "Main", bundle: nil)  
     let vc: ThirdViewController = storyboard.instantiateViewController(withIdentifier: "ThirdViewController") as! ThirdViewController  
     self.navigationController?.pushViewController(vc, animated: true)  
   }  
       }

So whenever a notification is opened when the app is in the foreground or background the above will execute and move to respective view controller according to the category in the payload.

因此,每当应用程序处于前台或后台时打开通知时,上述内容将根据有效负载中的类别执行并移动到相应的视图控制器。

Now the second case

现在第二种情况

We know that when the app is inactive the first function that will be called when the push notification is opened is

我们知道,当应用处于非活动状态时,推送通知打开时将调用的第一个函数是

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {  
 return true  
       }  

So we have to check in this function whether the app is launched by opening push notification or by clicking the app icon. For this, there is a provision provided to us. The function will look as follows after adding the required code.

所以我们必须在这个函数中检查应用程序是通过打开推送通知还是通过点击应用程序图标来启动的。为此,我们提供了一项规定。添加所需代码后,该函数将如下所示。

        func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {  
     FirebaseApp.configure()  
     if #available(iOS 10.0, *) {  
       // For iOS 10 display notification (sent via APNS)  
       UNUserNotificationCenter.current().delegate = self  
       let authOptions: UNAuthorizationOptions = [.alert, .badge, .sound]  
       UNUserNotificationCenter.current().requestAuthorization(  
         options: authOptions,  
         completionHandler: {_, _ in })  
     } else {  
       let settings: UIUserNotificationSettings =  
         UIUserNotificationSettings(types: [.alert, .badge, .sound], categories: nil)  
       application.registerUserNotificationSettings(settings)  
     }  
     // Register the notification categories.  
     application.registerForRemoteNotifications()  
     Messaging.messaging().delegate = self  
     /// Check if the app is launched by opening push notification  
     if launchOptions?[UIApplication.LaunchOptionsKey.remoteNotification] != nil {  
       // Do your task here  
       let dic = launchOptions?[UIApplication.LaunchOptionsKey.remoteNotification] as? NSDictionary  
       let dic2 = dic?.value(forKey: "aps") as? NSDictionary  
       let alert = dic2?.value(forKey: "alert") as? NSDictionary  
       let category = dic2?.value(forKey: "category") as? String  
       // We can add one more key name 'click_action' in payload while sending push notification and check category for indentifying the push notification type. 'category' is one of the seven built in key of payload for identifying type of notification and take actions accordingly  


// Method - 1
       if category == "Second"  
       {  
         /// Set the flag true for is app open from Notification and on root view controller check the flag condition to take action accordingly  
         AppConstants.sharedInstance.userDefaults.set(true, forKey: AppConstants.sharedInstance.kisFromNotificationSecond)  
       }  
       else if category == "Third"  
       {  
        AppConstants.sharedInstance.userDefaults.set(true, forKey: AppConstants.sharedInstance.kisFromNotificationThird)  
       } 


// Method 2: Check top view controller and push to required view controller
 if let currentVC = UIApplication.topViewController() {
       if category == "Second"
       {
         let storyboard = UIStoryboard(name: "Main", bundle: nil)
         let vc: SecondViewController = storyboard.instantiateViewController(withIdentifier: "SecondViewController") as! SecondViewController
         currentVC.navigationController?.pushViewController(vc, animated: true)
       }
       else if category == "Third"
       {
         let storyboard = UIStoryboard(name: "Main", bundle: nil)
         let vc: ThirdViewController = storyboard.instantiateViewController(withIdentifier: "ThirdViewController") as! ThirdViewController
         currentVC.navigationController?.pushViewController(vc, animated: true)
        }

      } 
    }  
     return true  
 }  

For Method 1-
After this, check these flags value in the default view controller in viewdidLoad as follows

        if AppConstants.sharedInstance.userDefaults.bool(forKey: AppConstants.sharedInstance.kisFromNotificationSecond) == true  
     {  
       //Land on SecondViewController  
       let storyboard = UIStoryboard(name: "Main", bundle: nil)  
       let vc: SecondViewController = storyboard.instantiateViewController(withIdentifier: "SecondViewController") as! SecondViewController  
       self.navigationController?.pushViewController(vc, animated: true)  
       AppConstants.sharedInstance.userDefaults.set(false, forKey: AppConstants.sharedInstance.kisFromNotificationSecond)  
     }  
     if AppConstants.sharedInstance.userDefaults.bool(forKey: AppConstants.sharedInstance.kisFromNotificationThird) == true  
     {  
       //Land on SecondViewController  
       let storyboard = UIStoryboard(name: "Main", bundle: nil)  
       let vc: ThirdViewController = storyboard.instantiateViewController(withIdentifier: "ThirdViewController") as! ThirdViewController  
       self.navigationController?.pushViewController(vc, animated: true)  
       AppConstants.sharedInstance.userDefaults.set(false, forKey: AppConstants.sharedInstance.kisFromNotificationThird)  
     }  

This will achieve the goal to open a particular view controller when the push notification is opened.

这将实现在推送通知打开时打开特定视图控制器的目标。

You can go through this blog- How to open a particular View Controller when the user taps on the push notification received?for reference.

您可以浏览此博客 -如何在用户点击收到的推送通知时打开特定的视图控制器?以供参考。