Swift:当应用程序在后台运行时,无法使用 pushNotification 的信息刷新 rootViewController

Posted

技术标签:

【中文标题】Swift:当应用程序在后台运行时,无法使用 pushNotification 的信息刷新 rootViewController【英文标题】:Swift: Unable to refresh rootViewController with pushNotification's info when the application is running in the background 【发布时间】:2016-07-11 22:13:52 【问题描述】:

我正在实施一个新闻应用程序。一旦我收到带有突发新闻 id 和消息的通知,我应该打开应用程序并使用推送通知中收到的 id 刷新 rootViewController。

当应用程序不在后台运行时一切正常,而当应用程序在后台运行时出现问题。

在 AppDelegate.swift 中,我将 didReceiveRemoteNotifications 设置如下

func application(application: UIApplication,  didReceiveRemoteNotification userInfo: [NSObject : AnyObject],  fetchCompletionHandler completionHandler: (UIBackgroundFetchResult) -> Void) 
        strNotificationId = (userInfo["id"] as? String)!

在我的 applicationWillEnterForeground 中,我调用了 rootViewController 方法 activeController.request(),该方法使用收到的 id 重新加载页面,如下所示

func applicationWillEnterForeground(application: UIApplication) 
        print("Push notifications are not supported in the ios Simulator.")

        if let navigationController = window?.rootViewController as?UINavigationController 
            navigationController.popToRootViewControllerAnimated(false)
                
        let navigationController = window?.rootViewController as? UINavigationController
        let activeController = navigationController!.visibleViewController as! FeedTableViewController

        activeController.request("http://example.net/rsssite.xml")

我的 rootViewController 实现了 request("http://example.net/rsssite.xml") 方法。请求方法读取通知id如下所示

delegate.notificationId = [NSObject: AnyObject]()
notificationId = delegate.strNotificationId as String

我的问题是,每当我单击在 IOS 通知列表中收到的通知时,并且当应用程序恰好在后端运行时,在 rootViewController 中实现的请求(“http://example.net/rsssite.xml”)都不是在我的 rootViewController viewDidLoad 和 applicationWillEnterForeground 中触发

以下是我的 rootViewController 中 request(url) 方法的完整代码,可能对您的反馈无用

//Method to request and parser the rss feeds
        func request(urlLink: String)


            forceError = false
            let alert = UIAlertController(title: nil, message: Util.getMessage("loading"), preferredStyle: .Alert)
            alert.view.tintColor = UIColor.blackColor()
            let loadingIndicator: UIActivityIndicatorView = UIActivityIndicatorView(frame: CGRectMake(10, 5, 50, 50)) as UIActivityIndicatorView

            loadingIndicator.hidesWhenStopped = true
            loadingIndicator.activityIndicatorViewStyle = UIActivityIndicatorViewStyle.Gray
            loadingIndicator.startAnimating();


            alert.view.addSubview(loadingIndicator)
            self.view.addSubview(alert.view)
            self.view.bringSubviewToFront(loadingIndicator)

            let viewsDictionary = ["alert":alert.view]
            let loadingMetrics = ["xDimension":(self.view.bounds.size.width - alert.view.frame.width ) / 2, "yDimension": (self.view.bounds.size.height - alert.view.frame.height ) / 2]

            let horizontalLoadingConstraint = NSLayoutConstraint.constraintsWithVisualFormat("H:|-50-[alert]", options: NSLayoutFormatOptions.AlignAllCenterX, metrics:loadingMetrics, views: viewsDictionary)
            let verticalLoadingConstraint = NSLayoutConstraint.constraintsWithVisualFormat("V:|-100-[alert]", options: NSLayoutFormatOptions.AlignAllCenterX, metrics: loadingMetrics, views: viewsDictionary)

            self.view.addConstraints(horizontalLoadingConstraint)
            self.view.addConstraints(verticalLoadingConstraint)
            presentViewController(alert, animated: true, completion: nil)


            let delegate = UIApplication.sharedApplication().delegate as! AppDelegate

            let notificationsData = delegate.notificationId
            for aButton in notificationsData 
                let key = aButton.0
                let value = aButton.1
                if(key == "id")
                    notificationId = value as! String
                
            

            delegate.notificationId = [NSObject: AnyObject]()
            notificationId = delegate.strNotificationId as String
            //notificationId = "17579"
            if (notificationId != "" && self.directLoad==false) 
                //var notificationURLLink = defaults.stringForKey("notificationId")
                let diceRoll = Int(arc4random_uniform(9999) + 1) as NSNumber
                let notificationURLLink = "http://example.net/"+notificationId+"-rss.xml?_=" + diceRoll.stringValue
                let queue = NSOperationQueue()
                queue.addOperationWithBlock() 
                    let url = NSURL(string: notificationURLLink)
                    let feedParser = MWFeedParser(feedURL: url)
                    feedParser.delegate = self

                    feedParser.parse()
                    NSOperationQueue.mainQueue().addOperationWithBlock() 
                        let item = self.feedItems[0] as MWFeedItem
                        self.slectedItems = item
                        self.sideBar.showSidebar(false)
                        self.performSegueWithIdentifier("DetailsViewControllerSegue", sender: self)
                        self.dismissViewControllerAnimated(false, completion: nil)
                        self.notificationId = ""
                        self.directLoad = true
                    
                
            else
                let queue = NSOperationQueue()
                queue.addOperationWithBlock() 
                    let url = NSURL(string: urlLink)
                    let feedParser = MWFeedParser(feedURL: url)
                    feedParser.delegate = self
                    feedParser.parse()

                    NSOperationQueue.mainQueue().addOperationWithBlock() 
                        self.tableView.reloadData()
                        self.dismissViewControllerAnimated(false, completion: nil)
                    
                
            
            delegate.strNotificationId = ""
        

谢谢

【问题讨论】:

【参考方案1】:

尝试将applicationWillEnterForeground 中的代码移动到didReceiveRemoteNotification。该过程应在您收到通知后立即完成。

func application(application: UIApplication,  didReceiveRemoteNotification userInfo: [NSObject : AnyObject],  fetchCompletionHandler completionHandler: (UIBackgroundFetchResult) -> Void) 
    strNotificationId = (userInfo["id"] as? String)!
    print("Push notifications are not supported in the iOS Simulator.")

    if let navigationController = window?.rootViewController as?UINavigationController 
        navigationController.popToRootViewControllerAnimated(false)
            
    let navigationController = window?.rootViewController as? UINavigationController
    let activeController = navigationController!.visibleViewController as! FeedTableViewController

    activeController.request("http://example.net/rsssite.xml")

另外请检查当您在后台打开通知时首先执行哪个功能,applicationWillEnterForegrounddidReceiveRemoteNotification

【讨论】:

以上是关于Swift:当应用程序在后台运行时,无法使用 pushNotification 的信息刷新 rootViewController的主要内容,如果未能解决你的问题,请参考以下文章

即使应用程序在后台运行,如何使用 swift 在 ios 中获取位置更新

我无法在 iOS 的后台获取数据

Swift:当应用程序进入后台时启动另一个计时器

应用程序进入后台时如何保持 Swift Socket IO 运行?

应用程序在后台运行时发送本地通知 Swift 2.0

当应用程序进入后台时,应用程序在前台使用带有 GPU 的 CoreML 无法切换到 CPU