-->

AppDelegate Never Gets Its didReceiveRemoteNotific

2019-08-18 04:35发布

问题:

I'm trying to let the iOS app listen to CKQuerySubscription changes. Data is transmitted by a remote iOS app. I already have a macOS application, which does receive data sent by the remote iOS app. The iOS app I have trouble with already has a subscription. Yet, its AppDelegate never receives a call in the didReceiveRemoteNotification method.

import UIKit
import UserNotifications
import CloudKit

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterDelegate {
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
        /* notifications */
        let center  = UNUserNotificationCenter.current()
        center.delegate = self
        UNUserNotificationCenter.current().getNotificationSettings { (settings) in
            switch settings.authorizationStatus {
            case .authorized:
                print("You already have permission")
                DispatchQueue.main.async() {
                    application.registerForRemoteNotifications()
                }
            case .denied:
                print("setting has been disabled")
            case .notDetermined:
                print("Let me ask")
                UNUserNotificationCenter.current().requestAuthorization(options: []) { (granted, error) in
                    if error == nil {
                        if granted {
                            print("you are granted permission")
                            DispatchQueue.main.async() {
                                application.registerForRemoteNotifications()
                            }
                        }
                    }
                }
            }
        }
        return true
    }
}

    func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) {
        print("Failed to register notifications_ error:", error)
    }

    func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
        print("Receiving data...") // never called...
    }
}

I have some capabilities on as shown below. I don't know if the app needs push notifications. For now, it's turned on.

So why doesn't my iOS app get the remote notification call? I'm using the app with an actual device, not a simulator. Thanks.

EDIT: Creating a subscription to a record change

class HomeViewController: UIViewController {
    override func viewDidLoad() {
        registerSubscription()
    }

    func registerSubscription() {
        let cloudContainer = CKContainer(identifier: "iCloud.com.xxx.XXXXX")
        let privateDB = cloudContainer.privateCloudDatabase
        let predicate = NSPredicate(format: "TRUEPREDICATE")
        let subscription = CKQuerySubscription(recordType: "PrivateRecords", predicate: predicate, options: .firesOnRecordCreation)
        let notification = CKNotificationInfo()
        subscription.notificationInfo = notification
        privateDB.save(subscription, completionHandler: ({returnRecord, error in
            if let err = error {
                print("Subscription has failed: \(err.localizedDescription)")
            } else {
                print("Subscription set up successfully")
                print("Subscription ID: \(subscription.subscriptionID)")
            }
        }))
    }
}

回答1:

There are a few more things you can check.

First, make sure you implement didReceiveRemoteNotification in your app delegate:

func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any]) {  
  let dict = userInfo as! [String: NSObject]
  let notification = CKNotification(fromRemoteNotificationDictionary: dict)

  if let sub = notification.subscriptionID{
    print("iOS Notification Received: \(sub)")
  }
}

There are also a few other things you can check:

  1. Try deleting your CKQuerySubscription in the CloudKit dashboard, then run your iOS code again that registers it. Does the subscription show up in the dashboard?
  2. Does the CloudKit log show that a notification was sent? It lists all notifications that were pushed to a device.
  3. If you are using silent push notifications, try enabling Background fetch in the Background Modes capability (right above Remote notifications).

If you do all that and it still doesn't work, can you share your CKQuerySubscription code?

-- Update --

Try setting some additional attributes on your CKNotificationInfo object. There are some obscure bugs with notifications that can usually be circumvented by setting a couple properties like this:

notification.shouldSendContentAvailable = true
notification.alertBody = "" //(Yes, a blank value. It affects the priority of the notification delivery)

You can also try setting your predicate to: NSPredicate(value: true)

Also, what does your privateDB.save method return? Does it say it succeeds or fails?