didReceiveRemoteNotification, когда в фоновом режиме
Подобные вопросы задавались несколько раз, но у меня происходит какая-то конкретная ситуация.
Когда мое приложение активно, и я получаю сообщение PUSH, я успешно могу проанализировать пользовательские полезные нагрузки и тому подобное.
Однако, когда мое приложение находится в фоновом режиме и приходит PUSH, пользователь должен нажать на кнопку "Просмотр / Открыть", чтобы получить didReceiveRemoteNotification
называется и didFinishLaunchingWithOptions
называется после этого.
Мне нужно, чтобы мое приложение решило, должны ли они запрашивать пользователя с помощью UIAlert, когда он находится в фоновом режиме, или подавлять push-сообщения, основываясь на некоторых локальных настройках.
Любая помощь будет оценена,
6 ответов
Ваше приложение должно обрабатывать все возможные состояния доставки push-уведомлений:
Ваше приложение было только что запущено
Ваше приложение было просто перенесено с фона на передний план
Ваше приложение уже запущено на переднем плане
Вы не можете выбрать во время доставки, какой метод представления используется для представления push-уведомления, который закодирован в самом уведомлении (необязательное предупреждение, номер значка, звук). Но так как вы, вероятно, управляете как приложением, так и полезной нагрузкой push-уведомления, вы можете указать в полезной нагрузке, было ли представление предупреждения и сообщение, уже представленное пользователю. Только в том случае, если приложение уже запущено на переднем плане, вы знаете, что пользователь запустил ваше приложение не просто с помощью оповещения или регулярно с домашнего экрана.
Вы можете сказать, было ли ваше приложение только что выведено на передний план или нет в didReceiveRemoteNotification, используя этот бит кода:
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
{
if ( application.applicationState == UIApplicationStateActive )
// app was already in the foreground
else
// app was just brought from background to foreground
...
}
Вы должны сделать несколько вещей, чтобы управлять полученными push-уведомлениями, когда приложение находится в фоновом режиме.
Во-первых, на стороне вашего сервера вы должны установить {"aps":{"content-available": 1... / $body['aps']['content-available'] =1; в полезных данных push-уведомлений.
Во-вторых, в вашем проекте XCode вам необходимо предоставить "удаленные уведомления". Это делается путем перехода к цели проекта -> возможностям, затем включению переключателя возможностей и проверки флажка удаленных уведомлений.
В-третьих, вместо использования didReceiveRemoteNotification, вы должны вызвать application:didReceiveRemoteNotification:fetchCompletionHandler:, это позволит вам выполнять задачи, которые вы хотите в фоновом режиме, в момент получения уведомления:
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler
{
if(application.applicationState == UIApplicationStateInactive) {
NSLog(@"Inactive - the user has tapped in the notification when app was closed or in background");
//do some tasks
[self manageRemoteNotification:userInfo];
completionHandler(UIBackgroundFetchResultNewData);
}
else if (application.applicationState == UIApplicationStateBackground) {
NSLog(@"application Background - notification has arrived when app was in background");
NSString* contentAvailable = [NSString stringWithFormat:@"%@", [[userInfo valueForKey:@"aps"] valueForKey:@"content-available"]];
if([contentAvailable isEqualToString:@"1"]) {
// do tasks
[self manageRemoteNotification:userInfo];
NSLog(@"content-available is equal to 1");
completionHandler(UIBackgroundFetchResultNewData);
}
}
else {
NSLog(@"application Active - notication has arrived while app was opened");
//Show an in-app banner
//do tasks
[self manageRemoteNotification:userInfo];
completionHandler(UIBackgroundFetchResultNewData);
}
}
Наконец, вы должны добавить этот тип уведомления: UIRemoteNotificationTypeNewsstandContentAvailability в настройки уведомлений при его установке.
Кроме того, если ваше приложение было закрыто, когда пришло уведомление, вы должны управлять этим в didFinishLaunchingWithOptions, и только если пользователь нажимает на push-уведомление: способ сделать это:
if (launchOptions != nil)
{
NSDictionary *dictionary = [launchOptions objectForKey:UIApplicationLaunchOptionsRemoteNotificationKey];
if (dictionary != nil)
{
NSLog(@"Launched from push notification: %@", dictionary);
[self manageRemoteNotification:dictionary];
}
}
Параметр launchOptions имеет значение!= nil, когда вы запускаете приложение, нажав на push-уведомление, если вы получите к нему доступ, нажав на значок, launchOptions будет == nil.
Надеюсь это будет полезно. Здесь: https://developer.apple.com/library/ios/documentation/iPhone/Conceptual/iPhoneOSProgrammingGuide/BackgroundExecution/BackgroundExecution.html это объясняется Apple.
Проходить content-available = 1
с вашей полезной нагрузкой, и будет вызывать didReceiveRemoteNotification
даже в фоновом режиме. например
{
"alert" : "",
"badge" : "0",
"content-available" : "1",
"sound" : ""
}
Следует иметь в виду одну вещь: когда ваше push-сообщение прибывает на iPhone пользователя и он нажимает кнопку "отмена", за исключением номера значка значка (об этом их позаботится ОС), для вашего входа не будет никакого способа. - фоновое приложение, чтобы узнать об этом событии push и предпринять любые дальнейшие действия.
Слово предупреждения
Я думаю, что логика вашего приложения основана на пользовательских данных в вашем push-уведомлении. Это не то, для чего предназначены push-уведомления. Что вы должны сделать в качестве альтернативы didbecomeactive
в вашем приложении просто спросите у своего сервера данные, которые вам нужны и которые вы все равно отправляете как полезную нагрузку, и полагайтесь на них, а не на полезную нагрузку.
Потому что в документации также говорится, что это лучшая практика. Потому что Apple в любом случае не гарантирует, что ваше push-уведомление будет получено в 100% случаев.
Важно: доставка уведомлений - "лучшее усилие", а не гарантия. Он не предназначен для доставки данных в ваше приложение, а только для уведомления пользователя о наличии новых данных.
Однако, если вы хотите получить некоторую информацию о том, был ли изменен, например, значок, не полагаясь на пользователя, открывающего приложение, щелкнув значок, вы можете сделать что-то вроде этого:
A. Вы добавляете (правильный) номер значка в полезную нагрузку push-уведомления, отправляемого вашим сервером. Например, это может выглядеть так:
{
"aps" : {
"alert" : "You got your emails.",
"badge" : 9
}
}
B. Вы постоянно отслеживаете этот номер значка в своем приложении, например, сохраняя его в NSUserDefaults
,
Затем в applicationDidBecomeActive
можно сравнить applicationIconBadgeNumber
собственностью UIApplication
с вашим ранее сохраненным количеством значков и посмотрите, был ли он увеличен или уменьшен, и сделайте некоторые обновления на основе этого.
- (void)applicationDidBecomeActive:(UIApplication *)application
{
NSNumber *badgecount = [[NSUserDefaults standardUserDefaults] objectForKey:@"badgecount"];
if (!badgecount) badgecount = @(0);
if ([UIApplication sharedApplication].applicationIconBadgeNumber != [badgecount integerValue]) {
//store the new badge count
badgecount = [NSNumber numberWithInteger:[UIApplication sharedApplication].applicationIconBadgeNumber];
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setObject:badgecount forKey:@"badgecount"];
[defaults synchronize];
// do some stuff here because it's different
}
}
Начиная с недавнего iOS - я думаю, 8 - если у вас включены удаленные уведомления в качестве фонового режима, один трюк состоит в том, чтобы отследить, входите ли вы на передний план в качестве флага.
@interface AppDelegate ()
@property (assign, atomic, getter=isEnteringForeground) BOOL enteringForeground;
@end
- (void) applicationWillEnterForeground: (UIApplication *) application
{
self.enteringForeground = YES;
}
- (void) applicationDidBecomeActive: (UIApplication *) application
{
self.enteringForeground = NO;
}
- (void) application: (UIApplication *) application didReceiveRemoteNotification: (NSDictionary *) userInfo fetchCompletionHandler: (void (^) (UIBackgroundFetchResult)) completionHandler
{
const BOOL launchedFromBackground = !(application.applicationState == UIApplicationStateActive);
const BOOL enteringForeground = self.enteringForeground;
if (launchedFromBackground && enteringForeground) {
// The user clicked a push while the app was in the BG
}
}