在 iOS 上无法从我的服务器获取 FCM 推送通知(在 Android 上工作)

Can't get FCM push notifications from my server on iOS (working on Android)

我是 iOS/Swift 的新手,无法使用推送通知。我已将我的服务器后端配置为在发生某些操作时将通知推送到我的应用程序。我已经通过 FCM 配置了数据通知,因为我需要通知中的一些自定义数据才能打开一个 activity/view 或另一个。这是用于发送通知的代码 (python/django):

registration_id = profiletarget.device_token
    message_title = "Ha llegado tu turno"
    message_body = "Entra y escribe en el relato para el que estás en cola"
    data_message = {
        "title" : "¿Listo para escribir?",
        "body" : "Ha llegado tu turno para escribir en el relato. Recuerda que tienes un minuto para aceptar tu turno y 3 para escribir.",
        "bookid" : booktarget.pk,
        "multimediaurl" : multimediaused.url
        }
    result = push_service.notify_single_device(registration_id=registration_id, data_message=data_message)

此代码中的所有内容均有效,因为我在 Android 上正确地获取了它们。但是在iOS...我无法让它工作。

我已经得到通知令牌,我已经 post 它到我的服务器,我已经使用 FCM 控制台上的通知发送器发送测试推送通知(iPhone 得到它们),但是不是我的自定义方法中的那些,它没有显示任何内容。服务器方法有什么问题还是我遗漏了什么?

这是swift代码:

import UIKit
import KeychainSwift
import Firebase
import FirebaseMessaging

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterDelegate, MessagingDelegate {

    var window : UIWindow?;
    var storyboard : UIStoryboard?;
    var token = ""
    let gcmMessageIDKey = "gcm.message_id"


    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        // Override point for customization after application launch.
        self.storyboard = UIStoryboard(name: "Main", bundle: Bundle.main);
        UITabBarItem.appearance().setTitleTextAttributes([NSAttributedString.Key.font: UIFont(name: "PT Sans", size: 12)!], for: .normal)
        UITabBarItem.appearance().setTitleTextAttributes([NSAttributedString.Key.font: UIFont(name: "PT sans", size: 12)!], for: .selected)
        let keychain = KeychainSwift()
        token = keychain.get("token") ?? ""
        if (token != ""){
            print("log-token: ", token)
            print("log-redirection: ", "no redirection needed!")
            FirebaseApp.configure()
            Messaging.messaging().delegate = self
            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)
            }

            application.registerForRemoteNotifications()

        } else {
            print("log-token: ", "noToken")
            print("log-redirection: ", "redirection to LoginController")
            window?.rootViewController = self.storyboard?.instantiateViewController(withIdentifier: "loginView");
        }
        return true
    }

    func application(
      _ application: UIApplication,
      didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data
    ) {
      let tokenParts = deviceToken.map { data in String(format: "%02.2hhx", data) }
      let token = tokenParts.joined()
      print("Device Token: \(token)")
        postNotificationToken(token: token)
    }

    func messaging(_ messaging: Messaging, didReceiveRegistrationToken fcmToken: String) {
      print("Firebase registration token: \(fcmToken)")

      let dataDict:[String: String] = ["token": fcmToken]
      NotificationCenter.default.post(name: Notification.Name("FCMToken"), object: nil, userInfo: dataDict)
      // TODO: If necessary send token to application server.
      // Note: This callback is fired at each app startup and whenever a new token is generated.
    }

    func postNotificationToken(token:String) {
        var request = URLRequest(url: URL(string: "https://myurl?myparam="+token)!)
        request.httpMethod = "GET"
        request.addValue("application/json", forHTTPHeaderField: "Content-Type")
        request.addValue("Bearer "+self.token, forHTTPHeaderField: "myauth")

        let session = URLSession.shared
        let task = session.dataTask(with: request, completionHandler: { data, response, error -> Void in
            let httpURLResponse = response as? HTTPURLResponse;
            if (httpURLResponse?.statusCode == 200){
                let string = String.init(data: data!, encoding: String.Encoding.utf8)
                print(string)
            } else {
                print(httpURLResponse?.statusCode)
            }
        })

        task.resume()
    }



    func messaging(_ messaging: Messaging, didReceive remoteMessage: MessagingRemoteMessage) {
        print("Received data message: \(remoteMessage.appData)")
    }

    @available(iOS 10.0, *)
    func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void)
    {
        completionHandler([.alert, .badge, .sound])
    }


    // MARK: UISceneSession Lifecycle


}

这是我的目标能力:

这是我的开发者帐户中 APN 通知的密钥:

使用 FCM 控制台,通知正常:

感谢阅读这么长post。任何事情都会有所帮助!

您是否为您的应用证书配置了推送通知?

此外,您还需要在 Xcode select 目标之一中配置项目,然后转到 -> 登录和功能添加每个目标的推送通知能力,推送在模拟器中不可见,但是方法didReceiveRemoteNotification 被触发,如果您收到它们,您可以使用一些日志或断点进行调试。

Try to send this type of custom formate with custom payload

note : this is node.js code

    let message = {
    tokens: iosTokens,
    notification: {
        title: "title",
        body: "",
    },data = {
    "title" : "¿Listo para escribir?",
    "body" : "Ha llegado tu turno para escribir en el relato. Recuerda que tienes un minuto para aceptar tu turno y 3 para escribir.",
    "bookid" : booktarget.pk
    },apns : {
        payload: {
            aps: {
                mutableContent: true,
                contentAvailable: true,
                category: "CustomSamplePush",
                alert: {
                    launchImage: "imageURL.jpeg",
                    sound: "default"
                }
            }

        }
    }
}; 

好的,我已经开始混合一些答案和在其他帖子上找到的一些代码。首先,我使用的是 APN 密钥,而不是 APN 证书。

其次,我正在检查 OS 有哪些用户需要我发送通知 (iOS/Android),以便我可以配置不同的通知结构。这是 python/django 中的通知系统,使用 PyFCM 库并发送 iOS 通知作为警报,正如我在此 post 上发现的:

if devicetype == "and":
        registration_id = profiletarget.device_token
        message_title = "default-title"
        message_body = "default-body"
        data_message = {
            "title" : "title",
            "body" : "body",
            "bookid" : booktarget.pk,
            "multimediaurl" : multimediaused.url
            }
        result = push_service.notify_single_device(registration_id=registration_id, data_message=data_message)
    else:
        registration_id = profiletarget.device_token
        message_title = "title"
        message_body = "body"
        data_message = {
            "bookid" : booktarget.pk,
            "multimediaurl" : multimediaused.url,
            }
        result = push_service.notify_single_device(registration_id=registration_id,
                                   message_title=message_title,
                                   message_body=message_body,
                                   data_message=data_message,
                                   extra_kwargs={"apns_push_type": "alert"}
                                   )

在 Xcode 中,我只需要添加推送通知和后台模式的广告功能 - 远程通知,如问题图片中所述。

在代码中,我错过了与此方法对应的 firebase 教程的某些部分:

func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any]) {
      // If you are receiving a notification message while your app is in the background,
      // this callback will not be fired till the user taps on the notification launching the application.
      // TODO: Handle data of notification

      // With swizzling disabled you must let Messaging know about the message, for Analytics
      // Messaging.messaging().appDidReceiveMessage(userInfo)

      // Print message ID.
      if let messageID = userInfo["body"] {
        print("Notif metod 1")
//        gotoWritting(bookid: messageID)
      }

      // Print full message.
      print("Notif metod 1")
    }

    func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any],
                     fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
      // If you are receiving a notification message while your app is in the background,
      // this callback will not be fired till the user taps on the notification launching the application.
      // TODO: Handle data of notification

      // With swizzling disabled you must let Messaging know about the message, for Analytics
      // Messaging.messaging().appDidReceiveMessage(userInfo)

      // Print message ID.
        if let messageID = userInfo["body"]{
        print("Notif metod 2")
//        gotoWritting(bookid: messageID)
      }

      // Print full message.
      print(userInfo["bookid"]!)
        gotoWritting(bookid: Int(userInfo["bookid"]! as! String) ?? 90)
      completionHandler(UIBackgroundFetchResult.newData)
    }

第二个是由通知点击(背景、前景和应用程序关闭...)触发的,点击后,我可以使用一些通知参数重定向用户。

我无法在以前的版本上测试,但希望它能在 iOS 9 到(如果你知道它是否有效,请告诉我)。

感谢所有帮助过的人!