IOS App 無(wú)代碼入侵的方法hook詳細(xì)介紹
iOS App 無(wú)代碼入侵的方法hook
繼續(xù)Objective-C runtime的研究
最近公司項(xiàng)目在做用戶行為分析
于是App端在某些頁(yè)面切換,交互操作的時(shí)候需要給統(tǒng)計(jì)系統(tǒng)發(fā)送一條消息
在幾十個(gè)Controller 的項(xiàng)目里,一個(gè)一個(gè)地加代碼那完全是不可能的,維護(hù)起來(lái)也是吃力
但這里需要處理的是 Controller, 可以有以下方式實(shí)現(xiàn)上述需求
1. 利用Objective-C 中的對(duì)象繼承
繼承 在面向?qū)ο箝_發(fā)中是非常常用的,像我們現(xiàn)在做的項(xiàng)目工程中都會(huì)有一個(gè)BaseViewController,
所有新建的ViewController都繼承BaseViewController,通過(guò)往BaseViewController中添加一些公共方法\屬性 可以被他們的子類所調(diào)用
這是統(tǒng)一我們工程中所有視圖控制器樣式的一個(gè)主要途徑
2.利用Category 和Runtime實(shí)行方法hook
hook方案有一個(gè)好處,就是可以避免代碼入侵,做到更加廣泛的通用性.通過(guò)swizzling我們可以將原method與自己加入的method相結(jié)合,
即不需要在原有工程中加入代碼,又能做到全局覆蓋
兩種方案對(duì)比:
通過(guò)繼承父類來(lái)實(shí)現(xiàn) 相對(duì)于hook來(lái)說(shuō) 是較為準(zhǔn)確的,因?yàn)樾枰唤y(tǒng)計(jì)的頁(yè)面都是繼承于這個(gè)父類的控制器,而其他的如UINavigationController,系統(tǒng)自帶的UIAlertController等則不會(huì)誤入統(tǒng)計(jì)數(shù)據(jù)當(dāng)中
上面提到 hook方案是通過(guò)hook UIViewController viewdidload/viewdidappear等方法,而這些方法實(shí)際上 每個(gè)Controller 都會(huì)調(diào)用,那么就會(huì)出現(xiàn)不該出現(xiàn)的Controller 也出現(xiàn)在這里(如上面說(shuō)到的UINavigationController和UIAlertController).但hook方案一個(gè)比較好的特點(diǎn)是無(wú)代碼入侵,在不修改項(xiàng)目代碼的前提下完成工作.
考慮到 行為分析統(tǒng)計(jì)系統(tǒng) 有可能被公司其他項(xiàng)目中所應(yīng)用,這里采用hook方案.那么當(dāng)中必然會(huì)出現(xiàn) 不該統(tǒng)計(jì)的卻被統(tǒng)計(jì) 的情況,后面再作分析.
既然用到hook方案,又要用runtime 的swizzling
首先 新建一個(gè)UIViewController 的category
實(shí)現(xiàn)swizzling代碼
+ (void)load{
[super load];
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
// 假如要打開controller的統(tǒng)計(jì) ,則把下面這行代碼打開
__gbh_tracer_swizzleMethod([self class], @selector(viewDidAppear:), @selector(__gbh_tracer_viewDidAppear:));
});
}
嗯,看到這里大家會(huì)發(fā)現(xiàn) 這里調(diào)用的是一個(gè)C的方法,然而這個(gè)C方法是怎么實(shí)現(xiàn)的呢?看下面
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);
}
}
這是一個(gè)標(biāo)準(zhǔn)的swizzling寫法,當(dāng)然了 github上面也有關(guān)于swizzling的開源庫(kù),用起來(lái)也順手 這里就不多說(shuō)
看回第一塊代碼,紅色的viewDidAppear是即將被我hook的方法,__gbh_tracer_viewDidAppear 則是我需要實(shí)現(xiàn)的方法
- (void)__gbh_tracer_viewDidAppear:(BOOL)animated{
[self __gbh_tracer_viewDidAppear:animated]; //由于方法已經(jīng)被交換,這里調(diào)用的實(shí)際上是viewDidAppear:方法
//設(shè)置不允許發(fā)送數(shù)據(jù)的Controller
NSArray *filter = @[@"UINavigationController",@"UITabBarController"];
NSString *className = NSStringFromClass(self.class);
if ([filter containsObject:className]) return ; //如果該Controller在不允許發(fā)送log的列表里,則不能繼續(xù)往下走
if ([self.title isKindOfClass:[NSString class]] && self.title.length > 0){ //有標(biāo)題的才符合我的要求
// 這里發(fā)送log
}
}
嗯,剛剛說(shuō)到有部分Controller我是不發(fā)數(shù)據(jù)的,這里有兩重判斷,一個(gè)是加入到黑名單,另一個(gè)是 判斷Controller的title屬性是否為空
以上判斷基本能滿足我這個(gè)行為分析統(tǒng)計(jì)系統(tǒng)的需求,若還需要什么判斷還可以繼續(xù)加
以此 我只需要往工程里面添加這個(gè)Category,這個(gè)viewDidAppear就會(huì)被hook出來(lái),可以為所欲為..
另外 需求中還提到 需要在應(yīng)用啟動(dòng)的時(shí)候發(fā)送一次init消息
hook?可以,但我更傾向與利用category+NSNotification,因?yàn)橄到y(tǒng)中已經(jīng)有 UIApplicationDidFinishLaunchingNotification
這種通知,直接用就可以
@implementation UIApplication (GBHTracer)
+ (void)load{
[super load];
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{ //只執(zhí)行一次就可以了
[[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(__gbh_tracer_applicationDidFinishLaunching:) name:UIApplicationDidFinishLaunchingNotification object:nil];
});
}
+ (void)__gbh_tracer_applicationDidFinishLaunching:(NSNotification *)noti{
//應(yīng)用啟動(dòng)時(shí)為所欲為!
}
@end
嗯..我們的行為分析統(tǒng)計(jì)系統(tǒng)就在原工程不Import一個(gè)頭文件 不調(diào)用 任何一個(gè)方法就可以達(dá)到統(tǒng)計(jì)效果.
但是像什么操作響應(yīng)的時(shí)候的統(tǒng)計(jì),還是需要各位看官在響應(yīng)中調(diào)用相應(yīng)的方法
感謝閱讀,希望能幫助到大家,謝謝大家對(duì)本站的支持!
- iOS開發(fā)中實(shí)現(xiàn)hook消息機(jī)制的方法探究
- iOS內(nèi)存錯(cuò)誤EXC_BAD_ACCESS的解決方法
- iOS開發(fā)中ViewController的頁(yè)面跳轉(zhuǎn)和彈出模態(tài)
- js和html5實(shí)現(xiàn)手機(jī)端刮刮卡抽獎(jiǎng)效果完美兼容android/IOS
- iOS毛玻璃效果的實(shí)現(xiàn)及圖片模糊效果的三種方法
- iOS開發(fā)中WebView的基本使用方法簡(jiǎn)介
- IOS開發(fā)代碼分享之設(shè)置UISearchBar的背景顏色
- IOS獲取各種文件目錄路徑的方法
- iOS開發(fā)中實(shí)現(xiàn)顯示gif圖片的方法
相關(guān)文章
ios動(dòng)態(tài)庫(kù)和靜態(tài)庫(kù)的區(qū)別
這篇文章主要介紹了ios動(dòng)態(tài)庫(kù)和靜態(tài)庫(kù)的區(qū)別,幫助大家更好的理解和學(xué)習(xí)使用ios開發(fā),感興趣的朋友可以了解下2021-04-04
iOS 項(xiàng)目中的version和build 詳解
這篇文章主要介紹了iOS 項(xiàng)目中的version和build 詳解的相關(guān)資料,需要的朋友可以參考下2016-11-11
淺談iOS應(yīng)用中的相關(guān)正則及驗(yàn)證
下面小編就為大家?guī)?lái)一篇淺談iOS應(yīng)用中的相關(guān)正則及驗(yàn)證。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-04-04
ios利用RunLoop原理實(shí)現(xiàn)去監(jiān)控卡頓實(shí)例詳解
這篇文章主要為大家介紹了ios利用RunLoop原理實(shí)現(xiàn)去監(jiān)控卡頓實(shí)例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-09-09
iOS拍照后圖片自動(dòng)旋轉(zhuǎn)90度的完美解決方法
今天開發(fā)一個(gè)拍照獲取照片的功能的時(shí)候, 發(fā)現(xiàn)上傳之后圖片會(huì)自動(dòng)旋轉(zhuǎn)90.在測(cè)試中發(fā)現(xiàn)只要是圖片大于2M, 系統(tǒng)就會(huì)自動(dòng)翻轉(zhuǎn)照片。下面小編通過(guò)本文給大家分享下解決辦法2016-12-12
IOS 應(yīng)用程序管理的實(shí)現(xiàn)
這篇文章主要介紹了IOS 應(yīng)用程序管理的實(shí)現(xiàn)的相關(guān)資料,希望通過(guò)本文能幫助到大家,讓大家實(shí)現(xiàn)這樣的功能,需要的朋友可以參考下2017-10-10

