一、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 方法有较深入的理解有一定帮助。以上是一些功能点的例子,我们也可以根据实际需要进行策略和实现。希望对大家有所帮助。
原创文章,作者:小蓝,如若转载,请注明出处:https://www.506064.com/n/241439.html