应用程序未运行时的远程推送通知崩溃

Posted

技术标签:

【中文标题】应用程序未运行时的远程推送通知崩溃【英文标题】:Remote Push Notification when App is not running crashes 【发布时间】:2017-02-26 11:19:04 【问题描述】:

如果我发送远程推送通知,一切在后台/前台运行良好。但是如果我杀死我的应用并想要处理推送通知,应用会在几毫秒后启动并崩溃。

这是我的didFinishLaunchingWithOptions 函数:

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool 
        // Override point for customization after application launch.
        UNUserNotificationCenter.current().requestAuthorization(options:
            [[.alert, .sound, .badge]],
            completionHandler:  (granted, error) in
            // Handle Error
        )
        application.registerForRemoteNotifications()

        if let options: NSDictionary = launchOptions as NSDictionary? 
            let remoteNotification =
                options[UIApplicationLaunchOptionsKey.remoteNotification]

            if let notification = remoteNotification 
                self.application(application, didReceiveRemoteNotification:
                    notification as! [AnyHashable : Any],
                                 fetchCompletionHandler:   (result) in
                )

            
        

        return true

还有我的didReceiveRemoteNotification 函数

func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) 

        let tabBar: UITabBarController = self.window?.rootViewController as! UITabBarController
        let navController: UINavigationController = tabBar.viewControllers![1] as! UINavigationController
        let viewController = navController.viewControllers[0] as! CompanyProfileTableViewController
        //let viewController = tabBar.viewControllers![1] as! CompanyProfileTableViewController

        let notification: CKNotification = CKNotification(fromRemoteNotificationDictionary:
                userInfo as! [String : NSObject])

        print("\(notification)")

        if (notification.subscriptionID == "company-changed") 
            let queryNotification =
                notification as! CKQueryNotification
            print("\(queryNotification)")

            let recordID = queryNotification.recordID

            viewController.fetchRecord(recordID!)
        

    

我处理这个问题的时间已经够多了,但找不到合适的解决方案。我也查了

Handling Push Notifications when App is NOT running

如果我重新启动应用程序,则会对标签进行由 rPN 引起的更改。由于我必须终止应用程序,因此在将 rPN 发送到终止的应用程序时,我无法在 Xcode 中调试代码。

这里是获取记录和更新标签的函数

//Fetch records from DB
func fetchRecord(_ recordID: CKRecordID) -> Void 
    let privateDatabase = CKContainer.default().privateCloudDatabase
    var recordIDArray: [CKRecordID] = []
    recordIDArray.append(recordID)

    let fetchRecordsWithID = CKFetchRecordsOperation(recordIDs: recordIDArray)
    fetchRecordsWithID.fetchRecordsCompletionBlock =  (records, error) in
        if error != nil 
            print("Error")
         else 
            DispatchQueue.main.async() 
                self.currentRecord = records?[recordID]

                let data = NSKeyedArchiver.archivedData(withRootObject: self.currentRecord ?? "none")
                UserDefaults.standard.set(data, forKey: "companyRecord")
                UserDefaults.standard.synchronize()

                if let retrivedData = UserDefaults.standard.object(forKey: "companyRecord") 
                    let companyRecord = NSKeyedUnarchiver.unarchiveObject(with: retrivedData as! Data) as! CKRecord
                    self.companyNameLabel.text = companyRecord["companyName"] as? String
                    self.companyStreetLabel.text = companyRecord["companyStreet"] as? String
                    self.companyZipCodeLabel.text = companyRecord["companyZipCode"] as? String
                

            
        
    
    privateDatabase.add(fetchRecordsWithID)        

跟踪堆栈:

Trace Stack

我猜问题出在获取记录功能上。

错误:

; partial apply forwarder for Swift.(_fatalErrorMessage (Swift.StaticString, Swift.StaticString, Swift.StaticString, Swift.UInt, flags : Swift.UInt32) -> Swift.Never).(closure #2)
    0x1003d11e4 <+96>:  nop    
    0x1003d11e8 <+100>: mov    x0, x25
    0x1003d11ec <+104>: mov    x1, x24
    0x1003d11f0 <+108>: mov    x2, x23
    0x1003d11f4 <+112>: mov    x4, x8
    0x1003d11f8 <+116>: bl     0x1002c4b80               ; function signature specialization <preserving fragile attribute, Arg[1] = [Closure Propagated : reabstraction thunk helper from @callee_owned (@unowned Swift.UnsafeBufferPointer<Swift.UInt8>) -> () to @callee_owned (@unowned Swift.UnsafeBufferPointer<Swift.UInt8>) -> (@out ()), Argument Types : [@callee_owned (@unowned Swift.UnsafeBufferPointer<Swift.UInt8>) -> ()]> of generic specialization <preserving fragile attribute, ()> of Swift.StaticString.withUTF8Buffer <A> ((Swift.UnsafeBufferPointer<Swift.UInt8>) -> A) -> A
->  0x1003d11fc <+120>: brk    #0x1

【问题讨论】:

您能告诉我们应用程序崩溃时您的堆栈跟踪是什么吗? @carmine 堆栈跟踪是什么意思? ***.com/a/26341275/1622430 及以下.. @carmine 用跟踪堆栈(图像)和导致错误的函数更新了我的帖子。 @carmine 非常感谢您的帮助,您的问题让我朝着正确的方向前进 ;)。我发布了解决方案作为答案。 【参考方案1】:

我终于找到了解决办法。问题是我的 fetchRecord 函数。使用“已终止”应用执行 rPN 时,标签未初始化。

所以有两种方法可以解决这个问题:

第一个:

修改didReceiveRemoteNotification方法:

if (notification.subscriptionID == "company-changed") 
            let queryNotification =
                notification as! CKQueryNotification
            print("\(queryNotification)")

            let recordID = queryNotification.recordID
            tabBar.selectedIndex = 1
            viewController.fetchRecord(recordID!)

我添加了这个 ->

tabBar.selectedIndex = 1

这将显示 viewController 并且标签已初始化。

另一种解决方案是将我设置带有新值的标签的部分放入 viewWillAppear 或 viewDidLoad。

【讨论】:

以上是关于应用程序未运行时的远程推送通知崩溃的主要内容,如果未能解决你的问题,请参考以下文章

MFP 应用程序在应用程序未运行时在推送通知期间点击时崩溃

应用程序未运行时的 Windows Phone 7 推送通知

推送通知导致应用程序崩溃

WatchOS 3 在收到推送通知时崩溃

远程推送通知

应用程序在后台时的远程推送通知 swift 3