【问题标题】:Open a view controller when a iOS push notification is received收到 iOS 推送通知时打开视图控制器
【发布时间】:2014-01-12 11:42:34
【问题描述】:

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

我的代码是

-(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];
     }
}

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

【问题讨论】:

标签: ios cocoa-touch push-notification appdelegate


【解决方案1】:

您可能遇到if (applicationIsActive) 条件的问题。

-didReceiveRemoteNotification上下一个断点,看看它是否在不同的场景下执行,看看它是否在if-条件内。

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


注意:

如果您的应用(最初)关闭并且您点击了推送通知以打开应用,

-didReceiveRemoteNotification 将不会执行。
当应用程序在前台或应用程序从后台转换到前台时收到推送通知时,将执行此方法。

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

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


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

换句话说...-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
    }
    //...
}

另请阅读Apple's Doc on Handling Local and Remote Notifications

【讨论】:

  • 如果您的应用在后台进入前台,因为用户触摸推送通知,应用不会经过appliaction:didFinishLaunchingWithOptions(因为它已经启动)并触发application:didReceiveRemoteNotification:
  • 感谢您的回复,我使用了您的代码,也尝试了 if( [apsInfo objectForKey:@"alert"] != NULL) { Push to view controller} 但是当应用程序关闭时,应用程序仍然存在在主屏幕中而不是在消息视图控制器中
  • @cdsoft :对不起,我没有完全关注你。当您单击推送通知并启动应用程序时,它将执行 if 条件,但当没有待处理的推送通知时,您的应用程序将正常启动。
  • 感谢您的帮助,我使用了您的代码块,我在 didFinishLaunchingWithOptions 中编写了相同的代码,并将重定向代码编写到 PushBildirimlerim 视图。如果应用程序关闭并且我单击新推送通知,应用程序将打开但不会重定向 PushBildirimlerim 视图。我无法解决这个问题。
【解决方案2】:

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

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

【讨论】:

  • 应用关闭时didReceiveRemoteNotification不被调用,当你的应用处于活动状态或点击通知中心的通知时调用。
  • 根据你的情况我应该使用哪种方法?
  • 请正确阅读@staticVoidMan 的回答,他已经解释过了。
  • @Virussmca,感谢您的回复,但这解决了我的问题...UIViewController * viewController = (UIViewController*)[[NSClassFromString(@"ViewControllerName") alloc] init];
【解决方案3】:

在 Swift 4 中

如果你需要实现上述情况你必须处理2个情况

  1. 当您的应用程序处于后台/前台状态时(如果推送 通知不会静音)
  2. 当您的应用处于非活动状态时

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

那么对于第一种情况的处理,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()  }  

对于方法 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) 

对于方法 1- 并且还需要添加两个Notification Observer函数,用于添加与Observer中使用的同名要执行的动作。

    // 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)  
   }  
       }

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

现在是第二种情况

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

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

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

        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)  
     }  

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

您可以浏览此博客-How to open a particular View Controller when the user taps on the push notification received? 以供参考。

【讨论】:

  • 什么是默认视图控制器?如果我在第 8 个控制器上并且在点击 push 后我必须在第 2 个控制器上移动会发生什么
  • 在这种情况下,您必须在第 8 个控制器上添加观察者。这里作为示例,我已添加到仪表板等默认视图中。我们可以根据需要为多个视图控制器添加推送通知的观察者。如果我错了,请告诉我。
  • 但在这种情况下,我们必须在每个控制器中添加观察者,我更喜欢从应用委托检查顶部视图控制器,然后从那里推送到目标视图控制器
  • 是的。感谢您用这种方法更新我。我会尽快在我的回答中更新。
  • 我已经用新方法更新了答案。 @PramodShukla 请检查我是否错了。
【解决方案4】:

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

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

代码如下...

- (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;
}

然后在 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];
    }
}

【讨论】:

    【解决方案5】:

    点击通知时 调用通知委托函数

    func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {
    
            let nav = UINavigationController()
            nav.navigationBar.isHidden = true
            let first = Router.shared.splashVC()
            let sceond = Router.shared.CustomTabbarVC()
            let third = Router.shared.ProviderDetailsVC()
            sceond.selectedIndex = 2
            nav.viewControllers = [first,sceond,third]
            UIApplication.shared.keyWindow?.rootViewController = nav
            UIApplication.shared.keyWindow?.makeKeyAndVisible()
    
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-08-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多