IOS App 無代碼入侵的辦法hook
持續Objective-C runtime的研討
最近公司項目在做用戶行為剖析
於是App端在某些頁面切換,交互操作的時分需求給統計零碎發送一條音訊
在幾十個Controller 的項目裡,一個一個地加代碼那完全是不能夠的,維護起來也是費勁
但這裡需求處置的是 Controller, 可以有以下方式完成上述需求
1. 應用Objective-C 中的對象承繼
承繼 在面向對象開發中是十分常用的,像我們如今做的項目工程中都會有一個BaseViewController,
一切新建的ViewController都承繼BaseViewController,經過往BaseViewController中添加一些公共辦法\屬性 可以被他們的子類所調用
這是一致我們工程中一切視圖控制器款式的一個次要途徑
2.應用Category 和Runtime實行辦法hook
hook方案有一個益處,就是可以防止代碼入侵,做到愈加普遍的通用性.經過swizzling我們可以將原method與自己參加的method相結合,
即不需求在原有工程中參加代碼,又能做到全局掩蓋
兩種方案比照:
經過承繼父類來完成 絕對於hook來說 是較為精確的,由於需求被統計的頁面都是承繼於這個父類的控制器,而其他的如UINavigationController,零碎自帶的UIAlertController等則不會誤入統計數據當中
下面提到 hook方案是經過hook UIViewController viewdidload/viewdidappear等辦法,而這些辦法實踐上 每個Controller 都會調用,那麼就會呈現不該呈現的Controller 也呈現在這裡(如下面說到的UINavigationController和UIAlertController).但hook方案一個比擬好的特點是無代碼入侵,在不修正項目代碼的前提下完成任務.
思索到 行為剖析統計零碎 有能夠被公司其他項目中所使用,這裡采用hook方案.那麼當中必定會呈現 不該統計的卻被統計 的狀況,前面再作剖析.
既然用到hook方案,又要用runtime 的swizzling
首先 新建一個UIViewController 的category
完成swizzling代碼
+ (void)load{ [super load]; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ // 假設要翻開controller的統計 ,則把上面這行代碼翻開 __gbh_tracer_swizzleMethod([self class], @selector(viewDidAppear:), @selector(__gbh_tracer_viewDidAppear:)); }); }
嗯,看到這裡大家會發現 這裡調用的是一個C的辦法,但是這個C辦法是怎樣完成的呢?看上面
void __gbh_tracer_swizzleMethod(Class class, SEL originalSelector, SEL swizzledSelector){ Method originalMethod = class_getInstanceMethod(class, originalSelector); Method swizzledMethod = class_getInstanceMethod(class, swizzledSelector); BOOL didAddMethod = class_addMethod(class, originalSelector, method_getImplementation(swizzledMethod), method_getTypeEncoding(swizzledMethod)); if (didAddMethod) { class_replaceMethod(class, swizzledSelector, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod)); } else { method_exchangeImplementations(originalMethod, swizzledMethod); } }
這是一個規范的swizzling寫法,當然了 github下面也有關於swizzling的開源庫,用起來也隨手 這裡就不多說
看回第一塊代碼,白色的viewDidAppear是行將被我hook的辦法,__gbh_tracer_viewDidAppear 則是我需求完成的辦法
- (void)__gbh_tracer_viewDidAppear:(BOOL)animated{ [self __gbh_tracer_viewDidAppear:animated]; //由於辦法曾經被交流,這裡調用的實踐上是viewDidAppear:辦法 //設置不允許發送數據的Controller NSArray *filter = @[@"UINavigationController",@"UITabBarController"]; NSString *className = NSStringFromClass(self.class); if ([filter containsObject:className]) return ; //假如該Controller在不允許發送log的列表裡,則不能持續往下走 if ([self.title isKindOfClass:[NSString class]] && self.title.length > 0){ //有標題的才契合我的要求 // 這裡發送log } }
嗯,剛剛說到有局部Controller我是不發數據的,這裡有兩重判別,一個是參加到黑名單,另一個是 判別Controller的title屬性能否為空
以上判別根本能滿足我這個行為剖析統計零碎的需求,若還需求什麼判別還可以持續加
以此 我只需求往工程外面添加這個Category,這個viewDidAppear就會被hook出來,可以為所欲為..
另外 需求中還提到 需求在使用啟動的時分發送一次init音訊
hook?可以,但我更傾向與應用category+NSNotification,由於零碎中曾經有 UIApplicationDidFinishLaunchingNotification
這種告訴,直接用就可以
@implementation UIApplication (GBHTracer) + (void)load{ [super load]; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ //只執行一次就可以了 [[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(__gbh_tracer_applicationDidFinishLaunching:) name:UIApplicationDidFinishLaunchingNotification object:nil]; }); } + (void)__gbh_tracer_applicationDidFinishLaunching:(NSNotification *)noti{ //使用啟動時為所欲為! } @end
嗯..我們的行為剖析統計零碎就在原工程不Import一個頭文件 不調用 任何一個辦法就可以到達統計效果.
但是像什麼操作呼應的時分的統計,還是需求各位看官在呼應中調用相應的辦法
感激閱讀,希望能協助到大家,謝謝大家對本站的支持!
【IOS App 無代碼入侵的辦法hook詳細引見】的相關資料介紹到這裡,希望對您有所幫助! 提示:不會對讀者因本文所帶來的任何損失負責。如果您支持就請把本站添加至收藏夾哦!