哎,软件进入测试阶段了,设计这边来了一个新的需求,远程推送来的消息不管是在程序激活状态还是后台休眠状态,以及程序没有启动的状态,点击推送来的消息都要跳转到消息中心页面。
问题与难点
但是问题又来了。项目中有些地方是没有导航栏的也就是默写试图控制器是present出来的并不是push出来的。然后在程序处于登陆页面的时候由于用户没有登陆所以点击推送消息是不能进行跳转的,所以这时候就要分类讨论了。因为最终都要跳转到消息中心页面(MessageCenterViewController消息中西页面),但是消息中心页面是有导航栏的。(最终逻辑见代码pushToViewController方法内部)。
解决思路
1.如果用户当前正在使用APP也就是程序在激活状态下,那么这时候用户所在的控制器是含有UINavigationController的控制器,当用户点击推送消息的时候,这时候获取到当前正在显示的视图控制器,进行跳转push过去。
2.如果用户当前正在使用APP也就是程序在激活状态下,那么这时候用户所在的控制器是不含有UINavigationController的控制器,这时候获取到当前的视图控制器 给将要跳转的控制器(也就是目标控制器你要跳转到的控制器)消息中心(MessageCenterViewController)添加导航栏 然后presentViewController。
3.1.在极光推送的代理方法里面实现页面跳转的逻辑
#pragma mark- JPUSHRegisterDelegate
// iOS 10 Support
- (void)jpushNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(NSInteger))completionHandler {
// Required
NSDictionary * userInfo = notification.request.content.userInfo;
if([notification.request.trigger isKindOfClass:[UNPushNotificationTrigger class]]) {
[JPUSHService handleRemoteNotification:userInfo];
//判断程序是否是在激活状态下
if ([UIApplication sharedApplication].applicationState == UIApplicationStateActive) {
}
else{//程序在后台以及程序没有启动的时候
//跳转到指定页面
[self pushToViewController];
}
}
completionHandler(UNNotificationPresentationOptionAlert); // 需要执行这个方法,选择是否提醒用户,有Badge、Sound、Alert三种类型可以选择设置
}
// iOS 10 Support. 极光推送代理方法
- (void)jpushNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void (^)())completionHandler {
if([response.notification.request.trigger isKindOfClass:[UNPushNotificationTrigger class]]) {
[JPUSHService handleRemoteNotification:userInfo];
if ([UIApplication sharedApplication].applicationState == UIApplicationStateActive) {
//程序运行时收到通知,先弹出消息框
[self pushToViewController];//程序激活状态下点击跳转逻辑
}
else{//程序在后台以及程序没有激活的时候点击跳转逻
//跳转到指定页面
[self pushToViewController];
}
}
completionHandler(); // 系统要求执行这个方法
}
#pragma mark---- ios 10.0//系统自己的运程推送代理方法
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
// Required, iOS 7 Support
[JPUSHService handleRemoteNotification:userInfo];
completionHandler(UIBackgroundFetchResultNewData);
if (application.applicationState == UIApplicationStateActive || application.applicationState == UIApplicationStateBackground) {
}
else
{
//跳转到指定页面
[self pushToViewController];
}
}
跳转逻辑实现方法一
- (void)pushToViewController{//视图控制器的跳转逻辑
UIViewController *vc = nil;
//判断根视图是不是UINavigationController
if ([self.window.rootViewController isKindOfClass:[UINavigationController class]]) {
//如果是获取最上层的控制器也就是当前显示的控制器
vc = ((UINavigationController *)self.window.rootViewController).viewControllers.lastObject;
}else{
//根控制器
vc = self.window.rootViewController;
}
//判断如果是在登录页面,那么不进行跳转
if ([vc isKindOfClass:[LoginViewController class]]) {
return;
}
MessageCenterViewController *messageVC = [MessageCenterViewController new];
if (vc.presentedViewController) {
//根控制器不是导航控制器
messageVC.isPresent = YES;
//给MessageCenterViewController添加导航栏 因为点击消息中心页面需要跳转到下一页面 如果没有这个需求可以不加。
UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:messageVC];
[vc.presentedViewController presentViewController:nav animated:YES completion:nil];
}else{
//根控制器是导航控制器
UINavigationController *nav = (UINavigationController *)vc;
[nav pushViewController:messageVC animated:YES];
}
}
跳转逻辑实现方法二
- (void)pushToViewController{
//视图控制器的跳转逻辑
MessageCenterViewController *messageVC = [MessageCenterViewController new];
UIViewController *topController =[self theTopviewControler];
NSString *classs = NSStringFromClass([topController class]);
NSLog(@"%@",classs);
//判断如果是在登录页面,那么不进行跳转
if ([topController isKindOfClass:[LoginViewController class]]) {
return;
}else if ([topController isKindOfClass:[WWTPointSelectionViewController class]]){//如果是从不含导航栏的控制器跳转到消息中西(WWTPointSelectionViewController没有导航栏的控制器)
UINavigationController * Nav = [[UINavigationController alloc]initWithRootViewController:messageVC];
messageVC.isPresent = YES;
//这里加导航栏是因为我跳转的页面带导航栏,如果跳转的页面不带导航,那这句话请省去。
[topController presentViewController:Nav animated:YES completion:nil];
}else{
//根控制器是导航控制器
UINavigationController *nav = (UINavigationController *)topController;
[nav pushViewController:messageVC animated:YES];
}
}
//获取当前所展示的控制器
- (UIViewController *)theTopviewControler{
UIViewController *rootVC = [[UIApplication sharedApplication].delegate window].rootViewController;
UIViewController *parent = rootVC;
while ((parent = rootVC.presentedViewController) != nil ) {
rootVC = parent;
}
while ([rootVC isKindOfClass:[UINavigationController class]]) {
rootVC = [(UINavigationController *)rootVC topViewController];
}
return rootVC;
}
提示:由于跳转进MessageCenterViewController的方式有push和preset两种类型,所以在MessageCenterViewController的返回按钮需要做下判断和区分,(这时候需要自定义返回按钮在返回按钮的方法中做判断和区分)如果是push进来的需要popViewControllerAnimated回去,如果是present进来的那么就需要dismissViewControllerAnimated
//返回按钮执行的方法
- (void)doClickPushAction{
//判断推送跳转进来的方式,可能是modal过来的。也可能是push过来的
if (self.isPresent) {
[self dismissViewControllerAnimated:YES completion:nil];
}else{
[self.navigationController popViewControllerAnimated:YES];
}
}
实现效果:
程序在激活状态下点击推送消息跳转.gif 程序在进入后台的时候点击推送进行跳转.gif 杀死程序也就是程序未启动的时候点击推送跳转.gif总结
点击推送消息进行指定页面的跳转,这个是很常见的需求,一定要考虑到项目中有些界面是有导航栏有些页面是没有导航栏的,而且在用户处于登陆页面的时候点击推送消息是不需要进行跳转的。
网友评论