核心hook方法:网上有类似hook方式,但没考虑继承和子类的问题,会导致循环调用crash。
NSDictionary * checkIfObject(Class object,SEL selector) {
Class objSuperClass = [object superclass];
while (objSuperClass != Nil) {
BOOL isMethodOverridden = [object methodForSelector: selector] != [objSuperClass instanceMethodForSelector: selector];
if (isMethodOverridden) {
return @{@"class":objSuperClass,@"exist":@(YES)};
}
objSuperClass = [objSuperClass superclass];
}
return @{@"class":object,@"exist":@(NO)};
}
void exchangeMethod(Class oriClass, SEL originalSel, Class replacedClass, SEL replacedSel, SEL orginReplaceSel) {
NSDictionary *dict = checkIfObject(oriClass, originalSel);
Class originalClass = dict[@"class"];
BOOL exist = [dict[@"exist"] boolValue];
Method originalMethod = class_getInstanceMethod(originalClass, originalSel);
Method replacedMethod = class_getInstanceMethod(replacedClass, replacedSel);
if (!exist) {
Method orginReplaceMethod = class_getInstanceMethod(replacedClass, orginReplaceSel);
BOOL didAddOriginMethod = class_addMethod(originalClass, originalSel, method_getImplementation(orginReplaceMethod), method_getTypeEncoding(orginReplaceMethod));
if (didAddOriginMethod) {
NSLog(@"did Add Origin Replace Method");
}
return;
}
BOOL didAddMethod = class_addMethod(originalClass, replacedSel, method_getImplementation(replacedMethod), method_getTypeEncoding(replacedMethod));
if (didAddMethod) {
Method newMethod = class_getInstanceMethod(originalClass, replacedSel);
method_exchangeImplementations(originalMethod, newMethod);
}
}
使用 案例:(XXXX 前缀)注意实现方式
- (void)XXXX_setNavigationDelegate:(id<WKNavigationDelegate>)navigationDelegate {
[self XXXX_setNavigationDelegate:navigationDelegate];
exchangeMethod([navigationDelegate class], @selector(webView:decidePolicyForNavigationAction:decisionHandler:), [self class], @selector(XXXX_webView:decidePolicyForNavigationAction:decisionHandler:),@selector(XXXX_oriReplace_webView:decidePolicyForNavigationAction:decisionHandler:));
exchangeMethod([navigationDelegate class], @selector(webView:didStartProvisionalNavigation:), [self class], @selector(XXXX_webView:didStartProvisionalNavigation:),@selector(XXXX_oriReplace_webView:didStartProvisionalNavigation:));
exchangeMethod([navigationDelegate class], @selector(webView:didFinishNavigation:), [self class], @selector(XXXX_webView:didFinishNavigation:),@selector(XXXX_oriReplace_webView:didFinishNavigation:));
exchangeMethod([navigationDelegate class], @selector(webView:didFailProvisionalNavigation:withError:), [self class], @selector(XXXX_webView:didFailProvisionalNavigation:withError:),@selector(XXXX_oriReplace_webView:didFailProvisionalNavigation:withError:));
exchangeMethod([navigationDelegate class], @selector(webView:didFailNavigation:withError:), [self class], @selector(XXXX_webView:didFailNavigation:withError:),@selector(XXXX_oriReplace_webView:didFailNavigation:withError:));
}