一、Ioshook父类方法
1.方法简介
Ioshook是一个基于Cycript实现的库,它可以hook Objective-C方法并在运行时对其进行修改、添加与删除。下面我们会从多个方面进行详细阐述。
2.方法具体实现
/**
* Hook一个对象的类方法
*
* @param cls 类对象
* @param selector 方法选择器
* @param callback 回调函数
*
* @return 原始IMP地址
*/
+ (void *)hookClassMethod:(Class)cls selector:(SEL)selector callback:(void *)callback;
/**
* Hook一个对象的实例方法
*
* @param cls 类对象
* @param selector 方法选择器
* @param callback 回调函数
*
* @return 原始IMP地址
*/
+ (void *)hookInstanceMethod:(Class)cls selector:(SEL)selector callback:(void *)callback;
3.方法使用示例
以Hook UIAlertView
的 show
方法为例,我们可以实现自定义 UIAlertView
显示时的行为。
Class cls = objc_getClass("UIAlertView");
SEL sel = @selector(show);
[Ioshook hookInstanceMethod:cls selector:sel callback:&showCallback];
// 实现 showCallback 方法
void showCallback(id self, SEL sel) {
NSLog(@"custom show action");
}
二、子类重写
1.重写方法实现
除了通过 hook 来修改方法的行为,我们还可以通过 subclass 的方法来重写方法的实现,以此实现目标。
@interface TargetClass : NSObject
- (void)originalMethod;
@end
@implementation TargetClass
- (void)originalMethod {
NSLog(@"original method");
}
@end
@interface SubClass : TargetClass@end
@implementation SubClass
- (void)originalMethod {
NSLog(@"new method");
}
@end
2.重写方法使用示例
以 Hook UIViewController
的 viewDidAppear:
方法为例,我们可以在所有继承于 UIViewController
的子类中增加上报事件:
@implementation UIViewController (CustomEvent)
+ (void)load {
// Only add once
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
// subclass
[self mk_customHookMethod:@selector(viewDidAppear:) tarClass:self.newClass usingBlock:^(MKAspectInfo *info) {
UIViewController *controller = (UIViewController *)info.instance;
NSLog(@"custom event report: %@", NSStringFromClass([controller class]));
}];
});
}
@end
@interface UIViewController (CustomEvent) @end
@implementation UIViewController (CustomEvent)
// Override this method to return subclass
+ (Class)newClass {
// Allocate a new class, subclass of the original
NSString *className = NSStringFromClass(self);
Class newClass = objc_allocateClassPair(self, [className stringByAppendingString:@"_CustomEvent"].UTF8String, 0);
// Update hook for subclasses
[newClass aspect_hookSelector:@selector(viewDidAppear:) withOptions:AspectPositionAfter usingBlock:^(id info) {
UIViewController *controller = (UIViewController *)info.instance;
NSLog(@"custom event report: %@", NSStringFromClass([controller class]));
} error:nil];
objc_registerClassPair(newClass);
return newClass;
}
@end
三、使用场景
1.日志打印
在开发和调试过程中,日志打印是件非常重要的事情。我们可以通过 hook 的形式实现全局的日志打印。下面以 YYLog 框架为例:
void _objc_msgForward(void) {
// Hook it
orig_objc_msgForward();
// Do something with it
NSLog(@"classname : %@ SEL: %@", NSStringFromClass([self class]), NSStringFromSelector(_cmd));
}
2.检查错误
在发布的应用中,一个小小的错误有可能导致崩溃。通过 hook 可以实现全局的错误检测和上报。
// Define a new method
- (void)xxx_NSLog:(NSString *)format, ... {
va_list argp;
va_start(argp, format);
NSString *str = [[NSString alloc] initWithFormat:format arguments:argp];
va_end(argp);
// Do something with the log
NSLog(@"%@", str);
// Call the old method
[self xxx_NSLog:format,...];
}
// Hook NSUncaughtExceptionHandler
if (getenv("DEBUG_MODE")) { // debug mode
NSSetUncaughtExceptionHandler(&CBLDebugHandleException);
} else { // release mode
NSSetUncaughtExceptionHandler(&CBLReleaseHandleException);
}
// Implement CBLDebugHandleException and CBLReleaseHandleException functions to handle errors
3.统计调用次数
很多应用都需要进行功能点调用次数的统计。通过 hook 可以实现全局的统计,提高开发效率。
@implementation UIView (Count)
+ (void)load {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
[self aspect_hookSelector:@selector(didMoveToSuperview) withOptions:AspectPositionAfter usingBlock:^() {
// Statistics code here
} error:nil];
});
}
@end
4.网络监测
通过 hook 可以实现网络请求的监测,从而实现全局的网络监测。
+ (void)load {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
Class cls = objc_getClass("__NSCFURLSessionTask");
[Ioshook hookInstanceMethod:cls selector:@selector(cancel) callback:(void *)&HookedNSURLSessionTaskCancel];
});
}
void HookedNSURLSessionTaskCancel(NSURLSessionTask *self, SEL _cmd) {
// Statistics network interrupt times
[self HookedNSURLSessionTaskCancel];
}
四、小结
使用 hook 的方式,可以实现很多应用所需要的功能,例如日志打印、错误检测、调用次数统计、网络监测等等。对了解 iOS 运行机制和 Objective-C 方法有较深入的理解有一定帮助。以上是一些功能点的例子,我们也可以根据实际需要进行策略和实现。希望对大家有所帮助。