ios Google云消息传递(GCM)未收到远程通知

问题:
iOS没有收到任何来自GCM的远程通知,但无法find任何有关为什么会这样的信息。
第一次实施推送通知,不知道问题的原因是什么。

情况:
我目前正在使用GCM推送通知的应用程序的iOS版本。 通知正在Android上收到,但是,它似乎并没有在iOS上接收。

当我运行应用程序时,控制台显示一切正常,有一个令牌,连接到GCM并订阅主题

app [579:45511]注册令牌:bk3RNwTe3H0:CI2k_HHwgIpoDKCIZvvDMExUdFQ3P1pLTQ / 8t-5QNiXbYwZYEWiSFD-frQKlsV8lgI
应用程序[579:45511]连接到GCM
应用[579:45511]已订阅/ topics / global

但是,它不会收到任何通知,并且当我拉下通知中心或拉起控制中心时,会在控制台中发生以下消息

应用程序[579:45511]无法连接到GCM:操作无法完成。 (com.google.gcm错误2001.)

除了指的是…

///缺lessKeyPair。
kGGLInstanceIDOperationErrorCodeMissingKeyPair = 2001,

另一方面,当我把它发送到具有多任务function的背景并将其带回时,我再次得到这个:

应用程序[579:45511]连接到GCM
应用[579:45511]已订阅/ topics / global

build立:
我已经遵循GCM指令在iOS中进行设置,甚至还提到了GcmExample.xcodeproj的实现(代码完全相同)。

为“必需的背景模式”设置info.plist – >“应用程序下载内容以响应推送通知”

遇到另一个stackoverflow问题(现在找不到)GCM和IPs不被列入白名单,但裁定,这不是问题。

码:

#import "AppDelegate.h" @interface AppDelegate () @property(nonatomic, strong) void (^registrationHandler) (NSString *registrationToken, NSError *error); @property(nonatomic, assign) BOOL connectedToGCM; @property(nonatomic, strong) NSString* registrationToken; @property(nonatomic, assign) BOOL subscribedToTopic; @end NSString *const SubscriptionTopic = @"/topics/global"; @implementation AppDelegate - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { // Override point for customization after application launch. // [START_EXCLUDE] _registrationKey = @"onRegistrationCompleted"; _messageKey = @"onMessageReceived"; // Configure the Google context: parses the GoogleService-Info.plist, and initializes // the services that have entries in the file NSError* configureError; [[GGLContext sharedInstance] configureWithError:&configureError]; if (configureError != nil) { NSLog(@"Error configuring the Google context: %@", configureError); } _gcmSenderID = [[[GGLContext sharedInstance] configuration] gcmSenderID]; // [END_EXCLUDE] // Register for remote notifications UIUserNotificationType allNotificationTypes = (UIUserNotificationTypeSound | UIUserNotificationTypeAlert | UIUserNotificationTypeBadge); UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:allNotificationTypes categories:nil]; [[UIApplication sharedApplication] registerUserNotificationSettings:settings]; [[UIApplication sharedApplication] registerForRemoteNotifications]; // [END register_for_remote_notifications] // [START start_gcm_service] [[GCMService sharedInstance] startWithConfig:[GCMConfig defaultConfig]]; // [END start_gcm_service] __weak typeof(self) weakSelf = self; // Handler for registration token request _registrationHandler = ^(NSString *registrationToken, NSError *error){ if (registrationToken != nil) { weakSelf.registrationToken = registrationToken; NSLog(@"Registration Token: %@", registrationToken); [weakSelf subscribeToTopic]; NSDictionary *userInfo = @{@"registrationToken":registrationToken}; [[NSNotificationCenter defaultCenter] postNotificationName:weakSelf.registrationKey object:nil userInfo:userInfo]; } else { NSLog(@"Registration to GCM failed with error: %@", error.localizedDescription); NSDictionary *userInfo = @{@"error":error.localizedDescription}; [[NSNotificationCenter defaultCenter] postNotificationName:weakSelf.registrationKey object:nil userInfo:userInfo]; } }; [[NSNotificationCenter defaultCenter] postNotificationName:_messageKey object:nil userInfo:nil]; return YES; } - (void)subscribeToTopic { // If the app has a registration token and is connected to GCM, proceed to subscribe to the // topic if (_registrationToken && _connectedToGCM) { [[GCMPubSub sharedInstance] subscribeWithToken:_registrationToken topic:SubscriptionTopic options:nil handler:^(NSError *error) { if (error) { // Treat the "already subscribed" error more gently if (error.code == 3001) { NSLog(@"Already subscribed to %@", SubscriptionTopic); } else { NSLog(@"Subscription failed: %@", error.localizedDescription); } } else { self.subscribedToTopic = true; NSLog(@"Subscribed to %@", SubscriptionTopic); } }]; } } - (void)applicationWillResignActive:(UIApplication *)application { // 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. } // [START disconnect_gcm_service] - (void)applicationDidEnterBackground:(UIApplication *)application { // 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]; // [START_EXCLUDE] _connectedToGCM = NO; // [END_EXCLUDE] } // [END disconnect_gcm_service] - (void)applicationWillEnterForeground:(UIApplication *)application { // 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. } - (void)applicationDidBecomeActive:(UIApplication *)application { // 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. // Connect to the GCM server to receive non-APNS notifications [[GCMService sharedInstance] connectWithHandler:^(NSError *error) { if (error) { NSLog(@"Could not connect to GCM: %@", error.localizedDescription); } else { _connectedToGCM = true; NSLog(@"Connected to GCM"); // [START_EXCLUDE] [self subscribeToTopic]; // [END_EXCLUDE] } }]; } // [END connect_gcm_service] - (void)applicationWillTerminate:(UIApplication *)application { // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. } // [START receive_apns_token] - (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken { // [END receive_apns_token] // [START get_gcm_reg_token] // Start the GGLInstanceID shared instance with the default config and request a registration // token to enable reception of notifications [[GGLInstanceID sharedInstance] startWithConfig:[GGLInstanceIDConfig defaultConfig]]; _registrationOptions = @{kGGLInstanceIDRegisterAPNSOption:deviceToken, kGGLInstanceIDAPNSServerTypeSandboxOption:@YES}; [[GGLInstanceID sharedInstance] tokenWithAuthorizedEntity:_gcmSenderID scope:kGGLInstanceIDScopeGCM options:_registrationOptions handler:_registrationHandler]; // [END get_gcm_reg_token] } // [START receive_apns_token_error] - (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error { NSLog(@"Registration for remote notification failed with error: %@", error.localizedDescription); // [END receive_apns_token_error] NSDictionary *userInfo = @{@"error" :error.localizedDescription}; [[NSNotificationCenter defaultCenter] postNotificationName:_registrationKey object:nil userInfo:userInfo]; } - (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo { NSLog(@"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] } - (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))handler { NSLog(@"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(UIBackgroundFetchResultNoData); // [END_EXCLUDE] } // [END ack_message_reception] // [START on_token_refresh] - (void)onTokenRefresh { // A rotation of the registration tokens is happening, so the app needs to request a new token. NSLog(@"The GCM registration token needs to be changed."); [[GGLInstanceID sharedInstance] tokenWithAuthorizedEntity:_gcmSenderID scope:kGGLInstanceIDScopeGCM options:_registrationOptions handler:_registrationHandler]; } // [END on_token_refresh] @end 

UPDATE
后端php代码发送一个GCM消息

 //------------------------------ // Payload data you want to send // to Android device (will be // accessible via intent extras) //------------------------------ $msg = addslashes($_POST["msg"]); //------------------------------ // The recipient registration IDs // that will receive the push // (Should be stored in your DB) // // Read about it here: // http://developer.android.com/google/gcm/ //------------------------------ //------------------------------ // Call our custom GCM function //------------------------------ sendGoogleCloudMessage( $msg ); echo "send"; //------------------------------ // Define custom GCM function //------------------------------ function sendGoogleCloudMessage( $msg ) { //------------------------------ // Replace with real GCM API // key from Google APIs Console // // https://code.google.com/apis/console/ //------------------------------ $apiKey = 'abc'; //------------------------------ // Define URL to GCM endpoint //------------------------------ $url = 'https://android.googleapis.com/gcm/send'; //------------------------------ // Set CURL request headers // (Authentication and type) //------------------------------ $headers = array( 'Authorization: key=' . $apiKey, 'Content-Type: application/json' ); //------------------------------ // Initialize curl handle //------------------------------ $ch = curl_init(); //------------------------------ // Set URL to GCM endpoint //------------------------------ curl_setopt( $ch, CURLOPT_URL, $url ); //------------------------------ // Set request method to POST //------------------------------ curl_setopt( $ch, CURLOPT_POST, true ); //------------------------------ // Set our custom headers //------------------------------ curl_setopt( $ch, CURLOPT_HTTPHEADER, $headers ); //------------------------------ // Get the response back as // string instead of printing it //------------------------------ curl_setopt( $ch, CURLOPT_RETURNTRANSFER, true ); //------------------------------ // Set post data as JSON //------------------------------ $post_json_encode = '{"data":{"message":"' . $msg . '"},"to":"/topics/global"}'; curl_setopt( $ch, CURLOPT_POSTFIELDS, $post_json_encode ); //------------------------------ // Actually send the push! //------------------------------ $result = curl_exec( $ch ); //------------------------------ // Error? Display it! //------------------------------ if ( curl_errno( $ch ) ) { echo 'GCM error: ' . curl_error( $ch ); } //------------------------------ // Close curl handle //------------------------------ curl_close( $ch ); //------------------------------ // Debug GCM response //------------------------------ $arr_result = json_decode($result, true); foreach ($arr_result as $name => $value) { echo "<p>".$name .": ". $value ."</p>"; } } 

你得到的错误是不是kGGLInstanceIDOperationErrorCodeMissingKeyPair ,而是kGCMServiceErrorCodeAlreadyConnected 。 后者意味着你已经连接到GCM。 为了更好的debugging,我会尝试发送一个显示通知给设备令牌,即发送这个

$ post_json_encode ='{“notification”:{“body”:“'。$ msg。'”},“to”:“/ topics / global”}';

当你的应用程序在前台时,理论上应该连接到GCM,当你到后台时断开连接。 当你到达前台时,你可以再次重新连接。

data payloadnotification payload都适用于iOS和Android。 在iOS上,区别在于通知有效载荷是通过APNS发送的,而数据有效载荷是通过GCM自己的连接发送的,只有当应用程序处于前台时才有连接。 在Android通知有效载荷是最近添加的新显示通知的东西。

我在iOS上遇到同样的问题。 然后我在PushBots网站上find了解决scheme。 现在对我来说工作正常。

在XCode中,转到“目标”>“生成设置”>“代码签名标识”,并确保它不是自动的,并设置为链接到应用程序ID的configuration文件匹配证书