基于Aspects和JSContext对热更新的小理解

看了一下网上对Aspects做热修复的代码,代码是用不了的,所以有兴趣看了一下,并且做了一定的修改

用到的知识

  • JavaScriptCore
  • Aspects
  • runtime message

热修复

先说说热修复,前人已经对这里描述的挺清楚了,这里引用一下

iOS使用Aspects做简单热修复原理

热更新

原文里面的

    [self context][@"runClassWith2Paramters"] = ^id(NSString *className, NSString *selectorName, id obj1, id obj2) {
        return [self _runClassWithClassName:className selector:selectorName obj1:obj1 obj2:obj2];
    };

这种方法传参传了id,不知道是怎么做到的,于是自己做了一定的修改,把id obj改为了json字符串,自定义了使用的方法,在传参方面增加了基础参数的添加方法,在代码结构里面添加了几个demo,欢迎食用。

主要方法

+ (void)_runInstanceWithInstance:(NSString *)instanceName keyPath:(NSString *)keyPath selector:(NSString *)selector parameter1:(NSString *)parameter1 parameter2:(NSString *)parameter2 {
    
    
    /*
        HotFixManager 是作为存储实例的一个单例,如果跑实例方法却又重新alloc init的话,
        在当前页面上就无法展示了,具体可以查看demo
    */ 
    //搜索当前实例是否存在,如果存在的话继续
    id instance = [[HotFixManager shareManager] ViewController];
    
    if (!instance) {
        NSLog(@"对象未找到");
        return ;
    }
    if (keyPath) {
        instance = [instance valueForKeyPath:keyPath];
    }
    
    // 1.通过方法调用者创建方法签名;此方法是NSObject 的方法
    NSMethodSignature *sig = [[instance class] instanceMethodSignatureForSelector:NSSelectorFromString(selector)];
    // 2.通过方法签名 生成NSInvocation
    NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:sig];
    invocation.target = instance;
    invocation.selector = NSSelectorFromString(selector);
    // 注意 参数必须从2开始 因为0跟1已经被self,_cmd占用了
    // 3.对parameter进行操作
    if(parameter1) {
        id obj1 = [self fixObject:[self transferDictionary:parameter1]];
        [invocation setArgument:&obj1 atIndex:2];
    }
    
    if (parameter2) {
        id obj2 = [self fixObject:[self transferDictionary:parameter2]];
        [invocation setArgument:&obj2 atIndex:3];
    }
    //执行invoke
    [invocation invoke];
}

获取参数的方法

@interface ParamsHandler : NSObject

/** 字典处理 */
- initWithDictionary:(NSDictionary *)dic;

/** 处理JS返回回来的Json字符串,返回基本对象 */
- (id)fixIt;

@property (nonatomic, strong) NSString *type;
@property (nonatomic, strong) NSString *cls;
@property (nonatomic, strong) NSString *selector;
@property (nonatomic, strong) NSArray *parameters;
@property (nonatomic, strong) NSString *keyPath;

@end

- (id)fixIt {
    NSObject *obj;
    if ([self.type isEqualToString:@"instance"]) { //实例方法,将JS传过来的json字符串转化为iOS对象
        Class class = NSClassFromString(self.cls);
        // 这里就仅限传两个参数,主要是比较懒,有需要的同学自己添加两个以上的吧
        
        if (_parameters.count == 0) {
            obj = ((NSObject* (*) (id,SEL)) objc_msgSend) ([class alloc],sel_registerName(self.selector.UTF8String));
        } else if (_parameters.count == 1) {
            obj = ((NSObject* (*) (id,SEL,NSObject *)) objc_msgSend) ([class alloc],sel_registerName(self.selector.UTF8String),_parameters[0]);
        } else if (_parameters.count == 2) {
            obj = ((NSObject* (*) (id,SEL,NSObject *,NSObject *)) objc_msgSend) ([class alloc],sel_registerName(self.selector.UTF8String),_parameters[0],_parameters[1]);
        }
    } else if ([self.type isEqualToString:@"class"]) { // 类方法
        Class class = NSClassFromString(self.cls);
        if (_parameters.count == 0) {
            obj = ((NSObject* (*) (id,SEL)) objc_msgSend) (class,sel_registerName(self.selector.UTF8String));
        } else if (_parameters.count == 1) {
            obj = ((NSObject* (*) (id,SEL,NSObject *)) objc_msgSend) (class,sel_registerName(self.selector.UTF8String),_parameters[0]);
        } if (_parameters.count == 2) {
            obj = ((NSObject* (*) (id,SEL,NSObject *,NSObject *)) objc_msgSend) (class ,sel_registerName(self.selector.UTF8String),_parameters[0],_parameters[1]);
        }
    }
    
    return obj;
}

demo地址

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容