后台 IOS / php 服务器中的 GCM 通知

Posted

技术标签:

【中文标题】后台 IOS / php 服务器中的 GCM 通知【英文标题】:GCM Notifications in background IOS / php Server 【发布时间】:2016-03-05 13:11:38 【问题描述】:

我已经一周没有尝试在我的 ios 应用上实现 GCM 通知了。前台通知正在工作,但不是后台。 这是我来自 appdelegate 和我的服务器的代码:

    @UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate, GGLInstanceIDDelegate, GCMReceiverDelegate 

    var window: UIWindow?
let constants = Constants()

var connectedToGCM = false
var subscribedToTopic = false
var gcmSenderID: String?
var registrationToken: String?
var registrationOptions = [String: AnyObject]()
var notificationWasReceivedInForeground = true

let registrationKey = "onRegistrationCompleted"
let messageKey = "onMessageReceived"
let subscriptionTopic = "/topics/global"

func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool 

    // Google Maps 

    GMSServices.provideAPIKey("apiKey")

    // Initial View Controller

    self.window = UIWindow(frame: UIScreen.mainScreen().bounds)
    let storyboard = UIStoryboard(name: "Main", bundle: nil)
    var initialViewController = storyboard.instantiateViewControllerWithIdentifier("navConFirst")

    let defaults = NSUserDefaults.standardUserDefaults()
    if defaults.boolForKey(constants.userIsConnected) 
        initialViewController = storyboard.instantiateViewControllerWithIdentifier("navConConnection")
    


    // Google Cloud Messaging

    var configureError:NSError?
    GGLContext.sharedInstance().configureWithError(&configureError)
    assert(configureError == nil, "Error configuring Google services: \(configureError)")
    gcmSenderID = GGLContext.sharedInstance().configuration.gcmSenderID

    let settings: UIUserNotificationSettings =
    UIUserNotificationSettings(forTypes: [.Alert, .Badge, .Sound], categories: nil)
    application.registerUserNotificationSettings(settings)
    application.registerForRemoteNotifications()

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

    self.window?.rootViewController = initialViewController
    self.window?.makeKeyAndVisible()

    return true


func subscribeToTopic() 
    // If the app has a registration token and is connected to GCM, proceed to subscribe to the
    // topic
    if(registrationToken != nil && connectedToGCM) 
        GCMPubSub.sharedInstance().subscribeWithToken(self.registrationToken, 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 \(self.subscriptionTopic)")
                     else 
                        print("Subscription failed: \(error.localizedDescription)");
                    
                 else 
                    self.subscribedToTopic = true;
                    NSLog("Subscribed to \(self.subscriptionTopic)");
                
        )
    


// [START connect_gcm_service]
func applicationDidBecomeActive( application: UIApplication) 
    // Connect to the GCM server to receive non-APNS notifications
    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")
            // [START_EXCLUDE]
            self.subscribeToTopic()
            // [END_EXCLUDE]
        
    )

// [END connect_gcm_service]

// [START disconnect_gcm_service]
func applicationDidEnterBackground(application: UIApplication) 
    GCMService.sharedInstance().disconnect()
    // [START_EXCLUDE]
    self.connectedToGCM = false
    // [END_EXCLUDE]

// [END disconnect_gcm_service]

// [START receive_apns_token]
func application( application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: NSData ) 

    // [END receive_apns_token]
    // [START get_gcm_reg_token]
    // 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)
    registrationOptions = [kGGLInstanceIDRegisterAPNSOption:deviceToken,
        kGGLInstanceIDAPNSServerTypeSandboxOption:true]
    GGLInstanceID.sharedInstance().tokenWithAuthorizedEntity(gcmSenderID,
        scope: kGGLInstanceIDScopeGCM, options: registrationOptions, handler: registrationHandler)
    // [END get_gcm_reg_token]


// [START receive_apns_token_error]
func application( application: UIApplication, didFailToRegisterForRemoteNotificationsWithError
    error: NSError ) 
        print("Registration for remote notification failed with error: \(error.localizedDescription)")
        // [END receive_apns_token_error]
        let userInfo = ["error": error.localizedDescription]
        NSNotificationCenter.defaultCenter().postNotificationName(
            registrationKey, object: nil, userInfo: userInfo)


// [START ack_message_reception]
func application( application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject]) 
        print("Notification received: \(userInfo)")
        // This works only if the app started the GCM service
        GCMService.sharedInstance().appDidReceiveMessage(userInfo);
        // Handle the received message
        // [START_EXCLUDE]
        NSNotificationCenter.defaultCenter().postNotificationName(messageKey, object: nil,
            userInfo: userInfo)
        // [END_EXCLUDE]


func application( application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject], fetchCompletionHandler handler: (UIBackgroundFetchResult) -> Void) 
        print("Notification received: \(userInfo)")
        // This works only if the app started the GCM service
        GCMService.sharedInstance().appDidReceiveMessage(userInfo);
        // Handle the received message
        // Invoke the completion handler passing the appropriate UIBackgroundFetchResult value
        // [START_EXCLUDE]
        NSNotificationCenter.defaultCenter().postNotificationName(messageKey, object: nil,
            userInfo: userInfo)
        handler(UIBackgroundFetchResult.NoData);
        // [END_EXCLUDE]

// [END ack_message_reception]

func registrationHandler(registrationToken: String!, error: NSError!) 
    if (registrationToken != nil) 
        self.registrationToken = registrationToken
        print("Registration Token: \(registrationToken)")
        self.subscribeToTopic()
        let userInfo = ["registrationToken": registrationToken]
        NSNotificationCenter.defaultCenter().postNotificationName(
            self.registrationKey, object: nil, userInfo: userInfo)
     else 
        print("Registration to GCM failed with error: \(error.localizedDescription)")
        let userInfo = ["error": error.localizedDescription]
        NSNotificationCenter.defaultCenter().postNotificationName(
            self.registrationKey, object: nil, userInfo: userInfo)
    


// [START on_token_refresh]
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: registrationOptions, handler: registrationHandler)

// [END on_token_refresh]

// [START upstream_callbacks]
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 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 applicationWillEnterForeground(application: UIApplication) 
    // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.

对于服务器:

  $regId = "myID";
    $message = "message";

    $data = array( 'price' => $message, 'sound' => 'default', 'body' => 'helloworld', 'title' => 'default', 'badge' => 12);

    $ids = array( $regId);

sendGoogleCloudMessage(  $data, $ids );

function sendGoogleCloudMessage( $data, $ids )
 $apiKey = apiKey;

    $url = 'https://android.googleapis.com/gcm/send';

  $post = array(
                'to' => "myID",
                'data' => $data,
                'priority' => "high",
    );

    $headers = array(
                    'Authorization: key=' . $apiKey,
                    'Content-Type: application/json'
                );

    $ch = curl_init();

    curl_setopt( $ch, CURLOPT_URL, $url );

    curl_setopt( $ch, CURLOPT_POST, true );

    curl_setopt( $ch, CURLOPT_HTTPHEADER, $headers );

    curl_setopt( $ch, CURLOPT_RETURNTRANSFER, true );

    curl_setopt( $ch, CURLOPT_POSTFIELDS, json_encode( $post ) );

    $result = curl_exec( $ch );

    if ( curl_errno( $ch ) )
    
        echo 'GCM error: ' . curl_error( $ch );
    

    curl_close( $ch );

    echo $result;

事情是这样的:如果我添加 content_availble 或者我将“数据”更改为“通知”,就像我在此处阅读的那样,通知不再起作用,并且出现“未注册”错误

如果有人看到问题所在,我将非常感激!

提前致谢

【问题讨论】:

【参考方案1】:

我的证书似乎无效。我必须下载这个证书并安装它

new WWDR Certificate that expires in 2023

【讨论】:

以上是关于后台 IOS / php 服务器中的 GCM 通知的主要内容,如果未能解决你的问题,请参考以下文章

gcm推送通知:先成功,后IOS未注册

带有 GCM 的 iOS 推送通知

iOS应用后台主题推送通知

如何通过 GCM 向 iOS 设备发送推送通知?

React本机推送通知,GCM服务器返回401

当应用程序处于非活动状态时,GCM 推送通知不适用于 iOS