OC-实现动态钩子

140 阅读1分钟

记录下利用Objective-C的消息转发机制,来实现动态钩子,可以在运行时动态替换方法实现。 原理如下代码所示:

#import <objc/runtime.h>
#import <objc/message.h>

- (void)hook:(Class)cls selector:(SEL)sel
{
    // 获取原始方法
    Method originalMethod = class_getInstanceMethod(cls, sel);
    // 尝试给类添加原始方法,防止影响到父类
    class_addMethod(cls, sel, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod));
    // 设置一个自定义方法
    NSString *selStr = [NSString stringWithFormat:@"my_%@", NSStringFromSelector(sel)];
    // 添加自定义方法,用于存储原始方法实现
    class_addMethod(cls, NSSelectorFromString(selStr), method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod));
    // 将原始方法实现指向 forward 方法实现
    class_replaceMethod(cls, method_getName(originalMethod), (IMP)_objc_msgForward, method_getTypeEncoding(originalMethod));
    // 将原始的 forward 方法替换为自定义的 myforward
    class_replaceMethod(cls, @selector(forwardInvocation:), (IMP)MyForwardInvocation, "v@:@");
}

static void MyForwardInvocation(__unsafe_unretained id assignSlf, SEL selector, NSInvocation *invocation)
{
    // 做你想做的...
    
    // 调用原始方法的方法实现
    NSString *selStr = [NSString stringWithFormat:@"my_%@", NSStringFromSelector(invocation.selector)];
    invocation.selector = NSSelectorFromString(selStr);
    [invocation invoke];
    
    // 做你想做的...
}