GCM for iOS,gcm连接处理程序永远不会被调用 [英] GCM for iOS, gcm connection handler is never called

查看:193
本文介绍了GCM for iOS,gcm连接处理程序永远不会被调用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在应用程序中实施Google云消息传递。我已遵循google文档中提供的教程。我可以使用HTTP POST请求向我的设备发送通知,但问题是,在applicationDidBecomeActive中,正如google所示,我尝试连接gcmService,但 connectionHandler块永远不会被调用



我的AppDelegate中的applicationDidBecomeActive函数

  func applicationDidBecomeActive应用程序:UIApplication){


GCMService.sharedInstance()。connectWithHandler({
(NSError error) - >无效
如果错误!= nil {
print(无法连接到GCM:\(error.localizedDescription))
} else {
self.connectedToGCM = true
print(Connected to GCM)

self.subscribeToTopic()
}
})
}

有没有人解决过这个问题?

编辑 - 这是正确的方法



这是我的compl ete AppDelegate.swift文件

  // 
// AppDelegate.swift
//

导入UIKit
导入CoreData

@UIApplicationMain $ b $ 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))

//配置Google Analytics
//从GoogleService-Info中配置跟踪器。 plist中。
var configureError:NSError?
GGLContext.sharedInstance()。configureWithError(& configureError)
assert(configureError == nil,配置Google服务时出错:\(configureError))

//可选:配置GAI选项。
let gai = GAI.sharedInstance()
gai.trackUncaughtExceptions = true //报告未捕获的异常
gai.logger.logLevel = GAILogLevel.Verbose //在应用发布之前删除


//覆盖应用程序启动后自定义的点。
application.registerUserNotificationSettings(UIUserNotificationSettings(forTypes:[.Alert,.Badge,.Sound],categories:nil))//类型是UIUserNotificationType成员
//注册远程通知
UIApplication。 registerForRemoteNotifications()

//获取gcm发件人ID
gcmSenderID = GGLContext.sharedInstance()。configuration.gcmSenderID

var gcmConfig = GCMConfig。 defaultConfig()
gcmConfig.receiverDelegate = self
GCMService.sharedInstance()。startWithConfig(gcmConfig)

返回true
}

func applicationWillResignActive(application:UIApplication){
//当应用程序即将从活动状态转移到非活动状态时发送。对于某些类型的临时中断(例如来电或SMS消息)或用户退出应用程序并开始转换到后台状态时,可能会发生这种情况。
//使用此方法可暂停正在进行的任务,禁用定时器并降低OpenGL ES帧速率。游戏应该使用这种方法来暂停游戏。
}

func applicationDidEnterBackground(application:UIApplication){
//使用此方法释放共享资源,保存用户数据,使计时器无效并存储足够的应用程序状态信息以进行还原您的应用程序将保持当前状态,以备稍后终止。
//如果您的应用程序支持后台执行,则调用此方法而不是applicationWillTerminate:当用户退出时。
GCMService.sharedInstance()。disconnect()
$ b connectedToGCM = false
}

func applicationWillEnterForeground(application:UIApplication){
/ /作为从背景转换到活动状态的一部分;在这里您可以撤消进入背景时所做的许多更改。
}

func applicationDidBecomeActive(application:UIApplication){
//在应用程序处于非活动状态时,重新启动暂停(或尚未启动)的任何任务。如果应用程序以前位于后台,则可以选择刷新用户界面。

// - >应用程序经过这一点
//连接到GCM服务器以接收非APNS通知
GCMService.sharedInstance()。connectWithHandler(gcmConnectionHandler )
// - >应用程序经过这个点
}

func gcmConnectionHandler(error:NSError?){
// - > The应用程序永远不会输入这个函数
if error = error {
print(无法连接到GCM:\(error.localizedDescription))
} else {
self .connectedToGCM = true
print(Connected to GCM)
// ...
}
}

func applicationWillTerminate(application:UIApplication) {
//当应用程序即将终止时调用。如果适用,保存数据。另请参阅applicationDidEnterBackground :.
self.saveContext()
}

func application(application:UIApplication,didRegisterForRemoteNotificationsWithDeviceToken deviceToken:NSData){

//创建一个配置并设置一个实现GGLInstaceIDDelegate协议的委托。
let instanceIDConfig = GGLInstanceIDConfig.defaultConfig()
instanceIDConfig.delegate = self
//使用该配置启动GGLInstanceID共享实例并请求注册
//令牌以启用接收通知
GGLInstanceID.sharedInstance()。startWithConfig(instanceIDConfig)
gcmRegistrationOptions = [kGGLInstanceIDRegisterAPNSOption:deviceToken,
kGGLInstanceIDAPNSServerTypeSandboxOption:true]
GGLInstanceID.sharedInstance()。tokenWithAuthorizedEntity(gcmSenderID,
scope:kGGLInstanceIDScopeGCM,options:gcmRegistrationOptions,handler:gcmRegistrationHandler)


$ b func应用程序 - 无法获得deviceToken:\(error.localizedDescription))
}

func application(application:UIApplicati on,didReceiveRemoteNotification userInfo:[NSObject:AnyObject]){
application.applicationIconBadgeNumber + = 1

print(userInfo)
let apsInfo = userInfo [aps] as! NSDictionary

var alertMessage =
print(********************** Received Notif)

如果让alert = apsInfo [alert]为? String {
alertMessage = alert
print(alertMessage)
}
else如果让alert = apsInfo [alert]为? NSDictionary,让body = alert [body]为?字符串{
alertMessage = body
print(alertMessage)
}


//如果应用程序当前处于屏幕活动状态,那么我们触发一个自定义横幅查看通知显示
//否则系统将处理该通知并将其置于通知中心
if application.applicationState == UIApplicationState.Active {
AGPushNoteView.showWithNotificationMessage( alertMessage,autoClose:true,完成:{() - >无效
//无所作为
})
}
}


func gcmRegistrationHandler(registrationToken:String!,error:NSError!){
if(registrationToken!= nil){
self.gcmRegistrationToken = registrationToken
print(GCM Registration Token:\ (registrationToken))
let userInfo = [registrationToken:registrationToken]
NSNotificationCe (注册到GCM失败,错误:\(error。nter.defaultCenter()。postNotificationName(
self.gcmRegistrationKey,object:nil,userInfo:userInfo)
} else {
print )
let userInfo = [error:error.localizedDescription]
NSNotificationCenter.defaultCenter()。postNotificationName(self.gcmRegistrationKey,object:nil,userInfo:userInfo)
}

$ b $ // MARK: - GGLInstanceIDDelegate
func onTokenRefresh(){
//注册令牌轮换正在发生,所以应用程序需要一个新的令牌。
print(GCM注​​册令牌需要更改。)
GGLInstanceID.sharedInstance()。tokenWithAuthorizedEntity(gcmSenderID,
scope:kGGLInstanceIDScopeGCM,options:gcmRegistrationOptions,handler:gcmRegistrationHandler)


$ b // MARK: - GCMReceiverDelegate
func willSendDataMessageWithID(messageID:String !,错误:NSError!){
if(error!= nil) {
//发送消息失败。
} else {
//将发送消息,您可以保存消息ID以跟踪消息
}
}

func didSendDataMessageWithID(messageID:String !){
//成功发送messageID标识的消息
}
// [END upstream_callbacks]

func didDeleteMessagesOnServer(){
//在接收之前,发送到此设备的一些消息在GCM服务器上被删除,可能是
//因为TTL已过期。客户端应该通知应用程序服务器,以便应用程序
//服务器可以重新发送这些消息。

$ b $ func subscribeToTopic(){
//如果应用程序有一个注册令牌并连接到GCM,请继续订阅
// topic
let subscriptionTopic =/ topics / test-global
if(gcmRegistrationToken!= nil& connectedToGCM){
GCMPubSub.sharedInstance()。subscribeWithToken(gcmRegistrationToken,topic:subscriptionTopic,
options:nil,handler:{(NSError error) - >如果(错误!= nil){
//在
中无效$轻轻处理已订阅错误
如果error.code == 3001 {
print(已订阅到\(subscriptionTopic))
} else {
print(订阅失败:\(error.localizedDescription) );
}
} else {
sub scribedToTopic = true;
NSLog(订阅\(subscriptionTopic));
}
})
}
}


}

解决方案

您的代码中有几个问题。在 didFinishLaunchingWithOptions 方法中调用 GCMService.sharedInstance()。startWithConfig(GCMConfig.defaultConfig())在$ > didRegisterForRemoteNotificationsWithDeviceToken 方法中调用它。第二,你应该调用 application.registerForRemoteNotifications()在 didFinishLaunchingWithOptions 方法中,在 application.registerUserNotificationSettings()之后的



针对iOS的示例GCM项目可用,您可以按照 AppDelegate.swift 文件,rel =nofollow>示例实现,以便您的应用程序能正常工作。



您还可以通过 pod试用Google 来通过Cocoapods获取GCM iOS示例项目,您可以访问此文档以获取更多详细信息。



编辑:



您应该使用以下命令替换 didFinishLaunchingWithOptions 中的行(请注意,您应该使用 let gcmConfig = GCMConfig。 defaultConfig() gcmConfig.receiverDelegate = self ):

  // [START_EXCLUDE] 
//配置Google上下文:解析GoogleService-Info.plist,并初始化
//在文件中包含条目的服务
var configureError:NSError?
GGLContext.sharedInstance()。configureWithError(& configureError)
assert(configureError == nil,配置Google服务时出错:\(configureError))
gcmSenderID = GGLContext.sharedInstance ).configuration.gcmSenderID
// [END_EXCLUDE]
//注册远程通知
设置:UIUserNotificationSettings =
UIUserNotificationSettings(forTypes:[.Alert,.Badge,.Sound ],类别:无)
application.registerUserNotificationSettings(设置)
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]
返回true


I'm implementing Google Cloud Messaging in my application. I've followed the tutorial given in google documentations. I can send notifications to my device with HTTP POST request, but the problem is that in the applicationDidBecomeActive, as google showed, I try to connect with gcmService but the connectionHandler block is never called.

applicationDidBecomeActive function in my AppDelegate

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()
        }
    })
}

Does any one have solved this issue?

EDIT - This is the correct way

Here is my complete AppDelegate.swift file

//
//  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)");
                    }
            })
        }
    }


}

解决方案

There are couple problems in your code.

First, you need to call GCMService.sharedInstance().startWithConfig(GCMConfig.defaultConfig()) in the didFinishLaunchingWithOptions method, but you only called it in didRegisterForRemoteNotificationsWithDeviceToken method.

Second, you should call application.registerForRemoteNotifications() after application.registerUserNotificationSettings() in your didFinishLaunchingWithOptions method.

There is a sample GCM project for iOS available, you can follow the sample implementation for AppDelegate.swift file, so that your app will work correctly.

You can also get the GCM iOS sample project via Cocoapods by doing pod try Google, you can visit this documentation for more details.

Edited:

You should replace the lines in your didFinishLaunchingWithOptions with the following (notice that you should use let gcmConfig = GCMConfig.defaultConfig() and 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

这篇关于GCM for iOS,gcm连接处理程序永远不会被调用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆