5

我試圖根據notification點擊打開不同的視圖控制器,但當收到push notification時,它會自動在後臺運行控制器代碼,所以當我通過應用程序圖標/通知打開應用程序時notification centre它立即加載view controller,但是當收到多個通知時,它會加載第一個通知控制器,而不管通知哪個被點擊。如何處理IOS中的多個遠程通知單擊

比方說,我已經得到了與標題「晚報」,「晨報」和 「夜」的通知,應該打開「晚報 - 視圖 - 控制器」時,「晚報」 通知被竊聽,但它加載「夜景控制器「當我去 回加載」早晨視圖控制器「,最後它加載」晚上 視圖控制器「。在發出通知之前,我在主控制器 上,然後我將應用程序移到了後臺。

當我點擊「早晨」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堆棧,這就是爲什麼您會看到三個viewController堆疊的原因。

其次,didReceiveRemoteNotification可以調用/處理在不同的狀態。 StateBackground如果應用程序在後臺,StateInactive如果用戶點擊通知中心的通知,StateForeground如果應用程序處於前臺。你添加一個支票只會推動在StateBackground viewController,這就是爲什麼你看不到任何改變時,點擊通知。

+1

這是否意味着如果我將導航代碼添加到' StateInactive'會起作用嗎? @dichen – moDev

+0

添加State Inactive檢查將處理您點擊通知時的情況。但要小心處理多次,一次用於背景,一次用於不活動。您可能需要一個標誌來檢查目標viewController是否已經顯示。 – dichen

+0

我會檢查,但更早的時候我正在使用'StateBackground',並且它不會在通知點擊時進行。我會嘗試'StateInactive'並讓你知道。我應該使用直接視圖控制器代碼還是添加觀察者並嘗試? – moDev

1

爲此,它需要在didReceiveRemoteNotification方法檢查applicationstate。這裏是代碼:

- (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:方法,即 僅在您的應用程序在前臺運行時調用,系統 在您的應用程序在前臺運行或 後臺運行時調用此方法。另外,如果啓用了遠程通知 後臺模式,則系統將啓動您的應用(或從 掛起狀態中將其喚醒),並在推送 通知到達時將其置於後臺狀態。但是,如果用戶強制退出,系統不會自動啓動您的應用程序 。在這種情況下, 用戶必須重新啓動您的應用或重新啓動設備,然後系統 嘗試再次自動啓動您的應用。

謝謝。

+0

當在後臺收到推送時,我們遇到問題。 – 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. 
     } 

    }