iOS:针对特定View Controller类的didReceiveRemoteNotification

时间:2014-07-27 22:06:08

标签: ios objective-c push-notification parse-platform apple-push-notifications

场景 =我有一个具有消息功能的应用。在发送消息时,还将向接收者的电话发送推送通知。我希望用户每当用户接收带有“警报”(在屏幕上显示消息),“徽章”(红色圆圈中的应用程序图标徽章编号)和“声音”(在推送时播放的声音)的推送通知查看Instant Messenger屏幕 - ,当Instant Messenger屏幕上的用户 IS 时,我希望用户收到“徽章” “和”声音“

为什么我不想在Instant Messenger屏幕上发送“提醒”? 因为当消息加载到tableView时,即时消息屏幕已经向用户显示消息。当他们不得不一直点击它以便在屏幕上再次阅读时,我为什么要将IM推送到他们的屏幕上并显示“警报”?没有意义。

为什么我只希望用户在IM屏幕上收到“徽章”? 这是因为我的应用程序不断检查要增加的应用程序的徽章计数,以便在引发应用程序徽章时刷新表格视图。我还希望播放“声音”以通过声音通知用户推送已经到达他们的手机。

需要注意的事项 =我的应用程序基于包含Tab栏控制器的架构,该控制器包含每个选项卡的导航控制器。如果这有所不同。

编辑 - 总结和简化的问题。

你是怎么做到的?...(不是真正的代码)

-(void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo {

    if (isOnInstantMessagingScreen) {

        //Disable Push "Alert" messages
        //Enable Push "Badge"
        //Enable Push "Sound"
    }

    else {

        //Enable Push "Alert" messages
        //Enable Push "Badge"
        //Enable Push "Sound"
    }

3 个答案:

答案 0 :(得分:5)

虽然应用程序已打开,但Apple会使通知静音,因此您有责任显示警报或播放声音。这是个好消息,因为您不必担心取消注册通知类型。

要回答第一个问题,您可以通过

从应用程序委托访问topMostViewController
UIViewController *topMostViewController = [(UINavigationController *)[self.tabBarController selectedViewController] topViewController];

我假设您已将tabBarController设置为属性

@property (strong, nonatomic) UITabBarController *tabBarController;

如果您有多个标签,selectedViewController可以是moreViewController,那么您可以尝试

UIViewController *topMostViewController = [(UINavigationController *)[[self.tabBarController viewControllers] objectAtIndex:[self.tabBarController selectedIndex]] topViewController];

然后您可以指定布尔值 - 其中MessageScreenViewController是您的消息控制器

isOnInstantMessagingScreen = [topMostViewController isKindOfClass:[MessageScreenViewController class]];

您需要知道应用程序是否在前台才能显示UIAlertView并播放声音

if([application applicationState] == UIApplicationStateActive){}

如果用户不在讯息屏幕上,您将需要显示通知并播放声音

if(!isOnInstantMessagingScreen){
   [PFPush handlePush:userInfo]; // Display alert - can also be UIAlertView

   //Play sound
   NSURL* musicFile = [NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"Notification" ofType:@"wav"]];
        AVAudioPlayer *notify  = [[AVAudioPlayer alloc] initWithContentsOfURL:musicFile  error:nil];
        [notify play];

    //Perhaps increment badge number
    [[UIApplication sharedApplication] setApplicationIconBadgeNumber: +1];
}

这对你有帮助吗?

最终解决方案可能类似于(未经测试):

-(void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
{
    //The application is currently in the foreground
    if([application applicationState] == UIApplicationStateActive){
        UIViewController *topMostViewController = [(UINavigationController *)[self.tabBarController selectedViewController] topViewController];
        BOOL isOnInstantMessagingScreen = [topMostViewController isKindOfClass:[MessageScreenViewController class]];

        if(!isOnInstantMessagingScreen){
            UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Notification" message:[[userInfo objectForKey:@"aps"] objectForKey:@"alert"] delegate:self cancelButtonTitle:@"OK" otherButtonTitles:@"View", nil];
            alert.tag = 1;
            [alert show];

            //Play sound
            NSURL* musicFile = [NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"Notification" ofType:@"wav"]];
            AVAudioPlayer *notify  = [[AVAudioPlayer alloc] initWithContentsOfURL:musicFile  error:nil];
            [notify play];

            //Perhaps increment badge number
            [[UIApplication sharedApplication] setApplicationIconBadgeNumber: +1];
        }
    } else {
        //Application is in background - When the notification is clicked on, we will get here
        [[UIApplication sharedApplication] setApplicationIconBadgeNumber: 0]; //Clear notification as we have clicked it, potentially could also be -1 to decrement?

        UINavigationController *navigationController = (UINavigationController *)[self.tabBarController.viewControllers objectAtIndex:2];
        BOOL isOnInstantMessagingScreen = [[navigationController topViewController] isKindOfClass:[MessageScreenViewController class]];

        //Perhaps we want to navigate to the message controller screen
        if(!isOnInstantMessagingScreen){

            //Somehow push the messaging screen onto the UINavigationController
            //This could be done here by alloc and initing the view controller
            MessageScreenViewController *viewContoller = [[MessageScreenViewController alloc] init];
            [navigationController pushViewController:viewContoller animated:YES];

            //Or perhaps by calling a function on the rootView of the UINavigationController
            RootViewController *rootViewController = (RootViewController *)[navigationController.viewControllers objectAtIndex:0];
            [rootViewController loadMessageScreenWithUserInfo:userInfo];

            //Show tab
            [self.tabBarController setSelectedIndex:2]; // Index of NavigationController which will contain the MessageViewController
        }
    }
}

答案 1 :(得分:1)

我认为你不需要做所有工作来注册和取消注册不同的通知。我打算走出困境,并假设解析库负责显示UIAlertView。

当您的应用处于有效状态时,您会在appDelegate方法中获得回调

(void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo

每当收到推送通知时。在这种情况下,系统不会显示警报。我的猜测是Parse有你的实现方法,并对显示alertView的解析框架进行了某种方法调用。

作为参考,如果应用程序未激活并且响应推送通知而启动,则将调用ApplicationDidFinishLaunchingWithOptions,而推送通知的内容将位于启动选项字典中。

只需注册所有三种通知,然后处理这两种方法中的通知。

答案 2 :(得分:1)

当您收到推送时,无论是什么代码都会占用您的屏幕didReceiveRemoteNotification,所以请添加支票,例如:

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

if ([navController.visibleViewController isKindOfClass:[IMViewController class]]) {
    //user is on IM screen
}