Подтвердить что ты не робот

Обработка уведомлений Push, когда приложение не выполняется

Когда мое приложение работает не и получает Push-уведомление, если я нажимаю на это уведомление, приложение запускается - но тогда он не запрашивает у пользователя установленный Alert-View я спрашивая их, хотят ли они просматривать содержимое Уведомления или нет. Он просто запускается и сидит там.

Push-уведомления работают отлично, когда приложение работает - либо в качестве активного приложения, либо в фоновом режиме, но ничего не работает правильно, когда приложение не работает.

Я попытался вывести NSDictionary launchOptions в application: didFinishLaunchingWithOptions:, чтобы увидеть, какую нагрузку он приносит, но он появляется как "(null)". Таким образом, он в основном не содержит ничего, что не имеет смысла, не должно ли оно содержать нагрузку на уведомление?

У кого-нибудь есть идеи, как заставить Push Notifications работать, когда они приходят, когда приложение не работает?

EDIT: здесь код, который я использую в application: didReceiveRemoteNotification, чтобы посмотреть, что:

if (UIApplicationStateBackground) {

    NSLog(@"===========================");
    NSLog(@"App was in BACKGROUND...");
}
else if (UIApplicationStateActive == TRUE) {
    NSLog(@"===========================");
    NSLog(@"App was ACTIVE");
}
else {
    [[UIApplication sharedApplication] setApplicationIconBadgeNumber: 99]; 
    UIAlertView *BOOM = [[UIAlertView alloc] initWithTitle:@"BOOM"
                                                   message:@"app was INACTIVE"
                                                  delegate:self
                                         cancelButtonTitle:@"a-ha!"
                                         otherButtonTitles:nil];
    [BOOM show];
    NSLog(@"App was NOT ACTIVE");
}

Итак, это должно заботиться обо всех состояниях приложения, но это не так. Push-уведомления работают только при запуске приложения - либо в фоновом режиме, либо на переднем плане...

=============================================== =

UPDATE/EDIT # 2: в соответствии с предложением "@dianz" (ниже,) я изменил код моего application: didFinishLaunchingWithOptions, чтобы включить следующее:

UILocalNotification *localNotif = [launchOptions objectForKey:UIApplicationLaunchOptionsRemoteNotificationKey];
if (localNotif) {
    NSString *json = [localNotif valueForKey:@"data"]; 

    UIAlertView *bam = [[UIAlertView alloc] initWithTitle:@"appDidFinishWithOptions"
                                                  message:json   
                                                 delegate:self
                                        cancelButtonTitle:@"cool"
                                        otherButtonTitles:nil];
    [bam show];

}

Это делает поле AlertView отображаемым, но, похоже, нет никакой полезной нагрузки: заголовок AlertView появляется ( "appDidFinishWithOptions" ), но json NSString появляется EMPTY... Будет держать настройку...

======================

EDIT # 3 - теперь он работает почти на 100%
Итак, в didFinishLaunchingWithOptions:

UILocalNotification *localNotif = [launchOptions objectForKey:UIApplicationLaunchOptionsRemoteNotificationKey];
    if (localNotif) {
        // Grab the pushKey:
        pushKey = [localNotif valueForKey:@"pushKey"];
        // "pushKey" is an NSString declared globally
        // The "pushKey" in the "valueForKey" statement is part of my custom JSON Push Notification pay-load.
        // The value of pushKey will always be a String, which will be the name of the 
        // screen I want the App to navigate to. So when a Notification arrives, I go
        // through an IF statement and say "if pushKey='specials' then push the                                      
        // specialsViewController on, etc.

        // Here, I parse the "alert" portion of my JSON Push-Notification:
        NSDictionary *tempDict = [localNotif valueForKey:@"aps"];
        NSString *pushMessage = [tempDict valueForKey:@"alert"];


        // Finally, ask user if they wanna see the Push Notification or Cancel it:
        UIAlertView *bam = [[UIAlertView alloc] initWithTitle:@"(from appDidFinishWithOptions)"
                                                      message:pushMessage  
                                                     delegate:self
                                            cancelButtonTitle:@"Cancel"
                                            otherButtonTitles:@"View Info", nil];
        [bam show];

    }

Затем я реализую метод alertView: clickedButtonAtIndex, чтобы узнать, что пользователь выбрал в AlertView, и действуйте соответственно.

Это, наряду с логикой didReceiveRemoteNotification, отлично работает.

ОДНАКО... когда приложение не запущено, и я отправляю ему Push-уведомление, если я НЕ нажимаю на предупреждающее сообщение Push Notification, как только оно поступит, и вместо этого ожидайте его исчезновения (что происходит после например, 3-4 секунды), а затем я нажимаю значок приложения, на котором теперь есть BADGE из 1 - приложение запускается, но я не получаю сообщение Push Notification вообще при его запуске. Он просто сидит там.

Угадайте, мне нужно понять, что перестановка следующая...

4b9b3361

Ответ 1

Если ваше приложение не запущено или убито, и вы нажимаете на push-уведомление, эта функция будет запускаться;

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

поэтому вы должны справиться с этим,

UILocalNotification *localNotif = [launchOptions objectForKey:UIApplicationLaunchOptionsRemoteNotificationKey];
if (localNotif) {
    NSString *json = [localNotif valueForKey:@"data"];
    // Parse your string to dictionary
}

Ответ 2

Лучше, если вы переопределите didReceiveRemoteNotification Здесь вы идете

NSDictionary * pushNotificationPayload = [launchOptions valueForKey:UIApplicationLaunchOptionsRemoteNotificationKey];
if(pushNotificationPayload) {
    [self application:application didReceiveRemoteNotification:pushNotificationPayload];
}

Это снова вызовет метод didReceiveRemoteNotification, и ваш код push notification будет выполняться так же, как и во время выполнения приложения.

Ответ 3

Я попробовал ответить @dianz, это не сработало для меня, но я получил помощь от ответа.

В моем случае

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

NSDictionary *apnsBody = [launchOptions objectForKey:UIApplicationLaunchOptionsRemoteNotificationKey];
if (apnsBody) {
    // Do your code with apnsBody
}

Ответ 4

Хотя на это был дан ответ, ни один из предоставленных ответов не работал правильно. Вот моя реализация, что я смог работать.

Этот код находится в application:didFinishLaunchingWithOptions:

Swift:

if let options = launchOptions, notification = options[UIApplicationLaunchOptionsRemoteNotificationKey] as? [NSObject : AnyObject] {
    // NOTE: (Kyle Begeman) May 19, 2016 - There is an issue with iOS instantiating the UIWindow object. Making this call without
    // a delay will cause window to be nil, thus preventing us from constructing the application and assigning it to the window.
    Quark.runAfterDelay(seconds: 0.001, after: {
        self.application(application, didReceiveRemoteNotification: notification)
    })
}

Objective-C:

if (launchOptions[UIApplicationLaunchOptionsRemoteNotificationKey]) {
    [self application:application didReceiveRemoteNotification:launchOptions[UIApplicationLaunchOptionsRemoteNotificationKey]];
}

Несколько примечаний:

  • Возможно, из-за распределения очередей IOS, при запуске приложения после его уничтожения корневой объект UIApplication.sharedApplication().window равен нулю. Добавление 1 миллисекундной задержки устранило эту проблему. Не тестировал это в Objective-C

  • Для того, чтобы избежать конфликтов типа, требуется выполнить [NSObject: AnyObject], но я не экспериментировал с этим; держите это в своем уме при реализации в своем собственном проекте. Objective-C не требует этого.

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

Ответ 5

Попробуйте перейти к методу didReceiveRemoteNotification и обработать его там. Там вы можете проверить состояния приложения, выполнив условия для applicationState, например, проверив, есть ли он UIApplicationStateActive или другие.

Ответ 6

У меня была та же проблема, но я, наконец, смог обработать Push Notification, когда он неактивен (не работает), используя расширение службы уведомлений. Это решение было рекомендовано Apple Team Support, и только для iOS 10 я реализовал его, и он работает хорошо! Я оставляю ссылку:

https://developer.apple.com/library/content/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/ModifyingNotifications.html

Это процедура:

  • Создайте новое расширение службы уведомлений для вашего приложения. Откройте проект и нажмите "Файл" - "Создать" и выберите в разделе "iOS" опцию "Расширение службы уведомлений". Введите имя расширения и необходимую информацию. После этого Xcode добавит два файла с языком Objective C:.h и .m.

ПРИМЕЧАНИЕ. Учтите, что вы будете использовать три идентификатора: 1) Идентификатор вашего приложения (у вас уже есть)2) Идентификатор вашего расширения (вы создадите)3) Идентификатор для группы приложений. (вы создадите)

  1. Необходимо включить Группы приложений, чтобы создать ресурс, в котором вы можете сохранять и читать информацию для своего приложения и расширения. Нажмите "Показать навигатор проекта". В список целей выберите свой основной проект. Затем нажмите "Возможности" и включите опцию "Группы приложений" . Добавьте идентификатор группы приложений для определения общих ресурсов. Вы должны сделать тот же шаг для целевого расширения, которое вы создали (выберите цель расширения - Возможности - Включить в "Группы приложений" - Добавить тот же идентификатор для группы приложений)

  2. Вам следует добавить идентификатор для вашего расширения на сайт разработчика Apple для определения расширения службы уведомлений, также вам необходимо создать новые предварительные профили (Development, AdHoc и/или Production) и связать их с новым временным Профили.

  3. В обоих идентификаторах (приложение и расширение) вы должны отредактировать их и включить службу "Группы приложений" в обоих из них. Вы должны добавить группу "Идентификатор для приложения" в Службы групп приложений.

ПРИМЕЧАНИЕ. Идентификатор приложения и идентификатора для расширения ДОЛЖЕН ИМЕТЬ ИДЕНТИФИКАТОР ДЛЯ ГРУППЫ APP.

  1. Загрузите новый предварительный профиль на Xcode и свяжите его с расширением службы уведомлений. Пожалуйста, убедитесь, что с ними все в порядке.

  2. После этого в "Возможности" вашего приложения и расширения откройте раздел "Группы приложений" и обновите их. Три шага - 1) Добавьте права приложений в свой файл прав, 2) Приложите функцию "Группы приложений" к вашему идентификатору приложения и 3) "Добавить группы приложений" в свой идентификатор приложения - должны быть проверены.

  3. Вернитесь в навигатор проекта и выберите папку расширения. Откройте файл .m. Вы увидите метод, называемый requestReceiveNotificationRequest: (UNNotificationRequest *). В этот метод вы создадите различные NSUserDefaults с именем SuiteName, в точности равным идентификатору для группы приложений, например:

    NSUserDefaults * defaultsGroup = [[NSUserDefaults alloc] initWithSuiteName: @ "идентификатор для группы приложений" ];

  4. В этот же метод получите тело уведомления и сохраните его в NSMutableArray, а затем сохраните его в ресурсах общего доступа. Вот так:

- (void)didReceiveNotificationRequest:(UNNotificationRequest *)request withContentHandler:(void (^)(UNNotificationContent * _Nonnull))contentHandler{
    self.contentHandler = contentHandler;
    self.bestAttemptContent = [request.content mutableCopy];

    NSMutableArray *notifications = [NSMutableArray new];
    NSUserDefaults *defaultsGroup = [[NSUserDefaults alloc] initWithSuiteName: @"Identifier for app group"];
    notifications = [[defaultsGroup objectForKey:@"notifications"] mutableCopy];
    if (notifications != nil){
        [notifications addObject:self.bestAttemptContent.userInfo];
    }else{
        notifications = [NSMutableArray new];
        [notifications addObject:self.bestAttemptContent.userInfo];
    }
    [defaultsGroup setObject:notifications forKey:@"notifications"];    
}
  1. Наконец, в App Delegate вашего основного проекта, в вашем методе didFinishLaunchingWithOptions, восстановите Array в ресурсах общего доступа с помощью этого кода:
NSUserDefaults *defaultsGroup = [[NSUserDefaults alloc] initWithSuiteName: @"Identifier for app group"];
NSMutableArray *notifications = [[defaultsGroup objectForKey:@"notifications"] mutableCopy];
  1. Наслаждайтесь этим!

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

Ответ 7

попробуйте это

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];

    // Override point for customization after application launch.
    self.window.backgroundColor = [UIColor whiteColor];
    [self.window makeKeyAndVisible];

    //register notifications
    if([application respondsToSelector:@selector(registerUserNotificationSettings:)]) // ios 8
    {
        [application registerUserNotificationSettings:[UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeAlert|UIUserNotificationTypeBadge|UIUserNotificationTypeSound categories:nil]];
        [application registerForRemoteNotifications];
    }
    else // ios 7
    {
        [[UIApplication sharedApplication] registerForRemoteNotificationTypes:UIRemoteNotificationTypeSound | UIRemoteNotificationTypeAlert | UIRemoteNotificationTypeBadge];
    }

    // open app from a notification
    NSDictionary *notification = [launchOptions objectForKey:UIApplicationLaunchOptionsRemoteNotificationKey];

    if (notification) 
    {
        //your alert should be here
    }

    // Set icon badge number to zero
    application.applicationIconBadgeNumber = 0;

    return YES;
}

Ответ 8

Swift 3 и xCode 8.3.2:

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
    // your code here

    // Check if app was not running in background and user taps on Push Notification
    // This will perform your code in didReceiveRemoteNotification where you should handle different application states
    if let options = launchOptions, let notification = options[UIApplicationLaunchOptionsKey.remoteNotification] as? [NSObject : AnyObject] {
        self.application(application, didReceiveRemoteNotification: notification)
    }

    return true
}