正确检索FCM令牌的方法 - iOS 10 Swift 3

时间:2016-10-13 06:28:03

标签: ios swift firebase firebase-cloud-messaging

我使用FirebaseAuth / FCM等实施了Firebase,并通过Firebase控制台成功发送了通知。

但是我需要从我自己的应用服务器推送通知。

我想知道下面哪种方法是检索设备注册ID的正确方法: -

1)从didRegisterForRemoteNotificationWithDeviceToken检索注册ID令牌

func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
    var token = ""

    for i in 0..<deviceToken.count {
        token += String(format: "%02.2hhx", arguments: [deviceToken[i]])
    }

    print("Registration succeeded!")
    print("Token: ", token)
    Callquery(token)

}

2)从firebase检索注册令牌(基于检索当前注册令牌的Firebase文档)

let token = FIRInstanceID.instanceID().token()!

我正在使用第一种方式,即使注册ID相应地存储在我的应用服务器数据库上也没有收到推送通知,我得到了这个CURL会话结果: -

{"multicast_id":6074293608087656831,"success":0,"failure":1,"canonical_ids":0,"results":[{"error":"InvalidRegistration"}]}

我还尝试了第二种方式,并在运行应用程序时遇到致命错误,如下所示: - enter image description here

感谢任何人都能指出正确的方式,谢谢!

13 个答案:

答案 0 :(得分:49)

启动应用时,并不总是会调用tokenRefreshNotification函数。

但是,当将代码放在常规didRegisterForRemoteNotificationsWithDeviceToken委托函数中时,我每次都可以获取令牌:

func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
    if let refreshedToken = InstanceID.instanceID().token() {
        print("InstanceID token: \(refreshedToken)")
    }
}

(Swift 3 + Firebase 4.0.4)

答案 1 :(得分:23)

Swift 3 + Firebase 4.0.4:

static var FirebaseToken : String? {
    return InstanceID.instanceID().token()
}

答案 2 :(得分:19)

Firebase推荐的方式:

Context context;

OcrDetectorProcessor(GraphicOverlay<OcrGraphic> ocrGraphicOverlay, Context context) {
    mGraphicOverlay = ocrGraphicOverlay;
    this.context = context;
}

@Override
public void receiveDetections(Detector.Detections<TextBlock> detections) {
    mGraphicOverlay.clear();
    final String result;
    String detectedText = "";
    SparseArray<TextBlock> items = detections.getDetectedItems();
    for (int i = 0; i < items.size(); ++i) {

        final TextBlock item = items.valueAt(i);
        OcrGraphic graphic = new OcrGraphic(mGraphicOverlay, item);
        mGraphicOverlay.add(graphic);
        detectedText += item.getValue();
    }
    result = detectedText;
    ((OcrCaptureActivity)context).runOnUiThread(new Runnable() {
        @Override
        public void run() {
            Toast.makeText(context, result, Toast.LENGTH_SHORT).show();
        }
    });
}

参考:Setting Up a Firebase Cloud Messaging Client App on iOS

答案 3 :(得分:9)

Swift 4 + Firebase(5.3.0)

func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
    InstanceID.instanceID().instanceID(handler: { (result, error) in
        if let error = error {
            print("Error fetching remote instange ID: \(error)")
        } else if let result = result {
            print("Remote instance ID token: \(result.token)")
        }
    })
}

答案 4 :(得分:7)

快捷键4

https://stackoverflow.com/a/50945350/1014164

提供
InstanceID.instanceID().instanceID { (result, error) in
    if let error = error {
        print("Error fetching remote instange ID: \(error)")
    } else if let result = result {
        print("Remote instance ID token: \(result.token)")
    }
}

答案 5 :(得分:6)

FCM设备令牌swift3

    let fcmDeviceToken = FIRInstanceID.instanceID().token()
    print("FCM token: \(fcmDeviceToken ?? "")")

答案 6 :(得分:5)

使用第二个选项,这看起来真的很愚蠢/简单,但要修复那个nil可选的致命错误,只需删除最后的force-unwrap

您的代码:
var token = FIRInstanceID.instanceID().token()!
成功:
var token = FIRInstanceID.instanceID().token()

这至少可以解决这个令人讨厌的崩溃

答案 7 :(得分:5)

首先注册firebase令牌刷新通知:

NotificationCenter.default.addObserver(self, selector: 
     #selector(tokenRefreshNotification), name:     
     NSNotification.Name.InstanceIDTokenRefresh, object: nil)

然后您可以在tokenRefreshNotification选择器中接收令牌:

func tokenRefreshNotification(_ notification: Notification) {
    if let refreshedToken = FIRInstanceID.instanceID().token() {
      print("InstanceID token: \(refreshedToken)")
    }

    // Connect to FCM since connection may have failed when attempted before having a token.
    connectToFcm()
}

答案 8 :(得分:2)

我遇到了同样的问题,但无法弄清楚到底是怎么回事。

@Sam建议的didRegisterForRemoteNotificationsWithDeviceToken每次都(几乎)被调用,因此这是一个很好的解决方法。但是,第一次使用刷新的令牌打开应用程序时不会调用它。

因此,在这种情况下,您仍然需要:

func messaging(_ messaging: Messaging, didRefreshRegistrationToken fcmToken: String) {
    print("Refreshed Token: \(fcmToken)")
}

因此,如果您仅使用:

func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
    if let fcmToken = InstanceID.instanceID().token() {
        print("InstanceID token: \(fcmToken)")
    }
}

您将仅在用户第二次打开应用程序时获得“刷新令牌”。

我设法通过卸载应用程序并清理构建文件夹(产品>清洁构建文件夹)来强制刷新令牌。很适合测试。

理想情况下,它们都可以在messaging:didReceiveRegistrationToken委托方法下进行处理,但是我无法使其工作。通知FCM令牌更改的另一种方法是,按照文档https://firebase.google.com/docs/cloud-messaging/ios/client

中的建议,收听名为NSNotification的{​​{1}}

答案 9 :(得分:1)

首先导入像:

这样的库
import FirebaseInstanceID
import FirebaseMessaging
import UserNotifications

设置代理: MessagingDelegate,UNUserNotificationCenterDelegate

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

在didFinishLaunching()上编写此代码:

 func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {

    // Override point for customization after application launch.
    FirebaseApp.configure()
    Messaging.messaging().delegate = self

    //remote Notifications
    if #available(iOS 10.0, *) {
        UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound, .badge]) { (isGranted, err) in
            if err != nil {
                //Something bad happend
            } else {
                UNUserNotificationCenter.current().delegate = self
                Messaging.messaging().delegate = self

                DispatchQueue.main.async {
                    UIApplication.shared.registerForRemoteNotifications()
                }
            }
        }
    } else {
        // Fallback on earlier versions
    }

    if #available(iOS 10, *) {
        UNUserNotificationCenter.current().requestAuthorization(options: [.badge,.sound,.alert], completionHandler: { (granted, error) in
            application.registerForRemoteNotifications()
        })
    }else{
        let notificationSettings = UIUserNotificationSettings(types: [.badge,.sound,.alert], categories: nil)
        UIApplication.shared.registerUserNotificationSettings(notificationSettings)
        UIApplication.shared.registerForRemoteNotifications()
    }

    return true
}

以这种方式编写connectFCM方法:

func ConnectToFCM() {
    Messaging.messaging().shouldEstablishDirectChannel = true

    if let token = InstanceID.instanceID().token() {
        print("\n\n\n\n\n\n\n\n\n\n ====== TOKEN DCS: " + token)
    }

还要编写用于注册和接收推送通知的委托方法:

func messaging(_ messaging: Messaging, didRefreshRegistrationToken fcmToken: String) {
    print("\n\n\n\n\n ==== FCM Token:  ",fcmToken)
    HelperFunction.helper.storeInUserDefaultForKey(name: kFCMToken, val: fcmToken)
    ConnectToFCM()
}

@available(iOS 10.0, *)
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {

   // UIApplication.shared.applicationIconBadgeNumber += 1

    NotificationCenter.default.post(name: NSNotification.Name(rawValue: "Barker"), object: nil)
}

func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any]) {

    print(userInfo)
}

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

    print(userInfo)

    completionHandler(UIBackgroundFetchResult.newData)
}

}

现在我们可以从firebase控制台测试它。 enter image description here

100%正常,轻松且经过测试

注意: 1)从xcode的功能部分启用推送通知。

2)检查在firebase项目设置上上传的两个p12证书的两倍。

3)设备令牌只能从真实设备而不是模拟器获取。

答案 10 :(得分:1)

获取当前的FCM令牌

if let token = Messaging.messaging().fcmToken {
    // token is current fcmToken
}

续订当前的FCM令牌

如果我们删除当前的instanceId,稍后将通过MessagingDelegate(messaging:didReceiveRegistrationToken)接收新令牌。

InstanceID.instanceID().deleteID { (error) in
    if let er = error {
        print(er.localizedDescription)
    } else {
        print("instanceID().deleteID  success ---------------➤")
    }
}

答案 11 :(得分:0)

这个问题很旧,但是如果有人想在Objective C中使用它,还是可以的。

最新Firebase:6.27.0

在iOS Objective C中,我们可以这样使用

[[FIRInstanceID instanceID] instanceIDWithHandler:^(FIRInstanceIDResult * _Nullable result,
                                                            NSError * _Nullable error) {
            if (error != nil) {
                NSLog(@"Error : %@", error);
            } else {
                token = result.token;
            }
            NSLog(@"Token %@", result.token);
           
        }];

并获取实例ID:

 [[FIRInstanceID instanceID] getIDWithHandler:^(NSString *identity, NSError *error) {
         if (error != nil) {
           NSLog(@"Error : %@", error);
         } else {
           NSLog(@"instance ID: %@", identity);
         }
         NSLog(@"IID %@", identity);
       }];

答案 12 :(得分:-4)

func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {        
    Messaging.messaging().apnsToken = deviceToken

    let deviceTokenString = deviceToken.reduce("") { $0 + String(format: "%02X", $1) }

    print("APNs device token: \(deviceTokenString)"
}