Подтвердить что ты не робот

Управление загрузкой контроллера просмотра после получения push-уведомления в SWIFT

Как только я получаю push-уведомление и прокручиваю его, он просто открывает мое приложение, а не VC, которое я хочу.

Итак, мой вопрос: как загрузить VC, который я хочу? Я знаю, если приложение открыто, я переместил VC на другой внутри didReceiveRemoteNotification, но как это сделать, если приложение не открыто? или если он находится в фоновом режиме?

Также у меня есть два разных push-уведомления, поэтому мне нужно, чтобы он переместил ONE из двух разных VC. Как я могу рассказать о различии между различными push-уведомлениями?

Спасибо.

4b9b3361

Ответ 1

Обновлено для Swift 3.0

Как было сказано, вы хотите зарегистрироваться на удаленные уведомления в applicationDidLaunchWithOptions:

 func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
    let pushSettings = UIUserNotificationSettings(types: [.alert, .badge, .sound], categories: nil)
    UIApplication.shared.registerUserNotificationSettings(pushSettings)
    UIApplication.shared.registerForRemoteNotifications()
}

Невозможно узнать, в каком режиме viewController вы будете, когда вернетесь с экрана lockScreen/Background. Что я делаю, я отправляю уведомление из приложения appDelegate. Когда вы получаете remoteNotification, вызывается didReceiveRemoteNotification в appDelegate.

 func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any]) {
    let notif = JSON(userInfo) // SwiftyJSON required 

В зависимости от того, что содержит ваше уведомление, вы должны сначала убедиться, что он не нуль, а затем вызвать уведомление, которое будет улавливаться viewControllers, которое должно поймать это уведомление. Может выглядеть так: просто возьмите это как пример:

if notif["callback"]["type"] != nil{
    NotificationCenter.default.post(name: Notification.Name(rawValue: "myNotif"), object: nil)
    // This is where you read your JSON to know what kind of notification you received, for example :    

}

Например, если вы получаете уведомление по сообщениям, и вы больше не вошли в систему, потому что токен истек, тогда уведомление никогда не будет уловлено в контроллере представления, потому что оно никогда не будет просмотрено.

Теперь для той части, где вы обнаружите уведомление в контроллере представления. В представленииWillAppear:

 override func viewWillAppear(_ animated: Bool) {
    NotificationCenter.default.addObserver(self, selector: #selector(self.catchIt), name: NSNotification.Name(rawValue: "myNotif"), object: nil)
}

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

func catchIt(_ userInfo: Notification){

    if userInfo.userInfo?["userInfo"] != nil{
        let prefs: UserDefaults = UserDefaults.standard
        prefs.removeObject(forKey: "startUpNotif")
        prefs.synchronize()

        let storyboard = UIStoryboard(name: "Main", bundle: nil)
        let vc: RedirectAppInactiveVC = storyboard.instantiateViewController(withIdentifier: "RedirectAppInactiveVC") as! RedirectAppInactiveVC
        self.navigationController?.pushViewController(vc, animated: true)

    }
    else{
        let storyboard = UIStoryboard(name: "Main", bundle: nil)
        let vc: RedirectAppActiveVC = storyboard.instantiateViewController(withIdentifier: "RedirectAppActiveVC") as! RedirectAppActiveVC
        self.navigationController?.pushViewController(vc, animated: true)
    }
}

Не забывайте отменять подписку на уведомления при выходе из контроллера представления, иначе viewController, если он все еще находится в стеке, поймает уведомление и выполнит его (ну, возможно, вы захотите этого, но более безопасно знать, что вы вступают). Поэтому я предлагаю отказаться от подписки в viewWillDisappear:

  override func viewWillDisappear(_ animated: Bool) {
    NotificationCenter.default.removeObserver(self)
}

Выполняя это, вы загрузите требуемый viewController. Теперь мы все еще не рассматривали все случаи. Что делать, если вы еще не открыли приложение. Очевидно, что UIViewController не загружен, и никто из них не сможет поймать уведомление. Вы хотите знать, получили ли вы уведомление в файле didFinishLaunchingWithOptions: в appDelegate. Что я делаю:

let prefs: UserDefaults = UserDefaults.standard
    if let remoteNotification = launchOptions?[UIApplicationLaunchOptionsKey.remoteNotification] as? NSDictionary {
        prefs.set(remoteNotification as! [AnyHashable: Any], forKey: "startUpNotif")
        prefs.synchronize()
    }

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

override func viewDidAppear(animated: Bool) {
    let prefs:UserDefaults = UserDefaults.standard
    if prefs.value(forKey: "startUpNotif") != nil{
        let userInfo: [AnyHashable: Any] = ["inactive": "inactive"]
        NotificationCenter.default.post(name: Notification.Name(rawValue: "myNotif"), object: nil, userInfo: userInfo as [AnyHashable: Any])
    }

Надеюсь, это поможет. Я также создал репозиторий github, чтобы проиллюстрировать его локальными уведомлениями: Local Observation Pattern (аналогично удаленным уведомлениям). Аналогичную логику можно реализовать с помощью корневого представления Controller Локальный шаблон уведомлений Local, я лично думаю, что это будет зависеть от того, что вы хотите реализовать.

Ответ 2

В дополнение к ответу @NickCatib, чтобы узнать, получили ли вы уведомление во время работы вашего приложения, и если это так, на переднем плане или в фоновом режиме вам необходимо использовать этот метод в AppDelegate:

func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject]) {


// You can determine your application state by
if UIApplication.sharedApplication().applicationState == UIApplicationState.Active {

// Do something you want when the app is active

} else {

// Do something else when your app is in the background


}
}

Ответ 3

При запуске приложения вы вызываете applicationDidLaunchWithOptions:

UIApplication.sharedApplication().registerUserNotificationSettings ( UIUserNotificationSettings(forTypes: (UIUserNotificationType.Alert | UIUserNotificationType.Badge | UIUserNotificationType.Sound), categories: nil))



if( launchOptions != nil){
    var notificationDict: AnyObject? = launchOptions?[UIApplicationLaunchOptionsRemoteNotificationKey]
    if(notificationDict != nil){
        handleNotification(notificationDict! as! [NSObject : AnyObject])
    }

}

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

Вот пример этого:

let notificationType = userInfo["aps"]!["alert"]!!["some-key-I-Need"]! as! String
var storyboard = UIStoryboard(name: "Main", bundle: nil)
let mainViewController = storyboard.instantiateInitialViewController() as! MyViewController
self.window?.rootViewController  = mainViewController

Ответ 4

Я нашел все ответы выше, чтобы быть очень полезным. Тем не менее, большинство проголосовавших не работало для меня, когда приложение отключено. Позже попытался выполнить ответы от @NickCatib и @thefredelement в сочетании, и они породили ошибку при выполнении раскадровки .instantiateInitialViewController() - "Не удалось отличить значение типа" UINavigationController ". Я узнал, что это произошло потому, что у меня есть файл раскадровки с NavController как rootViewController. Чтобы решить эту проблему, я создал новый контроллер навигации, который работал с проблемой: я потерял правильную навигацию для приложения, и в представлении даже не появилась кнопка" Назад". Ответ на мои проблемы состоял в том, чтобы использовать ответы @NickCatib и @thefredelement, но чтобы создать экземпляр представления с использованием идентификатора и нажать его, используя rootViewController как UINavigationController, как показано ниже.

let rootViewController = self.window?.rootViewController as! UINavigationController
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let mvc = storyboard.instantiateViewControllerWithIdentifier("MyViewController") as! 
             MyViewController
rootViewController.pushViewController(mvc, animated: true)

Это сработало для меня, и я не потерял правильные свойства навигации для приложения.

Ответ 5

дополнительная информация к предыдущим ответам.

В зависимости от вашего состояния вы можете изменить свою логику. Внутри метода didReceiveRemoteNotification:

func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject]) {}

вы можете сделать такой переключатель

let state = UIApplication.sharedApplication().applicationState switch state { case UIApplicationState.Active: case UIApplicationState.Inactive: case UIApplicationState.Background: }

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

Ответ 6

Быстрый ответ Кролика лучший.

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

Вы можете добавить в AppDelegate, внутри didFinishedLaunchingWithOptions:

if let notification = launchOptions?[.remoteNotification] as? [AnyHashable : Any] {

            notificationsUserInfo = notification as [AnyHashable : Any]
            serveNotifications = true

        }

Вы можете создать глобальную переменную или userdefault со значением уведомления и использовать флаг, чтобы остальная часть приложения обнаружила уведомление.

Как только mainViewController будет виден, вы можете выполнять действия для обработки уведомлений.

override func viewDidAppear(_ animated: Bool) {
        if serveNotifications {
      notificationManager.sharedInstance.processNotification(userInfo: notificationsUserInfo)

            serveNotifications = false

        }

    }

Позаботьтесь.