在使用JPush 、JMessage、JMLink 等SDK时,iOS 客户端可能会收到下发的通知,或者收到回调里的返回参数,在拿到到参数后可能会有些场景需要跳转到目标页。
通过runtime 机制我们可以灵活的在服务端控制某条消息跳转到对应目标页。

runtime是个好东西

利用runtime动态生成对象、属性、方法这特性,我们可以先跟服务端商量好,定义跳转规则,比如要跳转到A控制器,需要传属性id、type,那么服务端返回字典给我,里面有控制器名,两个属性名跟属性值,客户端就可以根据控制器名生成对象,再用kvc给对象赋值,这样就搞定了。

比如:根据推送规则跳转对应界面HSFeedsViewController

HSFeedsViewController.h:

  • 进入该界面需要传的属性
objc
@interface HSFeedsViewController : UIViewController
// 注:根据下面的两个属性,可以从服务器获取对应的频道列表数据

/** 频道ID */
@property (nonatomic, copy) NSString *ID;

/** 频道type */
@property (nonatomic, copy) NSString *type;

AppDelegate.m:

  • 推送过来的消息规则
objc
// 这个规则肯定事先跟服务端沟通好,跳转对应的界面需要对应的参数
NSDictionary *userInfo = @{
    @"class": @"HSFeedsViewController", 
    @"property": @{
        @"ID": @"123", 
        @"type": @"12"
        } 
};
  • 接收推送消息
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo{    
    [self push:userInfo];
}
  • 魔链回调拿到参数

    [JMLinkService registerMLinkDefaultHandler:^(NSURL * _Nonnull url, NSDictionary * _Nullable params) {
       [self push:userInfo];
    }];
  • 跳转界面

- (void)push:(NSDictionary *)params {
 // 类名
 NSString *class =[NSString stringWithFormat:@"%@", params[@"class"]];
 const  char *className = [class cStringUsingEncoding:NSASCIIStringEncoding];
 // 从一个字串返回一个类
 Class newClass = objc_getClass(className);
 if (!newClass) {
 // 创建一个类
 Class superClass = [NSObject class];
 newClass = objc_allocateClassPair(superClass, className, 0);
 // 注册你创建的这个类
 objc_registerClassPair(newClass);
 }
 // 创建对象
 id instance = [[newClass alloc] init];
 // 对该对象赋值属性
 NSDictionary * propertys = params[@"property"];
 [propertys enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
     // 检测这个对象是否存在该属性
     if ([self checkIsExistPropertyWithInstance:instance verifyPropertyName:key]) {
         // 利用kvc赋值
         [instance setValue:obj forKey:key];
     }
 }];
 // 获取导航控制器
 UITabBarController *tabVC = (UITabBarController *)self.window.rootViewController;
 UINavigationController *pushClassStance = (UINavigationController *)tabVC.viewControllers[tabVC.selectedIndex];

 // 跳转到对应的控制器
 [pushClassStance pushViewController:instance animated:YES];
 }
  • 检测对象是否存在该属性
- (BOOL)checkIsExistPropertyWithInstance:(id)instance verifyPropertyName:(NSString *)verifyPropertyName {

 unsigned int outCount, i;
 // 获取对象里的属性列表
 objc_property_t * properties = class_copyPropertyList([instance
 class], &outCount);
 for (i = 0; i < outCount; i++) {
     objc_property_t property =properties[i];
     // 属性名转成字符串
     NSString *propertyName = [[NSString  alloc] initWithCString:property_getName(property) encoding:NSUTF8StringEncoding];

 // 判断该属性是否存在
 if ([propertyName isEqualToString:verifyPropertyName]) {
     free(properties);
     return YES;
 }
 }
 free(properties);
 return  NO;
}