IOS谷歌云消息(GCM)不接收远程通知 [英] ios Google Cloud Messaging (GCM) not receiving remote notifications

查看:487
本文介绍了IOS谷歌云消息(GCM)不接收远程通知的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

问题:结果
iOS的是没有收到来自任何GCM远程通知,却找不到关于为什么会出现这种情况的任何信息。结果
第一次实现推送通知,不知道的问题的原因是什么。结果
任何帮助将大大AP preciated。

Problem:
iOS isn't receiving any remote notifications from GCM, but can't find any information relating to why this would be the case.
First time implementing push notifications, not sure what the cause of problem is.
Any help would be greatly appreciated.

情况:结果
我目前正在使用GCM推送通知的应用程序的iOS版本。正在接收通知的Andr​​oid精品,但是,它并没有出现在所有iOS上是在接收。

Situation:
I am currently working on the iOS version of an app that uses GCM for push notifications. Notifications are being received fine on Android, however, it doesn't appear to be receiving at all on iOS.

当我运行应用程序,控制台显示我一切都很好,有一个道理,连接到GCM和订阅主题

When I run the application, the console shows me that everything is fine, has a token, connected to GCM and subscribed to topics

应用[579:45511]注册令牌:
  bk3RNwTe3H0:CI2k_HHwgIpoDKCIZvvDMExUdFQ3P1pLTQ / 8T-5QNiXbYwZYEWiSFD-frQKlsV8lgI结果
  应用[579:45511]连接到GCM结果
  应用[579:45511]已订阅/主题/全球搜索

app[579:45511] Registration Token: bk3RNwTe3H0:CI2k_HHwgIpoDKCIZvvDMExUdFQ3P1pLTQ/8t-5QNiXbYwZYEWiSFD-frQKlsV8lgI
app[579:45511] Connected to GCM
app[579:45511] Already subscribed to /topics/global

然而,它没有收到任何通知,当我拉下通知中心或拉起控制中心,在控制台中出现以下消息

However it doesn't receive any notifications and when I pull down Notifications Center or pull up Control Center, the following message occurs in console

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

app[579:45511] Could not connect to GCM: The operation couldn’t be completed. (com.google.gcm error 2001.)

这并没有告诉我很多除了指...

which doesn't tell me much other than referring to...

///缺少密钥对。结果
   kGGLInstanceIDOperationError codeMissingKeyPair = 2001,

/// Missing KeyPair.
kGGLInstanceIDOperationErrorCodeMissingKeyPair = 2001,

在另一手,当我把它发送到与多任务功能的背景和把它带回来,我再一次得到这样的:

On the other-hand, when I send it to the background with the multi-task feature and bring it back, I get this again:

应用[579:45511]连接到GCM结果
  应用[579:45511]已订阅/主题/全球搜索

app[579:45511] Connected to GCM
app[579:45511] Already subscribed to /topics/global

设置:结果
我跟着GCM说明设置iOS中甚至提到了GcmExample.x codeproj的实施(到了code是完全一样的点)。

Setup:
I've followed the GCM instructions to set up in iOS and even referred to the GcmExample.xcodeproj for the implementation (to the point that the code is exact same).

设置'所需的背景模式'Info.plist中 - >应用软件下载的内容响应推送通知

Set the info.plist for 'Required background modes' -> 'App downloads content in response to push notifications'

跨越另一个计算器问题就来了(现在找不到)关于GCM和IP地址没有被列入白名单,但排除了这种可能性不成为问题。

Came across another stackoverflow question (can't find now) about GCM and IPs not being whitelisted but ruled that out to not be the issue.

结果
code:搜索

#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 inactive 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

更新结果
后端PHP code发送消息GCM
结果

UPDATE
backend php code to send a GCM message

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

推荐答案

您得到的错误2001年不是 kGGLInstanceIDOperationError codeMissingKeyPair <​​/ code>而是 kGCMServiceError codeAlreadyConnected 。后者意味着你已经连接到GCM。为了更好地调试这个我会尝试显示通知发送到设备令牌即发送此

The error 2001 you get is NOT kGGLInstanceIDOperationErrorCodeMissingKeyPair but rather kGCMServiceErrorCodeAlreadyConnected. The latter means that you're already connected to GCM. To better debug this I would try to send a display notification to the device token i.e. send this

$ post_json_en code ='{通知:{体:'。$味精。
  },要:/主题/全球}';

$post_json_encode = '{"notification":{"body":"' . $msg . '"},"to":"/topics/global"}';

您理论上应该连接到GCM当你的应用程序是在前台,当你去后台断开连接。当你来到前台,您可以然后再重新连接。

You should theoretically connect to GCM when your app is in the foreground and disconnect when you go to background. You can then reconnect again when you come to the foreground.

数据有效载荷的通知有效载荷均适用于iOS和放大器; Android系统。在iOS不同的是,通知的有效载荷通过APNS发送在数据负载是通过GCM自己的连接,也就是只有在那里,当应用程序在前台发送。在Android的通知有效载荷是最近添加新的显示通知的东西。

The data payload and notification payload are both applicable on iOS & Android. On iOS the difference is that notification payload is sent through APNS while data payload is sent through GCM's own connection which is only there when app is in foreground. In Android notification payload is the new display notification stuff added recently.

这篇关于IOS谷歌云消息(GCM)不接收远程通知的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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