Обработка уведомлений 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 вообще при его запуске. Он просто сидит там.
Угадайте, мне нужно понять, что перестановка следующая...
Ответы
Ответ 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) Идентификатор для группы приложений. (вы создадите)
-
Необходимо включить Группы приложений, чтобы создать ресурс, в котором вы можете сохранять и читать информацию для своего приложения и расширения. Нажмите "Показать навигатор проекта". В список целей выберите свой основной проект. Затем нажмите "Возможности" и включите опцию "Группы приложений" . Добавьте идентификатор группы приложений для определения общих ресурсов. Вы должны сделать тот же шаг для целевого расширения, которое вы создали (выберите цель расширения - Возможности - Включить в "Группы приложений" - Добавить тот же идентификатор для группы приложений)
-
Вам следует добавить идентификатор для вашего расширения на сайт разработчика Apple для определения расширения службы уведомлений, также вам необходимо создать новые предварительные профили (Development, AdHoc и/или Production) и связать их с новым временным Профили.
-
В обоих идентификаторах (приложение и расширение) вы должны отредактировать их и включить службу "Группы приложений" в обоих из них. Вы должны добавить группу "Идентификатор для приложения" в Службы групп приложений.
ПРИМЕЧАНИЕ. Идентификатор приложения и идентификатора для расширения ДОЛЖЕН ИМЕТЬ ИДЕНТИФИКАТОР ДЛЯ ГРУППЫ APP.
-
Загрузите новый предварительный профиль на Xcode и свяжите его с расширением службы уведомлений. Пожалуйста, убедитесь, что с ними все в порядке.
-
После этого в "Возможности" вашего приложения и расширения откройте раздел "Группы приложений" и обновите их. Три шага - 1) Добавьте права приложений в свой файл прав, 2) Приложите функцию "Группы приложений" к вашему идентификатору приложения и 3) "Добавить группы приложений" в свой идентификатор приложения - должны быть проверены.
-
Вернитесь в навигатор проекта и выберите папку расширения. Откройте файл .m. Вы увидите метод, называемый requestReceiveNotificationRequest: (UNNotificationRequest *). В этот метод вы создадите различные NSUserDefaults с именем SuiteName, в точности равным идентификатору для группы приложений, например:
NSUserDefaults * defaultsGroup = [[NSUserDefaults alloc] initWithSuiteName: @ "идентификатор для группы приложений" ];
-
В этот же метод получите тело уведомления и сохраните его в 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"];
}
- Наконец, в App Delegate вашего основного проекта, в вашем методе didFinishLaunchingWithOptions, восстановите Array в ресурсах общего доступа с помощью этого кода:
NSUserDefaults *defaultsGroup = [[NSUserDefaults alloc] initWithSuiteName: @"Identifier for app group"];
NSMutableArray *notifications = [[defaultsGroup objectForKey:@"notifications"] mutableCopy];
- Наслаждайтесь этим!
Я надеюсь, что с каждым шагом будет ясно. Я собираюсь написать сообщение для реализации этого решения с изображениями на моей странице. Еще один момент, который вы должны учитывать, это не работает с уведомлением о молчании.
Ответ 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
}