5

Я пытаюсь открыть разные контроллеры представлений на основе notification, но при получении push notification он автоматически запускает код контроллера в фоновом режиме, поэтому, когда я открываю приложение через значок приложения/уведомление из notification centre сразу же загружает view controller, но при получении нескольких уведомлений он загружает первый контроллер уведомлений независимо от того, какое уведомление было прослушировано.Как работать с несколькими удаленными уведомлениями в IOS

Скажем, я получил уведомление с названиями «Вечер», «Утро» и «Ночь», он должен открыть «Вечерний View Controller», когда «Вечер» уведомление прослушивается, но он загружает «Night View Контроллер ", когда я иду назад он загружает« Morning View Controller »и, наконец, загружает« Вечер View Controller ». До того, как появилось уведомление, я был на Main Controller , а затем переместил приложение в фоновый режим.

Когда я нажимаю на «Утро» notification, он ничего не делает сейчас.

Раньше я пытался использовать addObserver, но результат такой же, поэтому я перехожу к делегату приложения.

Вот код приложения делегат

@interface AppDelegate() 

@end 


@implementation AppDelegate 

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

    [[UIApplication sharedApplication]setMinimumBackgroundFetchInterval:UIApplicationBackgroundFetchIntervalMinimum]; 

    // Override point for customization after application launch. 
    // Register for Push Notitications, if running iOS 8 or More 

    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 before iOS 8 

     [application registerForRemoteNotificationTypes:(UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeAlert | UIRemoteNotificationTypeSound)]; 
    } 

    [application setStatusBarHidden:YES]; 

    return YES; 
} 

// Handle remote notification registration. 
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken { 

    NSLog(@"Device Token %@",[self stringWithDeviceToken:deviceToken]); 

    [[NSUserDefaults standardUserDefaults]setObject:[self stringWithDeviceToken:deviceToken] forKey:@"registration_id"]; 
    [[NSUserDefaults standardUserDefaults] synchronize]; 
} 

- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)err { 

    NSLog(@"Error in registration. Error: %@", err); 
} 


- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler { 

    NSDictionary *alertInfo = (NSDictionary *) userInfo[@"aps"][@"alert"]; 
    NSLog(@"%@",alertInfo); 

    NSString *alertID = [userInfo valueForKey:@"alertid"]; 


    if (application.applicationState == UIApplicationStateBackground) { 

     [UIApplication sharedApplication].applicationIconBadgeNumber = [UIApplication sharedApplication].applicationIconBadgeNumber + 1; 

     NSLog(@"Background Mode"); 
     NSString *title = alertInfo[@"title"]; 

     [self openViewController:title]; 
    } 

    if(application.applicationState == UIApplicationStateActive){ 

     NSLog(@"Active Mode"); 
      } 

    completionHandler(UIBackgroundFetchResultNewData); 
    [self performSelector:@selector(sendAckRequest:) withObject:alertID]; 
} 


- (void)openViewController:(NSString *)notificationTitle{ 

    NSDictionary * userDict = [[NSUserDefaults standardUserDefaults] objectForKey:@"loginUser"]; 

    if([notificationTitle isEqualToString:@"Exercise"]){ 

    UINavigationController *navigationController = (UINavigationController *)self.window.rootViewController; 

    UIStoryboard *mainStoryboard = [UIStoryboard storyboardWithName:@"Main" bundle: nil]; 

    Excercise *excerciseController = (Excercise*)[mainStoryboard instantiateViewControllerWithIdentifier: @"Excercise"];  
    [navigationController pushViewController:excerciseController animated:YES]; 
    //[navigationController presentViewController:excerciseController animated:YES completion:nil]; 

    }else if([notificationTitle isEqualToString:@"Weight"]){ 

     UINavigationController *navigationController = (UINavigationController *)self.window.rootViewController; 

     UIStoryboard *mainStoryboard = [UIStoryboard storyboardWithName:@"Main" bundle: nil]; 

     Weight *weightController = (Weight*)[mainStoryboard instantiateViewControllerWithIdentifier: @"Weight"];   
     [navigationController pushViewController:weightController animated:YES]; 

     //[navigationController presentViewController:weightController animated:YES completion:nil]; 

    }else if([notificationTitle isEqualToString:@"MCQ"]){ 

     UINavigationController *navigationController = (UINavigationController *)self.window.rootViewController; 

     UIStoryboard *mainStoryboard = [UIStoryboard storyboardWithName:@"Main" bundle: nil]; 

     QuestionOfTheDay *questionController = (QuestionOfTheDay*)[mainStoryboard instantiateViewControllerWithIdentifier: @"QuestionOfTheDay"]; 
     questionController.self.dictUser = userDict; 
     [navigationController pushViewController:questionController animated:YES] 
    } 
} 

-(void)sendAckRequest:(NSString *)alertID { 

    AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager]; 
    manager.requestSerializer = [AFHTTPRequestSerializer serializer]; 
    manager.responseSerializer = [AFHTTPResponseSerializer serializer]; 

    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; 

    NSString *userID =[[defaults objectForKey:@"loginUser"]objectForKey:@"UserId"]; 
    NSString *serverRegistrationID = [defaults objectForKey:@"server_registration_id"]; 

    NSDateFormatter *dateFormatter = [[NSDateFormatter alloc]init]; 

    [dateFormatter setDateFormat:@"yyyy-MM-dd'T'HH:mm:ss"]; 
    NSString *currentDateString = [dateFormatter stringFromDate:[NSDate date]]; 

    //NSDate *currentDate = [dateFormatter dateFromString:currentDateString]; 

    //NSDictionary *parameter = @{@"ReminderDateTime":currentDateString}; 

    NSString *url = [NSString stringWithFormat:@"%@%@/%@/%@/?ReminderDateTime=%@",sendNotificationAck,userID,serverRegistrationID,alertID,currentDateString]; 


    NSLog(@"url: %@",url); 

    [manager GET:url parameters:nil success:^(AFHTTPRequestOperation * _Nonnull operation, id _Nonnull responseObject) { 

     if(operation.response.statusCode == 200) 
      NSLog(@"Notification Acknowledged"); 
     else 
      NSLog(@"Notification failed to acknowledge"); 

    } failure:^(AFHTTPRequestOperation * _Nullable operation, NSError * _Nonnull error) { 

     NSLog(@"error: %@",[error localizedDescription]); 
    }]; 
} 

- (NSString *)stringWithDeviceToken:(NSData *)deviceToken { 

    const char *data = [deviceToken bytes]; 

    NSMutableString *token = [NSMutableString string]; 

    for (int i = 0; i < [deviceToken length]; i++) { 

     [token appendFormat:@"%02.2hhX", data[i]]; 
    } 

    return token; 
} 

- (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. 

    if([UIApplication sharedApplication].applicationIconBadgeNumber!=0) 
    [UIApplication sharedApplication].applicationIconBadgeNumber = [UIApplication sharedApplication].applicationIconBadgeNumber - 1; 
} 

@end 
+0

Буферные значения можно использовать для обработки. – Santo

ответ

4

Во-первых, ваш фоновый режим Remote Notification включен, поэтому уведомления обрабатываются в фоновом режиме. Теперь ошибка заключается в том, что всякий раз, когда приходит уведомление, вы нажимаете viewController на стек viewController, поэтому вы видите три элемента управления viewControllers.

Во-вторых, didReceiveRemoteNotification можно назвать/обрабатывать в разных состояниях. StateBackground если приложение находится в фоновом режиме, StateInactive, если пользователь нажимает уведомление из Центра уведомлений, StateForeground, если приложение находится на переднем плане. Вы добавляете чек, только нажмите viewController в StateBackground, поэтому вы не видите никаких изменений при нажатии уведомления.

+1

Означает ли это, если я добавлю навигационный код в' StateInactive' будет работать? @dichen – moDev

+0

Добавить StateInactive check будет обрабатывать этот случай при нажатии уведомления. Но будьте осторожны, чтобы обращаться с ним несколько раз, один раз для фона и один раз для неактивного. Возможно, вам понадобится флаг, который проверяет, отображается ли объект viewController назначения или нет. – dichen

+0

Я проверю это, но раньше я использовал 'StateBackground', и это не происходило, когда уведомление постучало. Я попробую с 'StateInactive' и дам вам знать. Должен ли я использовать код контроллера прямого просмотра или добавить наблюдателя и попробовать? – moDev

1

Для этого необходимо проверить applicationstate в didReceiveRemoteNotification метода. Вот код:

- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler { 

//recieved notification 
    if (application.applicationState == UIApplicationStateActive){ 
     // app was already in the foreground 
     UIViewController* topViewController = [self.navigationController topViewController]; 
     if ([topViewController isKindOfClass:[HomeVC class]]) { 
      [[NSNotificationCenter defaultCenter] postNotificationName:@"getUpdatedServiceData" object:nil]; 
     } 
    } 
} 

в HomeVC Вам нужно создать notificate getUpdatedServiceData и в рамках этого метода толчок вид контроллера.

* примечание -

Используйте этот метод для обработки входящих удаленных уведомлений для вашего приложения. В отличие от приложения: didReceiveRemoteNotification: метод, который является , вызывается только тогда, когда ваше приложение работает на переднем плане, система вызывает этот метод, когда ваше приложение работает на переднем плане или . Кроме того, если вы включили фоновый режим удаленных уведомлений , система запускает ваше приложение (или пробуждает его из приостановленного состояния ) и помещает его в фоновое состояние, когда приходит сообщение push . Однако система автоматически не запускает ваше приложение, если у пользователя есть принудительное завершение. В этой ситуации пользователь должен перезапустить приложение или перезагрузить устройство до того, как система попытается снова запустить приложение.

Спасибо.

+0

У нас есть проблемы, когда push получен в фоновом режиме. – moDev

+0

На переднем плане мы показываем 'UIAlertView', поэтому это не проблема для нас – moDev

+0

Это не работает – moDev

0

Я не пробовал это, но я думаю, что этот метод делегирования приложения решит вашу проблему.

application:handleActionWithIdentifier:forRemoteNotification:withResponseInfo:completionHandler:

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

Параметр словаря userInfo содержит информацию, связанную с удаленным уведомлением.

Для получения дополнительной информации см яблочного документации

https://developer.apple.com/library/ios//documentation/UIKit/Reference/UIApplicationDelegate_Protocol/index.html#//apple_ref/occ/intfm/UIApplicationDelegate/application:handleActionWithIdentifier:forRemoteNotification:withResponseInfo:completionHandler:

+0

Этот метод доступен с 8.0 года, наша минимальная версия 7.0 – moDev

0

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

Так, чтобы решить проблему вы должны

  1. Проверить и решить для последнего или повернутого уведомления или которые когда-либо иметь смысл, чтобы показать в - (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler или - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions в зависимости от состояния приложения этих делегатов дозвонились для уведомления
  2. Проверить уже показанный viewController при запуске приложения. Если да, удалите их и покажите последнее или прослушанное уведомление.

    UINavigationController *navigationController = (UINavigationController *)self.window.rootViewController; 
    
    UIViewController* topViewController = [navigationController visibleViewController]; 
    
    if ([topViewController isKindOfClass:[Excercise class]]) 
    { 
        [topViewController dismissViewControllerAnimated:NO completion:nil]; 
    } 
    

// запуск соответствующего уведомления VC после.

0

Вы можете использовать разные приложения.

func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject], fetchCompletionHandler completionHandler: (UIBackgroundFetchResult) -> Void) 
    { 
     if (application.applicationState == UIApplicationState.Active) 
     { 
      // App is foreground and notification is recieved, 
      // Show a alert. 
     } 
     else if(application.applicationState == UIApplicationState.Background) 
     { 
      // App is in background and notification is received, 
      // You can fetch required data here don't do anything with UI. 
     } 
     else if(application.applicationState == UIApplicationState.Inactive) 
     { 
      // App came in foreground by used clicking on notification, 
      // Use userinfo for redirecting to specific view controller. 
     } 

    }