Откройте диспетчер представлений, когда получено одноразовое уведомление iOS

Я хочу открыть определенный контроллер представления, когда пользователь нажимает на полученное сообщение push-уведомления, но когда я получаю push-уведомление и щелкаю сообщение, открывается только приложение, но оно не перенаправляется на определенный контроллер представления.

Мой код

-(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 push.

Ответ 1

У вас могут возникнуть проблемы с условием if (applicationIsActive).

Поместите точку останова на -didReceiveRemoteNotification и посмотрите, выполняется ли она в разных сценариях и посмотрите, идет ли она в if -condition.

(не связанный в определенной степени, но заслуживающий проверки) этот вопрос:
didReceiveRemoteNotification в фоновом режиме


Примечание:

-didReceiveRemoteNotification не будет выполняться, если ваше приложение было (первоначально) закрыто, и вы нажали на push-уведомление, чтобы открыть приложение.
Этот метод выполняется, когда push-уведомление принимается, когда приложение находится на переднем плане или когда приложение переходит из фона на передний план.

Справочник Apple: https://developer.apple.com/documentation/uikit/uiapplicationdelegate

Если приложение запущено и получает удаленное уведомление, приложение вызывает этот метод для обработки уведомления. Ваша реализация этот метод должен использовать уведомление, чтобы пройти соответствующий курс действия.
...
Если приложение не запускается при поступлении push-уведомления, метод запускает приложение и предоставляет соответствующую информацию в словарь параметров запуска. Приложение не вызывает этот метод для обработки это толчок уведомление. Вместо этого ваша реализация приложение: willFinishLaunchingWithOptions: или приложение: didFinishLaunchingWithOptions: метод должен получить нажимать данные полезной нагрузки и реагировать соответствующим образом.


Итак... Когда приложение не работает и получено push-уведомление, когда пользователь нажимает на push-уведомление, приложение запускается и теперь... содержимое push-уведомления будет доступно в -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 Doc при обработке локальных и удаленных уведомлений

Ответ 2

В имени идентификатора есть дополнительное пространство. Удалите его и попробуйте:

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

Ответ 3

У меня была такая же проблема, что, когда приложение приостановлено/завершено, а push-уведомление приходит, мое приложение только открывалось, а не перенаправлялось на конкретный экран, соответствующий этому уведомлению, это решение,

в - (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: уведомление вы можете перенаправить пользователя на соответствующий экран, например...

//** 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];
    }
}

Ответ 4

В Swift 4

Если вам нужно добиться вышеупомянутого случая, вы должны обработать 2 случая

  1. Когда ваше приложение находится в фоновом/переднем плане (если push-уведомление не отключено)
  2. Когда ваше приложение находится в неактивном состоянии

Здесь я использую категорию (встроенный параметр в полезных данных push-уведомлений для определения типа уведомлений), если существует более 1 типа уведомлений. В случае, если у вас есть только 1 тип уведомления, нет необходимости проверять категорию.

Таким образом, для обработки первого случая, код в файле AppDelegate выглядит следующим образом

     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() {

            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- А также необходимо два добавить функцию наблюдателя уведомлений для добавления действий, которые будут выполняться с тем же именем, которое используется в 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)  
   }  
       }

Таким образом, всякий раз, когда уведомление открывается, когда приложение находится на переднем плане или в фоне, вышеуказанное будет выполняться и перемещаться к соответствующему контроллеру представления в соответствии с категорией в полезной нагрузке.

Теперь второй случай

Мы знаем, что когда приложение неактивно, первая функция, которая будет вызываться при открытии push-уведомления,

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

Поэтому мы должны проверить в этой функции, запущено ли приложение, открыв push-уведомление или щелкнув значок приложения. Для этого есть положение, предоставленное нам. Функция будет выглядеть следующим образом после добавления необходимого кода.

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

Это позволит достичь цели открыть конкретный контроллер представления при открытии push-уведомления.

Вы можете пройти через это blog- Как открыть определенный View Controller, когда пользователь нажимает на полученное push-уведомление? для справки.

Ответ 5

Если вам нужно добиться вышеупомянутого случая, вы должны обработать 2 случая

  1. Когда ваше приложение находится в фоновом/переднем плане (если push-уведомления не отключены)
  2. Когда ваше приложение неактивно

S для обработки первого случая, который вы должны обработать в функции ниже.

    func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {  
 completionHandler()  }

И для обработки второго случая мы должны обработать его в следующей функции

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

Вы можете пройти через это Как открыть определенный View Controller, когда пользователь нажимает на полученное push-уведомление? чтобы понять поток правильно. Просто пройдите вышеуказанные 2 пункта.