记录下利用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];
// 做你想做的...
}