無(wú)埋點(diǎn)耙饰,不是不需要埋點(diǎn),更確切地說(shuō)是“全埋點(diǎn)”纹份,只是埋點(diǎn)代碼不會(huì)出現(xiàn)在業(yè)務(wù)代碼中
優(yōu)點(diǎn):容易管理和維護(hù)苟跪。并且可移植性高廷痘。
缺點(diǎn):埋點(diǎn)成本高,后期的解析也比較復(fù)雜件已,再加上 view_path 的不確定性笋额。所以,這種方案并不能解決所有的埋點(diǎn)需求篷扩,但對(duì)于大量通用的埋點(diǎn)需求來(lái)說(shuō)兄猩,能夠節(jié)省大量的開(kāi)發(fā)和維護(hù)成本。
廢話不多說(shuō)直接上代碼
1.創(chuàng)建一個(gè)Hook類(lèi)用于方法替換
.h文件如下
@interface Hook : NSObject
+ (void)hookClass:(Class)classObject fromSelector:(SEL)fromSelector toSelector:(SEL)toSelector;
@end
.m文件如下
#import "Hook.h"
#import <objc/runtime.h>
@implementation Hook
+ (void)hookClass:(Class)classObject fromSelector:(SEL)fromSelector toSelector:(SEL)toSelector {
Class class = classObject;
// 得到被替換類(lèi)的實(shí)例方法
Method fromMethod = class_getInstanceMethod(class, fromSelector);
// 得到替換類(lèi)的實(shí)例方法
Method toMethod = class_getInstanceMethod(class, toSelector);
// class_addMethod 返回成功表示被替換的方法沒(méi)實(shí)現(xiàn)鉴未,然后會(huì)通過(guò) class_addMethod 方法先實(shí)現(xiàn)枢冤;返回失敗則表示被替換方法已存在,可以直接進(jìn)行 IMP 指針交換
if(class_addMethod(class, fromSelector, method_getImplementation(toMethod), method_getTypeEncoding(toMethod))) {
// 進(jìn)行方法的替換
class_replaceMethod(class, toSelector, method_getImplementation(fromMethod), method_getTypeEncoding(fromMethod));
} else {
// 交換 IMP 指針
method_exchangeImplementations(fromMethod, toMethod);
}
}
@end
寫(xiě)一個(gè)UIViewcontroller的分類(lèi)
@interface UIViewController (HookBuriedPoint)
@end
分類(lèi).m文件代碼如下
#import "UIViewController+HookBuriedPoint.h"
#import "Hook.h"
@implementation UIViewController (HookBuriedPoint)
+ (void)load {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
// 通過(guò) @selector 獲得被替換和替換方法的 SEL铜秆,作為 ViewHook:hookClass:fromeSelector:toSelector 的參數(shù)傳入
SEL fromSelectorAppear = @selector(viewWillAppear:);
SEL toSelectorAppear = @selector(hook_viewWillAppear:);
[Hook hookClass:self fromSelector:fromSelectorAppear toSelector:toSelectorAppear];
SEL fromSelectorDisappear = @selector(viewWillDisappear:);
SEL toSelectorDisappear = @selector(hook_viewWillDisappear:);
[Hook hookClass:self fromSelector:fromSelectorDisappear toSelector:toSelectorDisappear];
});
}
- (void)hook_viewWillAppear:(BOOL)animated {
// 先執(zhí)行插入代碼淹真,再執(zhí)行原 viewWillAppear 方法
[self insertToViewWillAppear];
[self hook_viewWillAppear:animated];
}
- (void)hook_viewWillDisappear:(BOOL)animated {
// 執(zhí)行插入代碼,再執(zhí)行原 viewWillDisappear 方法
[self insertToViewWillDisappear];
[self hook_viewWillDisappear:animated];
}
- (void)insertToViewWillAppear {
// 在 ViewWillAppear 時(shí)進(jìn)全局無(wú)侵入埋點(diǎn)
NSLog(@"hook-%@",[NSString stringWithFormat:@"%@ Appear",NSStringFromClass([self class])]);
}
- (void)insertToViewWillDisappear {
// 在 ViewWillDisappear 時(shí)進(jìn)全局無(wú)侵入埋點(diǎn)
}
@end