想要为某各类添加钩子首先要建立这个类或父类的分类,运用runtime的方法交换的方法实现交换再调回原方法 这就是钩子的基本思路 运用lldb 查看方法的调用堆栈 就可以找到在这个方法之前调用的方法,然后我们拦截它,交换它!
lldb 的命令 thread backtrace 查看调用堆栈
找到你需要的拦截的方法
Method applicationLanch = class_getInstanceMethod([self class],@selector(application: didFinishLaunchingWithOptions:));
Method newApplicationLanch = class_getInstanceMethod([self class], @selector(configurationApplication: didFinishLaunchingWithOptions:));
method_exchangeImplementations(applicationLanch, newApplicationLanch);
然后调回本身:
- (BOOL)configurationApplication:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
BOOL result = [self configurationApplication:application didFinishLaunchingWithOptions:launchOptions];
NSLog(@"%@AppDelegate+Hook",
[self class]);
return result;
}
注意这两个方法已经交换所以实际调用的是application: didFinishLaunchingWithOptions: 这个方法,那么代理方法怎么拦截呢?
也是一样的只要拦截 交换setDelegate: 方法 在交换的方法中遵守代理 然后在这个方法里继续交换你想要交换的方法
#define GET_CLASS_CUSTOM_SEL(sel,class) NSSelectorFromString([NSString stringWithFormat:@"%@_%@",NSStringFromClass(class),NSStringFromSelector(sel)])
- (void)fd_setDelegate:(id<UIScrollViewDelegate>)delegate {
if ([self isMemberOfClass:[UIScrollView class]]) {
if (![self isContainSel:GET_CLASS_CUSTOM_SEL(@selector(scrollViewWillBeginDragging:),[delegate class]) inClass:[delegate class]]) {
[self swizzling_scrollViewWillBeginDragging:delegate];
}
[self fd_setDelegate:delegate];
}
}
- (BOOL)isContainSel:(SEL)sel inClass:(Class)class {
unsigned int count;
Method *methodList = class_copyMethodList(class,&count);
for (int i = 0; i < count; i++) {
Method method = methodList[i];
NSString *tempMethodString = [NSString stringWithUTF8String:sel_getName(method_getName(method))];
if ([tempMethodString isEqualToString:NSStringFromSelector(sel)]) {
return YES;
}
}
return NO;
}