The iOS app I have been hired to build uses Batch and Rover. While I have had success in getting Batch to display an incoming notification, Rover is not even attempting to connect. I've been trying to figure this problem out for a few hours now. Here is my AppDelegate:

@import Batch; @import Rover; #import "app_appDelegate.h" #import "BT_loading.h" @implementation app_appDelegate //didFinishLaunchingWithOptions... -(BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{ [BT_debugger showIt:self message:[NSString stringWithFormat:@"didFinishLaunchingWithOptions (iOS)%@", @""]]; [Batch startWithAPIKey:@"_removed_"]; [BatchPush registerForRemoteNotifications]; [Rover setupWithApplicationToken:@"_removed_"]; [Rover registerForNotifications]; [Rover startMonitoring]; NSDictionary *notificationPayload = launchOptions[UIApplicationLaunchOptionsRemoteNotificationKey]; // notificationPayload = @{@"nickname":@"Wine List 1"}; [self appOpenDeepLink:notificationPayload]; // Register for Push Notitications, if running iOS 8 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)]; if (application.applicationState != UIApplicationStateBackground) { // Track an app open here if we launch with a push, unless // "content_available" was used to trigger a background push (introduced // in iOS 7). In that case, we skip tracking here to avoid double // counting the app-open. BOOL preBackgroundPush = ![application respondsToSelector:@selector(backgroundRefreshStatus)]; BOOL oldPushHandlerOnly = ![self respondsToSelector:@selector(application:didReceiveRemoteNotification:fetchCompletionHandler: self: showDeepLinkScreen:userInfo:)]; BOOL noPushPayload = ![launchOptions objectForKey:UIApplicationLaunchOptionsRemoteNotificationKey]; if (preBackgroundPush || oldPushHandlerOnly || noPushPayload) { //[PFAnalytics trackAppOpenedWithLaunchOptions:launchOptions]; } } } NSLog(@"Notification Payload: %@", notificationPayload); //hide status bar on launch... [[UIApplication sharedApplication] setStatusBarHidden:TRUE withAnimation:UIStatusBarAnimationNone]; //setup the window on launch... [self setWindow:[[UIWindow alloc] initWithFrame:UIScreen.mainScreen.bounds]]; [self.window setBackgroundColor:[BT_color getColorFromHexString:@"#FFFFFF"]]; //load initial storyboard, "BT_loading"... UIStoryboard *launchStoryboard = [UIStoryboard storyboardWithName:@"BT_loading" bundle:nil]; BT_viewController *launchViewController = [launchStoryboard instantiateViewControllerWithIdentifier:@"BT_loading"]; //set the rootViewController on the window to the BT_loading storyboard... self.window.rootViewController = launchViewController; [self.window makeKeyAndVisible]; //return... return TRUE; } - (void) appOpenDeepLink:(NSDictionary *) notificationPayload{ [[NSUserDefaults standardUserDefaults] removeObjectForKey:@"screenNickname"]; if(notificationPayload[@"nickname"]){ [[NSUserDefaults standardUserDefaults] setObject:notificationPayload[@"nickname"] forKey:@"screenNickname"]; [[NSUserDefaults standardUserDefaults] synchronize]; } } //when app becomes active again - (void)applicationDidBecomeActive:(UIApplication *)application{ //make sure we have an app... if([self rootApp] == nil){ [BT_debugger showIt:self message:[NSString stringWithFormat:@"applicationDidBecomeActive rootApp not available yet (iOS).%@", @""]]; }else{ [BT_debugger showIt:self message:[NSString stringWithFormat:@"applicationDidBecomeActive (iOS)%@", @""]]; //flag as visible... [self setUiIsVisible:TRUE]; //report to cloud (not all apps do this, dataURL and reportToCloudURL required)... if([[self.rootApp dataURL] length] > 1 && [[self.rootApp reportToCloudURL] length] > 1){ if(![self isRefreshing]){ [self reportToCloud]; } } //if we have a location manager... if([self rootLocationManager] != nil){ [self.rootLocationManager setUpdateCount:0]; [self.rootLocationManager.locationManager startUpdatingLocation]; } } } //promptforPushNotificationsAfterDelay... -(void)promptforPushNotificationsAfterDelay{ [BT_debugger showIt:self message:[NSString stringWithFormat:@"promptforPushNotificationsAfterDelay%@", @""]]; if([[UIApplication sharedApplication] respondsToSelector:@selector(registerUserNotificationSettings:)]){ [[UIApplication sharedApplication] registerUserNotificationSettings:[UIUserNotificationSettings settingsForTypes:(UIUserNotificationTypeSound | UIUserNotificationTypeAlert | UIUserNotificationTypeBadge) categories:nil]]; [[UIApplication sharedApplication] registerForRemoteNotifications]; } } //didRegisterForRemoteNotificationsWithDeviceToken... -(void)application:(UIApplication*)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData*)deviceToken{ [Rover didRegisterForRemoteNotificationWithDeviceToken:deviceToken]; [BT_debugger showIt:self theMessage:[NSString stringWithFormat:@"didRegisterForRemoteNotificationsWithDeviceToken (iOS): Device Token: %@", deviceToken]]; //if we have a token, and a register it... if([deviceToken length] > 1 && [[self.rootApp registerForPushURL] length] > 1){ //clean up token... NSString *useToken = [NSString stringWithFormat:@"%@", deviceToken]; useToken = [useToken stringByReplacingOccurrencesOfString:@"<"withString:@""]; useToken = [useToken stringByReplacingOccurrencesOfString:@">"withString:@""]; useToken = [useToken stringByReplacingOccurrencesOfString:@" "withString:@""]; //save it for next time... [BT_strings setPrefString:@"lastDeviceToken" valueOfPref:useToken]; //append deviceToken and deviceType to end of URL... NSString *useURL = [[self.rootApp registerForPushURL] stringByAppendingString:[NSString stringWithFormat:@"&deviceType=%@", @"ios"]]; useURL = [useURL stringByAppendingString:[NSString stringWithFormat:@"&deviceToken=%@", useToken]]; //append currentMode ("Live" or "Design") to end of URL... useURL = [useURL stringByAppendingString:[NSString stringWithFormat:@"¤tMode=%@", [self currentMode]]]; //merge environment variables in URL... useURL = [BT_strings mergeBTVariablesInString:useURL]; //escape the URL... NSString *escapedUrl = [useURL stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; //tell the BT_device to register on the server (the device class makes the URL request)... [appDelegate.rootDevice registerForPushNotifications:escapedUrl]; } } //didFailToRegisterForRemoteNotificationsWithError... -(void)application:(UIApplication*)application didFailToRegisterForRemoteNotificationsWithError:(NSError*)error{ [BT_debugger showIt:self theMessage:[NSString stringWithFormat:@"didFailToRegisterForRemoteNotificationsWithError (iOS): ERROR: %@", error]]; } //didReceiveRemoteNotification.. -(void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo{ [BT_debugger showIt:self theMessage:[NSString stringWithFormat:@"didReceiveRemoteNotification (iOS)%@", @""]]; //NSLog(@"Message ID: %@", userInfo); //NSLog(@"%@", userInfo); //(void)[Rover didReceiveRemoteNotification:userInfo fetchCompletionHandler:nil]; //don't do anything if the app is not in the foreground. iOS handles inbound APNS message when app is in the background... if(application.applicationState == UIApplicationStateActive){ NSString *alertMsg; NSString *badge; NSString *sound; //alert message... if([[userInfo objectForKey:@"aps"] objectForKey:@"alert"] != NULL){ alertMsg = [[userInfo objectForKey:@"aps"] objectForKey:@"alert"]; } //badge... if([[userInfo objectForKey:@"aps"] objectForKey:@"badge"] != NULL){ badge = [[userInfo objectForKey:@"aps"] objectForKey:@"badge"]; } //sound... if([[userInfo objectForKey:@"aps"] objectForKey:@"sound"] != NULL){ sound = [[userInfo objectForKey:@"aps"] objectForKey:@"sound"]; } //if we have a sound... if([sound length] > 1){ [self performSelector:@selector(playSoundFromPushMessage:) withObject:sound afterDelay:.1]; } //show messsage... //UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"" message:alertMsg preferredStyle:UIAlertControllerStyleAlert]; //UIAlertAction* MyAlert = [UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:^(UIAlertAction *alertTag) // { // OK button tappped. //[self dismissViewControllerAnimated:YES completion:^{ //}]; // }]; // [alert addAction:MyAlert]; //[[[[[UIApplication sharedApplication] delegate] window] rootViewController] presentViewController:alert animated:YES completion:nil]; //show messsage... UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"" message:alertMsg delegate:nil cancelButtonTitle:NSLocalizedString(@"ok", "OK") otherButtonTitles:nil]; [alert show]; ////WATCH }//in foreground... } //playSoundFromPushMessage... -(void)playSoundFromPushMessage:(NSString *)soundEffectFileName{ [BT_debugger showIt:self theMessage:[NSString stringWithFormat:@"playSoundFromPushMessage: %@", soundEffectFileName]]; NSString *theFileName = soundEffectFileName; if([BT_fileManager doesFileExistInBundle:theFileName]){ NSURL *soundFileUrl = [NSURL fileURLWithPath:[NSString stringWithFormat:@"%@/%@", [[NSBundle mainBundle] resourcePath], theFileName]]; NSError *error; AVAudioPlayer *tmpPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:soundFileUrl error:&error]; if(!error){ [tmpPlayer setNumberOfLoops:0]; [tmpPlayer prepareToPlay]; [tmpPlayer play]; }else{ [BT_debugger showIt:self theMessage:[NSString stringWithFormat:@"didReceiveRemoteNotification soundEffectPlayer ERROR: %@", [error description]]]; } } } //playSoundEffect... -(void)playSoundEffect:(NSString *)theFileName{ [BT_debugger showIt:self message:[NSString stringWithFormat:@"playSoundEffect %@", theFileName]]; if([theFileName length] > 3){ if([self.rootSoundEffectPlayer.soundEffectNames containsObject:theFileName]){ int playerIndex = (int)[self.rootSoundEffectPlayer.soundEffectNames indexOfObject:theFileName]; AVAudioPlayer *tmpPlayer = (AVAudioPlayer *)[self.rootSoundEffectPlayer.soundEffectPlayers objectAtIndex:playerIndex]; if(tmpPlayer){ [tmpPlayer play]; } }else{ [BT_debugger showIt:self message:[NSString stringWithFormat:@"playSoundInBundle:ERROR. This sound effect is not included in the list of available sounds: %@", theFileName]]; } } } - (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler { NSLog(@"Message ID: %@", userInfo); NSLog(@"%@", userInfo); (void)[Rover didReceiveRemoteNotification:userInfo fetchCompletionHandler:completionHandler]; } @end

I have been going off the instruction created by the Rover developers at: https://github.com/RoverPlatform/rover-ios

I'm probably missing something simple but guidance would definitely be appreciated.

My logcat's responses to Rover: