iOS 无代码入侵的方法hook

*于是App端在某些页面切换,交互操作的时候需要给统计系统发送一条消息在几十个Controller 的项目里,一个一个地加代码那完全是不可能的,维护起来也是吃力,但这里需要处理的是 Controller, 可以有以下方式实现上述需求

(1). 利用Objective-C 中的对象继承
  • 继承 在面向对象开发中是非常常用的,像我们现在做的项目工程中都会有一个BaseViewController,
  • 所有新建的ViewController都继承BaseViewController,通过往BaseViewController中添加一些公共方法\属性 可以被他们的子类所调用
  • 这是统一我们工程中所有视图控制器样式的一个主要途径
(2). 利用Category 和Runtime实行方法hook
  • hook方案有一个好处,就是可以避免代码入侵,做到更加广泛的通用性.通过swizzling我们可以将原method与自己加入的method相结合,即不需要在原有工程中加入代码,又能做到全局覆盖

  • 既然用到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
    }

}
  • 这是转载地址 http://www.cnblogs.com/n1ckyxu/p/6186850.html
  • 感谢!!!

你可能感兴趣的:(iOS 无代码入侵的方法hook)