为 FCM 检索令牌的正确方法 - iOS 10 Swift 3
Posted
技术标签:
【中文标题】为 FCM 检索令牌的正确方法 - iOS 10 Swift 3【英文标题】:Correct way to retrieve token for FCM - iOS 10 Swift 3 【发布时间】:2017-02-22 03:36:44 【问题描述】:我已经使用 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"]
我也尝试过第二种方法,在运行应用程序时出现致命错误,如下所示:-
如果有人能指出正确的方法,不胜感激,谢谢!
【问题讨论】:
看到这个对你有帮助***.com/questions/37667753/… 注意:didRegisterForRemoteNotificationWithDeviceToken 中的 deviceToken 参数不是 Firebase 注册令牌。您仍然需要调用 return InstanceID.instanceID().token() ,如下所述。 【参考方案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 控制台对其进行测试。
100% 工作、简单且经过测试
注意:
从 xcode 的功能部分启用推送通知。
检查您在 firebase 项目设置上上传的两个 p12 证书。
设备令牌只能从真实设备而不是模拟器获取。
【讨论】:
【参考方案2】:这个问题很老,但如果有人想在 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);
];
【讨论】:
【参考方案3】:确认 MessagingDelegate 协议。
然后您可以添加以下委托方法并获取 Firebase 令牌。 (文档https://firebase.google.com/docs/cloud-messaging/ios/client)
func messaging(_ messaging: Messaging, didReceiveRegistrationToken fcmToken: String)
// send to remote server
InstanceID.instanceID().instanceID result, error in
if let error = error
print("Error fetching remote instance ID: \(error)")
else if let result = result
print("Remote instance ID token: \(result.token)")
【讨论】:
【参考方案4】:首先,你应该导入所有需要的库
import Firebase
import UserNotifications
稍后在 AppDelegate.swift 中调用下一个函数
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data)
Messaging.messaging().apnsToken = deviceToken
InstanceID.instanceID().instanceID (result, error) in
if let error = error
print("Error fetching remote instance ID: \(error)")
else if let result = result
print("Remote instance ID token: \(result.token)")
【讨论】:
【参考方案5】: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)
【讨论】:
嗨,如何发布请求令牌? 如果有人做了我所做的,deviceToken:Data 参数不是 FCM 注册令牌。来自 InstanceID().token() 的令牌是。 我得到 'token()' 已被弃用:使用 instanceIDWithHandler: 代替。对于令牌() 我这样做了:InstanceID.instanceID().instanceID (result, error) in if error == nil print("InstanceID token: (result)") else print(error , ": 获取 Fire 令牌时出错") this 怎么样?注册令牌通过messaging:didReceiveRegistrationToken:
方法传递。此方法通常在每个应用程序以注册令牌开始时调用一次。【参考方案6】:
我遇到了同样的问题,但不知道发生了什么。
@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 令牌更改通知的方法是按照文档中的建议收听名为 kFIRMessagingRegistrationTokenRefreshNotification
的 NSNotification
:https://firebase.google.com/docs/cloud-messaging/ios/client
【讨论】:
【参考方案7】:获取当前的 FCM Token
if let token = Messaging.messaging().fcmToken
// token is current fcmToken
更新当前的 FCM 令牌
如果我们删除当前的instanceId,稍后将通过vi MessagingDelegate (messaging:didReceiveRegistrationToken) 接收到新的token。
InstanceID.instanceID().deleteID (error) in
if let er = error
print(er.localizedDescription)
else
print("instanceID().deleteID success ---------------➤")
【讨论】:
【参考方案8】:Firebase 推荐的方式:
let token = Messaging.messaging().fcmToken
参考:Setting Up a Firebase Cloud Messaging Client App on iOS
【讨论】:
【参考方案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)")
)
【讨论】:
【参考方案10】:斯威夫特 4
礼貌:https://***.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)")
【讨论】:
我在主屏幕 viewdidload 中调用时得到“静态成员 'instanceID' 不能使用”,你能帮忙吗? @kemdo 确保你用括号写InstanceID.instanceID().instanceID
而不是 InstanceID.instanceID.instanceID
@kemdo,Yocoh,当我遇到静态成员 'instanceID...... 问题时,你是如何解决这个问题的?【参考方案11】:
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)"
【讨论】:
这是做什么的?你能解释一下吗?【参考方案12】:首先注册firebase令牌刷新通知:
NotificationCenter.default.addObserver(self, selector:
#selector(tokenRefreshNotification), name:
NSNotification.Name.InstanceIDTokenRefresh, object: nil)
然后就可以在tokenRefreshNotification选择器中接收token了:
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()
【讨论】:
请注意,InstanceIDTokenRefresh
和 FIRInstanceID
现在已弃用。【参考方案13】:
Swift 3 + Firebase 4.0.4:
static var FirebaseToken : String?
return InstanceID.instanceID().token()
【讨论】:
只是为了澄清;你的和下面的答案(Messaging.messaging().fcmToken
)有什么区别? @MBH
***.com/questions/44615817/…【参考方案14】:
FCM 设备令牌 swift3
let fcmDeviceToken = FIRInstanceID.instanceID().token()
print("FCM token: \(fcmDeviceToken ?? "")")
【讨论】:
【参考方案15】:使用第二个选项,这看起来真的很愚蠢/简单,但要修复那个 nil 可选的致命错误,只需删除最后的 force-unwrap
您的代码:var token = FIRInstanceID.instanceID().token()!
成功:var token = FIRInstanceID.instanceID().token()
这至少可以解决令人讨厌的崩溃
【讨论】:
嗨约翰,错误仍然存在,似乎 FIRInstanceID.instanceID().token() 返回 nil。 @aznelite89,之所以为nil,是因为你还没有注册Firebase Cloud Messaging以上是关于为 FCM 检索令牌的正确方法 - iOS 10 Swift 3的主要内容,如果未能解决你的问题,请参考以下文章
FCM/APNS 集成适用于新令牌,但在转换旧 APNS 令牌时不行?