想要為某各類添加鈎子首先要建立這個類或父類的分類,運用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;
}