15

Проблема:
IOS не получает никаких уведомлений от удаленных GCM, но не может найти любую информацию, касающуюся того, почему это было бы дело.
Первый раз, когда вы вводите push-уведомления, не знаете, в чем причина проблемы.ИОС Google Cloud Messaging (GCM) не получает удаленные Уведомления

Ситуация:
я в настоящее время работает над версией IOS из приложения, которое использует GCM для уведомления толчка. Уведомления на тонкой основе получаются на Android, однако он, похоже, не получает вообще на iOS.

Когда я запустить приложение, консоль показывает мне, что все в порядке, есть маркер, связанный с ГКМ и подписчики темы

приложение [579: 45511] Регистрация Токен: bk3RNwTe3H0: CI2k_HHwgIpoDKCIZvvDMExUdFQ3P1pLTQ/8Т-5QNiXbYwZYEWiSFD-frQKlsV8lgI
приложение [579: 45511] Подключение к GCM
приложение [579: 45511] Уже подписались/темы/глобальные

Однако он не получает никаких уведомлений и когда я тяну вниз Notifications Center или подтяните центр управления, появляется следующее сообщение в консоли

приложение [579: 45511] Не удалось подключиться к GCM: Операция не может быть завершено. (Ошибка com.google.gcm 2001.)

, который не говорит мне многое другое, чем со ссылкой на ...

/// Отсутствует KeyPair.
kGGLInstanceIDOperationErrorCodeMissingKeyPair = 2001,

С другой-стороны, когда я посылаю его на фоне с функцией мульти-задач и вернуть его обратно, я это снова получить:

приложение [579 : 45511] Подключение к GCM
приложение [579: 45511] Уже подписался/темы/глобальные

Установка:
Я выполнил инструкции GCM для настройки в iOS и даже упомянул GcmExample.xcodeproj для реализации (до такой же точности кода).

Установите info.plist для «Необходимых режимов фона» -> «App загрузки содержимого в ответ на Push-уведомление»

Наткнулся другим StackOverflow вопроса (не может найти сейчас) о ГОМ и IP-адресе не белый список но постановил, что это не проблема.

Код:

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

+1

у меня точно такая же проблема. Однако я получаю хороший контент в userInfo в 'didReceiveRemoteNotification', и я могу NSLog, но по какой-то причине я получаю ту же ошибку, что и вы, если я попытаюсь опубликовать уведомление. Получаете ли вы также содержание сообщения? – Gannicus

+0

Было бы полезно увидеть, как вы отправляете сообщение, т. Е. Содержимое вашего HTTP-запроса (или строфы xmpp), с удаленным ключом API, конечно. – TheWonderBird

+0

@Gannicus, к сожалению, для меня это не похоже, что мое приложение получает какие-либо уведомления вообще. Я поставил контрольные точки в каждой из функций didReceiveRemoteNotification, чтобы проверить, но ничего. Я также заметил, что в GcmExample, предоставленном Google, также генерируется ошибка 2001 года «Не удалось подключиться» в той же ситуации. – setzuiro

ответ

4

Ошибка 2001 вы получаете НЕ kGGLInstanceIDOperationErrorCodeMissingKeyPair, а скорее kGCMServiceErrorCodeAlreadyConnected. Последнее означает, что вы уже подключены к GCM. Для лучшей отладки это я хотел бы попытаться послать уведомление дисплея устройства лексема т.е. отправить этот

$ post_json_encode = '{ „уведомление“: { „тело“: ".. $ Сообщ '"}, "к": "/ темы/глобальное"} ";

Вы должны теоретически подключиться к GCM, когда ваше приложение находится на переднем плане и отключается при переходе на задний план. Затем вы можете снова подключиться, когда вы перейдете на передний план.

data payload и notification payload оба применимы к iOS & Android. В iOS разница заключается в том, что полезная нагрузка уведомления отправляется через APNS, тогда как полезная нагрузка данных отправляется через собственное соединение GCM, которое существует только там, где приложение находится на переднем плане. В Android-уведомлении полезная нагрузка - это новый материал для уведомления о просмотре, добавленный недавно.

+0

Означает ли это, что есть только полезная информация данных? le получать уведомление, когда приложение находится в фоновом режиме? Надеюсь, не потому, что я использую эту java-библиотеку https://github.com/google/gcm, которая, как представляется, не содержит полезной нагрузки уведомления. – Gannicus

+1

Нет, вы все равно можете использовать 'content_available' для отправки сообщения через APNS даже без ключа« уведомления »в вашей полезной нагрузке. Например, эта полезная нагрузка '{" content_available ": true," data ": {" key1 ":" value1 "}}' будет проходить через APNS и пробуждать приложение в фоновом режиме, чтобы позволить ему получать некоторые новые данные , – evanescent

+0

@evanescent Попробуйте отправить push-уведомление в фоновом режиме, используя: '{ " to ":"/themes/ios-tests ", " data ": { " m ":" TEST 11112 WITH NOTIFICATION ", " e " : 1443045599999 }, "content_available": true, "priority": 10 } ', но он работает только на переднем плане. Если мое приложение переходит на задний план или оно убито, оно не получает никаких уведомлений. Не могли бы вы рассказать мне, что я делаю неправильно? Мой код приложения iOS такой же, как в примере с GCM – granan

0

Я столкнулся с той же проблемой на iOS. Затем я нашел решение на сайте PushBots. Сейчас он работает отлично.

В XCode перейти к Цели> Построить настройки> Код подписи Удостоверение и убедитесь, что это не происходит автоматически и устанавливается на сертификат соответствия профиля, связанного с идентификатором приложения, например

+0

Да так понравилось. Но все равно не работает. –

Смежные вопросы