一、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/zh-hant/n/241439.html