почему didRegisterForRemoteNotificationsWithDeviceToken не вызывается

89

Я делаю приложение, в котором хочу реализовать службу push-уведомлений Apple. Я следую пошаговым инструкциям, приведенным в этом руководстве .

Но все равно методы не вызываются. Я не знаю, в чем проблема. Может кто-нибудь мне помочь?

    - (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken { 
        //NSString * token = [[NSString alloc] initWithData:deviceTokenencoding:NSUTF8StringEncoding];
        NSString *str = [NSString stringWithFormat:@"Device Token=%@",deviceToken];
        NSLog(@"Device Token:%@",str);

        //NSLog(@"Device token is called");
        //const void *devTokenBytes = [deviceToken bytes];
        //NSLog(@"Device Token");
    }

    - (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)err { 
        NSString *str = [NSString stringWithFormat: @"Error: %@", err];
        NSLog(@"Error:%@",str);    
    }
Музаммил
источник
нет необходимости добавлять какой-либо другой код, просто проверьте его ссылку stackoverflow.com/a/39849892/3269536
jenish

Ответы:

74

У меня была такая же проблема: вызов не registerForRemoteNotificationTypes:вызвал application:didRegisterForRemoteNotificationsWithDeviceToken:ниapplication:didFailToRegisterForRemoteNotificationsWithError:

В конце концов я решил эту проблему с помощью технической заметки Apple TN2265 .

Вот что я сделал:

Во-первых, я дважды проверил, что я действительно правильно регистрируюсь для push-уведомлений , включая проверку моего профиля обеспечения для ключа «aps-environment» и кодовой подписи самого файла .app. У меня все было настроено правильно.

Затем мне пришлось отлаживать сообщения о состоянии push-уведомлений в консоли (вам необходимо установить профиль обеспечения PersistentConnectionLogging.mobileconfig на вашем устройстве и перезагрузить его. См. TN2265 в разделе «Наблюдение за сообщениями о состоянии push-уведомлений »). Я заметил, что процесс apns запускает таймер и вычисляет минимальную дату срабатывания, что заставило меня подозревать, что сообщение с подтверждением регистрации push-уведомления, которое обычно отображается в этот момент, подавляется APNS, как указано в TN2265:

Сброс уведомления о разрешениях push-уведомлений на iOS

Когда приложение с поддержкой push регистрируется для получения push-уведомлений в первый раз, iOS спрашивает пользователя, хотят ли они получать уведомления для этого приложения. После того, как пользователь ответил на это предупреждение, оно больше не отображается, если устройство не будет восстановлено или приложение не было удалено в течение как минимум одного дня.

Если вы хотите смоделировать первый запуск своего приложения, вы можете оставить приложение неустановленным на день. Вы можете достичь последнего, фактически не дожидаясь дня, установив системные часы на день или более вперед, полностью выключив устройство, а затем снова включив его.

Итак, я удалил приложение с устройства, затем вручную изменил дату iPhone в настройках, перезагрузил устройство и повторно установил приложение.

В следующий раз, когда мой код вызвал registerForRemoteNotificationTypes, он получил обратные вызовы, как и ожидалось.

Это решило проблему для меня. Надеюсь, это поможет.

100 грамм
источник
1
Ключевым моментом для меня было то, что я использовал старый сертификат разработки на другом компьютере. Перенос новейшего сертификата с основного портативного компьютера разработчика устранил эту проблему.
Маркус Раутопуро
3
После включения push-уведомлений необходимо снова создать профили обеспечения.
Тони
3
Здравствуй! хотя это старый пост, я обнаружил, что иногда это исправляется, когда вы выключаете и включаете все настройки уведомлений в приложении. Потому что в прошлый раз, когда я помню, был вызван метод RegisterForRemoteNotificationsWithDeviceToken, но внезапно этого не произошло. Надеюсь, это поможет.
otakuProgrammer
1
Я только заставил это работать, добавив еще один шаг сброса: 1. Удалить приложение 2. Сбросить устройство 3. Переслать часы на 1+ дней 4. Сбросить устройство СНОВА 5. Теперь установите, и он должен
выдать
Также важно убедиться, что у вас нет нескольких «действительных» копий одного и того же профиля обеспечения разработки ни в Xcode, ни на самом устройстве. Возможно, вы создали новый сертификат APN и воссоздали свой профиль подготовки после истечения срока действия предыдущего сертификата. Старый профиль разработки по-прежнему действителен в качестве профиля разработки, но его будет недостаточно для включения APN. Вы увидите типичную ошибку «нет допустимых прав на доступ, бла-бла».
jaredsinclair
66

В iOS 8 некоторые методы устарели. Следуйте инструкциям ниже для совместимости с iOS 8.

1. Зарегистрируйте уведомление

if([[UIDevice currentDevice] systemVersion].floatValue >= 8.0)
{
    UIUserNotificationSettings* notificationSettings = [UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeAlert | UIUserNotificationTypeBadge | UIUserNotificationTypeSound categories:nil];
    [[UIApplication sharedApplication] registerUserNotificationSettings:notificationSettings];    
}
else
{
    [[UIApplication sharedApplication] registerForRemoteNotificationTypes:(UIRemoteNotificationTypeAlert | UIRemoteNotificationTypeSound|UIRemoteNotificationTypeBadge)];
}

2. Добавьте новые 2 метода

- (void)application:(UIApplication *)application didRegisterUserNotificationSettings:(UIUserNotificationSettings *)notificationSettings
{
    //register to receive notifications
    [application registerForRemoteNotifications];
}

//For interactive notification only
- (void)application:(UIApplication *)application handleActionWithIdentifier:(NSString *)identifier forRemoteNotification:(NSDictionary *)userInfo completionHandler:(void(^)())completionHandler
{
    //handle the actions
    if ([identifier isEqualToString:@"declineAction"]){
    }
    else if ([identifier isEqualToString:@"answerAction"]){
    }
}

Примечание: в iOS 8 требуются два новых метода в дополнение к didRegisterForRemoteNotificationsWithDeviceTokenиdidReceiveRemoteNotification противном случае метод делегата не будет вызываться.

См .: Удаленное уведомление iOS 8.

Сообщество
источник
1
Следует ли использовать эти два новых метода в Appdelegate.m?
Итан Паркер,
- (void) application: (UIApplication *) application didRegisterUserNotificationSettings: (UIUserNotificationSettings *) notificationSettings {// регистрируемся для получения уведомлений [application registerForRemoteNotifications]; } Добавление следующего опасно, это привело к сбою моего телефона, и я не могу даже восстановить заводские настройки на данный момент.
Джон
Вероятно, это ответ, который вы ищете, если окажетесь здесь. Как ни странно, сегодня делегат был вызван без добавления одного из этих методов. Теперь мне кажется, что они оба мне нужны.
Уилл
мое приложение вылетает с этой строкой[application registerForRemoteNotifications];
smithyy
26

В iOS 8 , помимо другого запроса доступа к push-уведомлениям, вам также необходимо по-другому зарегистрироваться.

Запрос доступа:

if ([application respondsToSelector:@selector(registerUserNotificationSettings:)]) {
    // iOS 8
    UIUserNotificationSettings* settings = [UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeAlert | UIUserNotificationTypeBadge | UIUserNotificationTypeSound categories:nil];
    [[UIApplication sharedApplication] registerUserNotificationSettings:settings];
} else {
    // iOS 7 or iOS 6
    [[UIApplication sharedApplication] registerForRemoteNotificationTypes:(UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeSound | UIRemoteNotificationTypeAlert)];
}

Обрабатывать зарегистрированное устройство:

// New in iOS 8
- (void)application:(UIApplication *)application didRegisterUserNotificationSettings:(UIUserNotificationSettings *)notificationSettings {
    [application registerForRemoteNotifications];
}

// iOS 7 or iOS 6
- (void)application:(UIApplication *)app didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
    NSString *token = [[deviceToken description] stringByTrimmingCharactersInSet: [NSCharacterSet characterSetWithCharactersInString:@"<>"]];
    token = [token stringByReplacingOccurrencesOfString:@" " withString:@""];
    // Send token to server
}
Кайл Клегг
источник
Очень полезно. Я не мог понять, почему мои уведомления сломались.
GoldenJoe
4
Как получить токен в iOS 8?
Yossi
@Yossi, это хранится в переменной "token" вapplication:didRegisterForRemoteNotificationsWithDeviceToken:
Кайл Клегг
мое приложение вылетает с этой строкой [application registerForRemoteNotifications];
кузнец
13

Имейте в виду, что удаленные уведомления не поддерживаются в симуляторе. Следовательно, если вы запустите свое приложение в симуляторе, оно didRegisterForRemoteNotificationsWithDeviceTokenне будет вызываться.

Эрик
источник
@hochl: Я обновил свой ответ, чтобы он более конкретно отвечал на вопрос.
Эрик
1
Обратите внимание, что didFailToRegisterForRemoteNotificationsWithError также не будет вызван. Фактически, ни одно уведомление не вызывается, если вы отключите push-уведомления для своего приложения в настройках (на устройстве или симуляторе). Apple, похоже, не считает это ошибкой stackoverflow.com/questions/9199935/…
Зак Моррис
12

Убедитесь, что вы вызываете свой код (обновите в соответствии с поддерживаемыми видами уведомлений)

[[UIApplication sharedApplication] registerForRemoteNotificationTypes: UIRemoteNotificationTypeAlert | UIRemoteNotificationTypeSound];

и профиль обеспечения включен APNS. Возможно, вам потребуется повторно загрузить профиль обеспечения после включения APNS. Если у вас проблемы и возникают ошибки, то, возможно, вам следует создать Entitlements.plist и добавить ключ «aps-environment» со значением «разработка» или «производство» в зависимости от типа сборки (обычно эта пара ключ-значение содержатся в профиле обеспечения, но иногда Xcode с ними связывается).

Лоренцо Бевилаква
источник
Примечание: «и в профиле обеспечения включен APNS». Щелкните в верхней части «Дерево проектов»> «Возможности»> «Push-уведомления», чтобы установить значение «ВКЛ.».
Trevorgrayson
6

Если профили подготовки использовались раньше для включения и настройки службы push-уведомлений Apple, вам потребуется повторно загрузить профили подготовки.

Удалите профили подготовки из Xcode Organizer и с iPhone / iPad. Перейти к Settings -> General -> Profiles -> [Your provisioning] -> Remove.

Установите новые загруженные профили обеспечения. Затем очистите и запустите проект из XCode. Теперь didRegisterForRemoteNotificationsWithDeviceTokenследует позвонить.

Борислав Гиздов
источник
Это работает для меня. просто выбрал сертификацию и подготовку, в которых были зарегистрированы APN для приложения.
lee
Я удалил весь профиль подготовки с iphone (ios9), а затем после получения токена устройства. Потратьте четыре часа, чтобы исправить это (хотя я многому научился). Спасибо
Шобхакар Тивари
3

Я совершил ошибку и упустил из виду деталь реализации, которая привела меня сюда. Я попытался пофантазировать и попросить пользователя о push-уведомлениях позже в процессе адаптации приложения, поэтому у меня был свой registerForRemoteNotificationTypes, didRegisterForRemoteNotificationsWithDeviceTokenи didFailToRegisterForRemoteNotificationsWithErrorвсе это в пользовательском UIView.

ИСПРАВЛЕНИЕ: didRegisterForRemoteNotificationsWithDeviceTokenи didFailToRegisterForRemoteNotificationsWithErrorдолжны быть в UIApplicationDelegate( YourAppDelegate.m) для срабатывания.

теперь кажется очевидным, хех.

GraehamF
источник
Да, методы должны быть AppDelegate. Не могу поверить, что потратил последние несколько часов на этот простой ответ
Even Cheng
3

Убедитесь, что ваше интернет-соединение включено. На получение уведомлений о работе из-за подключения к Интернету у меня ушло несколько часов.

Rendel
источник
3

Если вы добавили push к существующему идентификатору приложения, убедитесь, что вы повторно создали свои профили подготовки. Если вы этого не сделаете, профиль не будет знать о том, что вы включили push для идентификатора приложения.

Майкл Петерсон
источник
3

Попробуйте, это сработает для меня,

Первый шаг

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions

В приведенном выше методе добавьте ниже код

 UIApplication *application = [UIApplication sharedApplication];
 if ([application respondsToSelector:@selector(registerUserNotificationSettings:)]) {
UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:(UIUserNotificationTypeBadge
                                                                                     |UIUserNotificationTypeSound
                                                                                     |UIUserNotificationTypeAlert) categories:nil];
[application registerUserNotificationSettings:settings];
 } 
 else {
      UIRemoteNotificationType myTypes = UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeAlert | UIRemoteNotificationTypeSound;
[application registerForRemoteNotificationTypes:myTypes];
     }

Второй шаг

Добавить ниже код Функция

 #ifdef __IPHONE_8_0
   - (void)application:(UIApplication *)application didRegisterUserNotificationSettings:(UIUserNotificationSettings *)notificationSettings
   {
  //register to receive notifications
  [application registerForRemoteNotifications];
  }

 - (void)application:(UIApplication *)application handleActionWithIdentifier:(NSString *)identifier forRemoteNotification:(NSDictionary *)userInfo completionHandler:(void(^)())completionHandler
  {
    //handle the actions
    if ([identifier isEqualToString:@"declineAction"]){
    }
   else if ([identifier isEqualToString:@"answerAction"]){
   }
}
 #endif

Вы получите токен устройства в функции ниже

 - (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken 

для подробного ответа обратитесь к этому

Надеюсь, это поможет кому-то.

Джайвант Хедкар
источник
2
-​(BOOL)application:(UIApplication​*)application​ didFinishLaunchingWithOptions:(NSDictionary​*)launchOptions​{​​​​ ​​​​ ​​​​//​Override​point​for​customization​after​application​launch.
​​​​//​Add​the​view​controller’s​view​to​the​window​and​display. ​​​​[window​addSubview:viewController.view]; ​​​​[window​makeKeyAndVisible];
NSLog(@”Registering for push notifications...”);
 [[UIApplication sharedApplication]
registerForRemoteNotificationTypes: (UIRemoteNotificationTypeAlert | UIRemoteNotificationTypeBadge |
UIRemoteNotificationTypeSound)]; 
​​​​returnYES;
}


- (void)application:(UIApplication *)app didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
}
NSString *str = [NSString stringWithFormat:@”Device Token=%@”,deviceToken];
NSLog(@”%@”, str);


- (void)application:(UIApplication *)app didFailToRegisterForRemoteNotificationsWithError:(NSError *)err {
NSString *str = [NSString stringWithFormat: @”Error: %@”, err]; NSLog(@”%@”, str);
}


- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo {
}
for (id key in userInfo) { NSLog(@”key: %@, value: %@”, key, [userInfo objectForKey:key]);
}
Сачин Кумарам
источник
2

Минимальные требования для получения токена устройства:

нет необходимости настраивать идентификатор приложения, подготовку или сертификат и т. Д., Поэтому для вызова метода делегата didRegisterForRemoteNotificationsWithDeviceToken не установлена ​​подпись кода .

Я только что создал новый проект iOS в Xcode 7 для единого представления с настройками по умолчанию и дал случайный идентификатор пакета, например com.mycompany.pushtest, который не настроен на портале разработки Apple.

С помощью следующего кода я получаю токен своего устройства в методе didRegisterForRemoteNotificationsWithDeviceToken на моем iPad с доступом в Интернет к WIFI. Мое устройство подключено, и я просто запускаю приложение прямо из xcode и просматриваю значения в консоли xcode.

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions   

{  
    if ([application respondsToSelector:@selector(registerUserNotificationSettings:)])  
    {  
        UIUserNotificationType userNotificationTypes = (UIUserNotificationTypeAlert | UIUserNotificationTypeBadge | UIUserNotificationTypeSound);  
        UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:userNotificationTypes categories:nil];  
        [application registerUserNotificationSettings:settings];  
        [application registerForRemoteNotifications];  
    }  
    else  
    {  
        // Register for Push Notifications, if running iOS version < 8  
        [application registerForRemoteNotificationTypes:(UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeAlert | UIRemoteNotificationTypeSound)];  
    }  
    return YES;  
}  


- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error {
    NSLog(@"Error: %@", error.description);
}

- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
    NSLog(@"didRegisterForRemoteNotificationsWithDeviceToken: %@", deviceToken);
}

- (void)application:(UIApplication *)application didRegisterUserNotificationSettings:(UIUserNotificationSettings *)notificationSettings {
    NSLog(@"NotificationSettings: %@", notificationSettings);
}
зиаван
источник
1

У меня есть точка зрения. Недавно я тоже столкнулся с этой проблемой. Я сделал все в соответствии с документацией, но метод делегата не вызывается. Наконец, я увидел одно сообщение, в котором говорилось об этой проблеме с сетью. Затем я сменил сеть, и она работает нормально. Так что позаботьтесь о сети еще и потому, что немногие сети могут блокировать APNS.

СЮРЕШ САНК
источник
1

После того, как вы потратили самые раздражающие 3 часа, вот шаги для решения проблемы:

  1. Удалить приложение

  2. Сбросить устройство

  3. Беги снова

Это просто сработало

ozd
источник
0

Это случилось со мной, потому что я сбросил и удалил все данные на телефоне (хотел использовать телефон разработчика). Это помешало APN вообще подключиться после повторной настройки телефона.

Я пробовал все, что угодно, но единственное, что исправило это, - это настройка телефона для работы с оператором связи с новой SIM-картой.

Эта ссылка предлагает больше подсказок относительно того, что могло происходить: https://developer.apple.com/library/ios/technotes/tn2265/_index.html

В нем говорится, что APN пытается подключиться преимущественно через оператора связи / вышки, а не через Wi-Fi. Возможно, проблема также заключалась в том, что маршрутизатор блокировал порт 5223 в сети Wi-Fi, но я сомневаюсь в этом, потому что он работал нормально накануне перед глобальным сбросом.

Филлис Сазерленд
источник
0

Для меня решающим было перейти к настройкам сборки и в разделе подписи кода, вручную выбрав идентификатор подписи кода и профиль обеспечения. По-видимому, автоматическая настройка не подобрала правильный, и поэтому приложение не было должным образом авторизовано.

Диего Ребозио
источник
0

если закрыть push-сообщение приложения,

appdidRegisterForRemoteNotificationsWithDeviceToken никогда не будет вызываться

либаи
источник
0

Также не забудьте проверить статус системы на Apple https://developer.apple.com/system-status/. .

Я пробовал все решения, опубликованные выше, но в итоге ошибка заключалась в том, что служба APNS не работала! На следующий день все снова заработало, как и ожидалось.

Кроме того, в вашем методе обратного вызова есть опечатка:

- (void)application:(UIApplication *)appdidRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken

Как указал Рупеш, правильное имя метода:

- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken

Наверное, поэтому вы так и не получили жетон в вашем случае!

Бретт
источник
На самом деле имя метода неверно, оно должно быть - (void) application: (UIApplication *) application didRegisterForRemoteNotificationsWithDeviceToken: (NSData *) deviceToken Между параметрами есть пробел
Рупеш
Спасибо, обновили ответ, включив в него свой комментарий. Уверен, что это решение проблемы OP, но мы никогда не узнаем!
Бретт
0

Вам нужно вызвать метод registerForNotifications из didFinishLaunchingWithOptions.

 func registerForNotifications(){

        if #available(iOS 10.0, *) {

            let center = UNUserNotificationCenter.current()
            center.delegate = self
            center.requestAuthorization(options:[.alert,.sound,.badge]) { (granted, error) in
                if granted{
                    UIApplication.shared.registerForRemoteNotifications()
                }else{

                    print("Notification permission denied.")

                }
            }

        } else {

            // For iOS 9 and Below
            let type: UIUserNotificationType = [.alert,.sound,.badge];
            let setting = UIUserNotificationSettings(types: type, categories: nil);
            UIApplication.shared.registerUserNotificationSettings(setting);
            UIApplication.shared.registerForRemoteNotifications()
        }
    }

 func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {

        let token = String(format: "%@", deviceToken as CVarArg).trimmingCharacters(in: CharacterSet(charactersIn: "<>")).replacingOccurrences(of: " ", with: "")
        print(token)

    }


extension AppDelegate : UNUserNotificationCenterDelegate{

    @available(iOS 10.0, *)

    func userNotificationCenter(_ center: UNUserNotificationCenter,  willPresent notification: UNNotification, withCompletionHandler   completionHandler: @escaping (_ options:   UNNotificationPresentationOptions) -> Void) {
        print("Handle push from foreground”)

        let info = ((notification.request.content.userInfo as NSDictionary).value(forKey: "aps") as! NSDictionary)
        if let type = info.value(forKey: "type") as? Int{
            if type == 0 {  

         // notification received ,Handle your notification here

            }
        }
    }

    @available(iOS 10.0, *)

    func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {

        print("Handle push from background or closed")

        let info = ((response.notification.request.content.userInfo as NSDictionary).value(forKey: "aps") as! NSDictionary)
        if let type = info.value(forKey: "type") as? Int{
            if type == 0 {   

            // notification received ,Handle your notification here
            }
        }
    }
}
Вед Раунияр
источник
0

У меня была другая проблема, когда мои обратные вызовы push-уведомлений были захвачены сторонними библиотеками, которые я включил, а именно Firebase. Эти библиотеки используют методы обратного вызова push-уведомлений для получения обратных вызовов.

Надеюсь, это кому-то поможет.

Jarora
источник