iOS 的 GCM,从不调用 gcm 连接处理程序
GCM for iOS, gcm connection handler is never called
我正在我的应用程序中实施 Google 云消息传递。我遵循了 google 文档中给出的 tutorial。我可以使用 HTTP POST 请求向我的设备发送通知,但问题是在 applicationDidBecomeActive 中,如 google 所示,我尝试连接 gcmService 但 connectionHandler 块永远不会叫.
我的 AppDelegate 中的 applicationDidBecomeActive 函数
func applicationDidBecomeActive(application: UIApplication) {
GCMService.sharedInstance().connectWithHandler({
(NSError error) -> Void in
if error != nil {
print("Could not connect to GCM: \(error.localizedDescription)")
} else {
self.connectedToGCM = true
print("Connected to GCM")
self.subscribeToTopic()
}
})
}
有人解决过这个问题吗?
编辑 - 这是正确的方法
这是我的完整 AppDelegate.swift 文件
//
// AppDelegate.swift
//
import UIKit
import CoreData
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate, GGLInstanceIDDelegate, GCMReceiverDelegate {
var window: UIWindow?
var connectedToGCM = false
var gcmSenderID: String?
var gcmRegistrationToken: String?
var gcmRegistrationOptions = [String: AnyObject]()
let gcmRegistrationKey = "onRegistrationCompleted"
var subscribedToTopic = false
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
print("bundleId=\(NSBundle.mainBundle().bundleIdentifier)")
// Configure Google Analytics
// Configure tracker from GoogleService-Info.plist.
var configureError:NSError?
GGLContext.sharedInstance().configureWithError(&configureError)
assert(configureError == nil, "Error configuring Google services: \(configureError)")
// Optional: configure GAI options.
let gai = GAI.sharedInstance()
gai.trackUncaughtExceptions = true // report uncaught exceptions
gai.logger.logLevel = GAILogLevel.Verbose // remove before app release
// Override point for customization after application launch.
application.registerUserNotificationSettings(UIUserNotificationSettings(forTypes: [.Alert, .Badge, .Sound], categories: nil)) // types are UIUserNotificationType members
// Register for remotes notifications
UIApplication.sharedApplication().registerForRemoteNotifications()
// Get the gcm sender id
gcmSenderID = GGLContext.sharedInstance().configuration.gcmSenderID
var gcmConfig = GCMConfig.defaultConfig()
gcmConfig.receiverDelegate = self
GCMService.sharedInstance().startWithConfig(gcmConfig)
return true
}
func applicationWillResignActive(application: UIApplication) {
// Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
// Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
}
func applicationDidEnterBackground(application: UIApplication) {
// Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
// If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
GCMService.sharedInstance().disconnect()
connectedToGCM = false
}
func applicationWillEnterForeground(application: UIApplication) {
// Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
}
func applicationDidBecomeActive(application: UIApplication) {
// Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
// -->The app go through this point
// Connect to the GCM server to receive non-APNS notifications
GCMService.sharedInstance().connectWithHandler(gcmConnectionHandler)
// -->The app go through this point
}
func gcmConnectionHandler(error: NSError?) {
// -->The app never enter in this function
if let error = error {
print("Could not connect to GCM: \(error.localizedDescription)")
} else {
self.connectedToGCM = true
print("Connected to GCM")
// ...
}
}
func applicationWillTerminate(application: UIApplication) {
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
self.saveContext()
}
func application(application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: NSData) {
// Create a config and set a delegate that implements the GGLInstaceIDDelegate protocol.
let instanceIDConfig = GGLInstanceIDConfig.defaultConfig()
instanceIDConfig.delegate = self
// Start the GGLInstanceID shared instance with that config and request a registration
// token to enable reception of notifications
GGLInstanceID.sharedInstance().startWithConfig(instanceIDConfig)
gcmRegistrationOptions = [kGGLInstanceIDRegisterAPNSOption:deviceToken,
kGGLInstanceIDAPNSServerTypeSandboxOption:true]
GGLInstanceID.sharedInstance().tokenWithAuthorizedEntity(gcmSenderID,
scope: kGGLInstanceIDScopeGCM, options: gcmRegistrationOptions, handler: gcmRegistrationHandler)
}
func application(application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: NSError) {
print("-- Failed to get deviceToken: \(error.localizedDescription)")
}
func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject]) {
application.applicationIconBadgeNumber += 1
print(userInfo)
let apsInfo = userInfo["aps"] as! NSDictionary
var alertMessage = ""
print("********************** Received Notif")
if let alert = apsInfo["alert"] as? String{
alertMessage = alert
print(alertMessage)
}
else if let alert = apsInfo["alert"] as? NSDictionary, let body = alert["body"] as? String {
alertMessage = body
print(alertMessage)
}
// If the application is currently on screen "Active" then we trigger a custom banner View for that notification to be shown
// Else the system will handle that and put it in the notification center
if application.applicationState == UIApplicationState.Active {
AGPushNoteView.showWithNotificationMessage(alertMessage, autoClose: true, completion: { () -> Void in
// Do nothing
})
}
}
func gcmRegistrationHandler(registrationToken: String!, error: NSError!) {
if (registrationToken != nil) {
self.gcmRegistrationToken = registrationToken
print("GCM Registration Token: \(registrationToken)")
let userInfo = ["registrationToken": registrationToken]
NSNotificationCenter.defaultCenter().postNotificationName(
self.gcmRegistrationKey, object: nil, userInfo: userInfo)
} else {
print("Registration to GCM failed with error: \(error.localizedDescription)")
let userInfo = ["error": error.localizedDescription]
NSNotificationCenter.defaultCenter().postNotificationName(self.gcmRegistrationKey, object: nil, userInfo: userInfo)
}
}
// MARK: - GGLInstanceIDDelegate
func onTokenRefresh() {
// A rotation of the registration tokens is happening, so the app needs to request a new token.
print("The GCM registration token needs to be changed.")
GGLInstanceID.sharedInstance().tokenWithAuthorizedEntity(gcmSenderID,
scope: kGGLInstanceIDScopeGCM, options: gcmRegistrationOptions, handler: gcmRegistrationHandler)
}
// MARK: - GCMReceiverDelegate
func willSendDataMessageWithID(messageID: String!, error: NSError!) {
if (error != nil) {
// Failed to send the message.
} else {
// Will send message, you can save the messageID to track the message
}
}
func didSendDataMessageWithID(messageID: String!) {
// Did successfully send message identified by messageID
}
// [END upstream_callbacks]
func didDeleteMessagesOnServer() {
// Some messages sent to this device were deleted on the GCM server before reception, likely
// because the TTL expired. The client should notify the app server of this, so that the app
// server can resend those messages.
}
func subscribeToTopic() {
// If the app has a registration token and is connected to GCM, proceed to subscribe to the
// topic
let subscriptionTopic = "/topics/test-global"
if(gcmRegistrationToken != nil && connectedToGCM) {
GCMPubSub.sharedInstance().subscribeWithToken(gcmRegistrationToken, topic: subscriptionTopic,
options: nil, handler: {(NSError error) -> Void in
if (error != nil) {
// Treat the "already subscribed" error more gently
if error.code == 3001 {
print("Already subscribed to \(subscriptionTopic)")
} else {
print("Subscription failed: \(error.localizedDescription)");
}
} else {
subscribedToTopic = true;
NSLog("Subscribed to \(subscriptionTopic)");
}
})
}
}
}
您是否检查过您是否已在 plist 中定义了 NSAppTransportSecurity 密钥。
您的代码中有几个问题。
首先,你需要在didFinishLaunchingWithOptions
方法中调用GCMService.sharedInstance().startWithConfig(GCMConfig.defaultConfig())
,但是你只在didRegisterForRemoteNotificationsWithDeviceToken
方法中调用了
其次,您应该在 didFinishLaunchingWithOptions
方法中的 application.registerUserNotificationSettings()
之后调用 application.registerForRemoteNotifications()
。
AppDelegate.swift
文件有一个 sample GCM project for iOS available, you can follow the sample implementation,这样您的应用程序才能正常运行。
您还可以通过执行 pod try Google
通过 Cocoapods 获取 GCM iOS 示例项目,您可以访问 this documentation 了解更多详情。
已编辑:
您应该将 didFinishLaunchingWithOptions
中的行替换为以下内容(注意您应该使用 let gcmConfig = GCMConfig.defaultConfig()
和 gcmConfig.receiverDelegate = self
):
// [START_EXCLUDE]
// Configure the Google context: parses the GoogleService-Info.plist, and initializes
// the services that have entries in the file
var configureError:NSError?
GGLContext.sharedInstance().configureWithError(&configureError)
assert(configureError == nil, "Error configuring Google services: \(configureError)")
gcmSenderID = GGLContext.sharedInstance().configuration.gcmSenderID
// [END_EXCLUDE]
// Register for remote notifications
let settings: UIUserNotificationSettings =
UIUserNotificationSettings( forTypes: [.Alert, .Badge, .Sound], categories: nil )
application.registerUserNotificationSettings( settings )
application.registerForRemoteNotifications()
// [END register_for_remote_notifications]
// [START start_gcm_service]
var gcmConfig = GCMConfig.defaultConfig()
gcmConfig.receiverDelegate = self
GCMService.sharedInstance().startWithConfig(gcmConfig)
// [END start_gcm_service]
return true
我正在我的应用程序中实施 Google 云消息传递。我遵循了 google 文档中给出的 tutorial。我可以使用 HTTP POST 请求向我的设备发送通知,但问题是在 applicationDidBecomeActive 中,如 google 所示,我尝试连接 gcmService 但 connectionHandler 块永远不会叫.
我的 AppDelegate 中的 applicationDidBecomeActive 函数
func applicationDidBecomeActive(application: UIApplication) {
GCMService.sharedInstance().connectWithHandler({
(NSError error) -> Void in
if error != nil {
print("Could not connect to GCM: \(error.localizedDescription)")
} else {
self.connectedToGCM = true
print("Connected to GCM")
self.subscribeToTopic()
}
})
}
有人解决过这个问题吗?
编辑 - 这是正确的方法
这是我的完整 AppDelegate.swift 文件
//
// AppDelegate.swift
//
import UIKit
import CoreData
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate, GGLInstanceIDDelegate, GCMReceiverDelegate {
var window: UIWindow?
var connectedToGCM = false
var gcmSenderID: String?
var gcmRegistrationToken: String?
var gcmRegistrationOptions = [String: AnyObject]()
let gcmRegistrationKey = "onRegistrationCompleted"
var subscribedToTopic = false
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
print("bundleId=\(NSBundle.mainBundle().bundleIdentifier)")
// Configure Google Analytics
// Configure tracker from GoogleService-Info.plist.
var configureError:NSError?
GGLContext.sharedInstance().configureWithError(&configureError)
assert(configureError == nil, "Error configuring Google services: \(configureError)")
// Optional: configure GAI options.
let gai = GAI.sharedInstance()
gai.trackUncaughtExceptions = true // report uncaught exceptions
gai.logger.logLevel = GAILogLevel.Verbose // remove before app release
// Override point for customization after application launch.
application.registerUserNotificationSettings(UIUserNotificationSettings(forTypes: [.Alert, .Badge, .Sound], categories: nil)) // types are UIUserNotificationType members
// Register for remotes notifications
UIApplication.sharedApplication().registerForRemoteNotifications()
// Get the gcm sender id
gcmSenderID = GGLContext.sharedInstance().configuration.gcmSenderID
var gcmConfig = GCMConfig.defaultConfig()
gcmConfig.receiverDelegate = self
GCMService.sharedInstance().startWithConfig(gcmConfig)
return true
}
func applicationWillResignActive(application: UIApplication) {
// Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
// Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
}
func applicationDidEnterBackground(application: UIApplication) {
// Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
// If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
GCMService.sharedInstance().disconnect()
connectedToGCM = false
}
func applicationWillEnterForeground(application: UIApplication) {
// Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
}
func applicationDidBecomeActive(application: UIApplication) {
// Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
// -->The app go through this point
// Connect to the GCM server to receive non-APNS notifications
GCMService.sharedInstance().connectWithHandler(gcmConnectionHandler)
// -->The app go through this point
}
func gcmConnectionHandler(error: NSError?) {
// -->The app never enter in this function
if let error = error {
print("Could not connect to GCM: \(error.localizedDescription)")
} else {
self.connectedToGCM = true
print("Connected to GCM")
// ...
}
}
func applicationWillTerminate(application: UIApplication) {
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
self.saveContext()
}
func application(application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: NSData) {
// Create a config and set a delegate that implements the GGLInstaceIDDelegate protocol.
let instanceIDConfig = GGLInstanceIDConfig.defaultConfig()
instanceIDConfig.delegate = self
// Start the GGLInstanceID shared instance with that config and request a registration
// token to enable reception of notifications
GGLInstanceID.sharedInstance().startWithConfig(instanceIDConfig)
gcmRegistrationOptions = [kGGLInstanceIDRegisterAPNSOption:deviceToken,
kGGLInstanceIDAPNSServerTypeSandboxOption:true]
GGLInstanceID.sharedInstance().tokenWithAuthorizedEntity(gcmSenderID,
scope: kGGLInstanceIDScopeGCM, options: gcmRegistrationOptions, handler: gcmRegistrationHandler)
}
func application(application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: NSError) {
print("-- Failed to get deviceToken: \(error.localizedDescription)")
}
func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject]) {
application.applicationIconBadgeNumber += 1
print(userInfo)
let apsInfo = userInfo["aps"] as! NSDictionary
var alertMessage = ""
print("********************** Received Notif")
if let alert = apsInfo["alert"] as? String{
alertMessage = alert
print(alertMessage)
}
else if let alert = apsInfo["alert"] as? NSDictionary, let body = alert["body"] as? String {
alertMessage = body
print(alertMessage)
}
// If the application is currently on screen "Active" then we trigger a custom banner View for that notification to be shown
// Else the system will handle that and put it in the notification center
if application.applicationState == UIApplicationState.Active {
AGPushNoteView.showWithNotificationMessage(alertMessage, autoClose: true, completion: { () -> Void in
// Do nothing
})
}
}
func gcmRegistrationHandler(registrationToken: String!, error: NSError!) {
if (registrationToken != nil) {
self.gcmRegistrationToken = registrationToken
print("GCM Registration Token: \(registrationToken)")
let userInfo = ["registrationToken": registrationToken]
NSNotificationCenter.defaultCenter().postNotificationName(
self.gcmRegistrationKey, object: nil, userInfo: userInfo)
} else {
print("Registration to GCM failed with error: \(error.localizedDescription)")
let userInfo = ["error": error.localizedDescription]
NSNotificationCenter.defaultCenter().postNotificationName(self.gcmRegistrationKey, object: nil, userInfo: userInfo)
}
}
// MARK: - GGLInstanceIDDelegate
func onTokenRefresh() {
// A rotation of the registration tokens is happening, so the app needs to request a new token.
print("The GCM registration token needs to be changed.")
GGLInstanceID.sharedInstance().tokenWithAuthorizedEntity(gcmSenderID,
scope: kGGLInstanceIDScopeGCM, options: gcmRegistrationOptions, handler: gcmRegistrationHandler)
}
// MARK: - GCMReceiverDelegate
func willSendDataMessageWithID(messageID: String!, error: NSError!) {
if (error != nil) {
// Failed to send the message.
} else {
// Will send message, you can save the messageID to track the message
}
}
func didSendDataMessageWithID(messageID: String!) {
// Did successfully send message identified by messageID
}
// [END upstream_callbacks]
func didDeleteMessagesOnServer() {
// Some messages sent to this device were deleted on the GCM server before reception, likely
// because the TTL expired. The client should notify the app server of this, so that the app
// server can resend those messages.
}
func subscribeToTopic() {
// If the app has a registration token and is connected to GCM, proceed to subscribe to the
// topic
let subscriptionTopic = "/topics/test-global"
if(gcmRegistrationToken != nil && connectedToGCM) {
GCMPubSub.sharedInstance().subscribeWithToken(gcmRegistrationToken, topic: subscriptionTopic,
options: nil, handler: {(NSError error) -> Void in
if (error != nil) {
// Treat the "already subscribed" error more gently
if error.code == 3001 {
print("Already subscribed to \(subscriptionTopic)")
} else {
print("Subscription failed: \(error.localizedDescription)");
}
} else {
subscribedToTopic = true;
NSLog("Subscribed to \(subscriptionTopic)");
}
})
}
}
}
您是否检查过您是否已在 plist 中定义了 NSAppTransportSecurity 密钥。
您的代码中有几个问题。
首先,你需要在didFinishLaunchingWithOptions
方法中调用GCMService.sharedInstance().startWithConfig(GCMConfig.defaultConfig())
,但是你只在didRegisterForRemoteNotificationsWithDeviceToken
方法中调用了
其次,您应该在 didFinishLaunchingWithOptions
方法中的 application.registerUserNotificationSettings()
之后调用 application.registerForRemoteNotifications()
。
AppDelegate.swift
文件有一个 sample GCM project for iOS available, you can follow the sample implementation,这样您的应用程序才能正常运行。
您还可以通过执行 pod try Google
通过 Cocoapods 获取 GCM iOS 示例项目,您可以访问 this documentation 了解更多详情。
已编辑:
您应该将 didFinishLaunchingWithOptions
中的行替换为以下内容(注意您应该使用 let gcmConfig = GCMConfig.defaultConfig()
和 gcmConfig.receiverDelegate = self
):
// [START_EXCLUDE]
// Configure the Google context: parses the GoogleService-Info.plist, and initializes
// the services that have entries in the file
var configureError:NSError?
GGLContext.sharedInstance().configureWithError(&configureError)
assert(configureError == nil, "Error configuring Google services: \(configureError)")
gcmSenderID = GGLContext.sharedInstance().configuration.gcmSenderID
// [END_EXCLUDE]
// Register for remote notifications
let settings: UIUserNotificationSettings =
UIUserNotificationSettings( forTypes: [.Alert, .Badge, .Sound], categories: nil )
application.registerUserNotificationSettings( settings )
application.registerForRemoteNotifications()
// [END register_for_remote_notifications]
// [START start_gcm_service]
var gcmConfig = GCMConfig.defaultConfig()
gcmConfig.receiverDelegate = self
GCMService.sharedInstance().startWithConfig(gcmConfig)
// [END start_gcm_service]
return true