SDMagicHook 1.2.5

SDMagicHook 1.2.5

GSD_iOS 维护。



  • 作者
  • gaoshaodong

SDMagicHook

中文文档 原理解析1 原理解析2 与Aspects异同

一种适用于 Objective-C 和 Swift 的安全且影响受限的方法钩子。

改进

使用 method_exchangeImplementations 进行的传统方法交换非常简单,但它有许多限制和缺陷。

  • 每当您想交换一个方法时,都必须在类类别中添加一个新的方法。
  • 不同类别中使用相同选择器的不同方法实现将导致方法冲突。
  • 方法交换将影响目标类的所有实例,然而在大多数情况下,这并不必要而且可能有副作用。

现在 SDMagicHook 将解决上述问题。

变更日志

2020.05.01 -- 发布兼容 KVO 的版本 "1.2.4"

2020.03.09 -- 兼容 KVO

用法

示例:挂钩CALayer的setBackgroundColor:方法以找出暗中更改视图背景色的人

[self.view.layer hookMethod:@selector(setBackgroundColor:) impBlock:^(CALayer *layer, CGColorRef color){
    [layer callOriginalMethodInBlock:^{
        [layer setBackgroundColor:color];
    }];
    NSLog(@"%@", [NSString stringWithFormat:@"AHA! Catch it! Here are the clues.\n\n%@", [NSThread callStackSymbols]]);
}];

示例:挂钩UIButton的pointInside:withEvent:方法以扩大热区域

- (void)expand:(Boolean)yn {

    if (yn) {
        __weak typeof(self) weakSelf = self;
        _hookID = [_button hookMethod:@selector(pointInside:withEvent:) impBlock:^(UIView *v, CGPoint p, UIEvent *e){
            __block BOOL res = false;
            [v callOriginalMethodInBlock:^{
                res = [v pointInside:p withEvent:e];
            }];
            if (res) return YES;

            return [weakSelf pointCheck:p view:v];
        }];
    } else {
        [_button removeHook:@selector(pointInside:withEvent:) strId:_hookID];
    }
}

示例:挂钩类方法

- (void)hookClassMethod {
    [[DemoVC3 class] hookMethod:@selector(testClassMethod) key:&testClassMethodTag impBlock:^(id cls){
        [cls callOriginalMethodInBlock:^{
            [[DemoVC3 class] testClassMethod];
        }];
        printf(">> hooked testClassMethod");
    }];
}

+ (void)testClassMethod {
    printf(">> %s", sel_getName(_cmd));
}

- (void)dealloc {
    [[DemoVC3 class] removeHook:@selector(testClassMethod) key:&testClassMethodTag];
}

示例:观察任意实例的dealloc事件。

[[NSObject new] addObjectDeallocCallbackBlock:^{
    printf("Will dealloc...");
}];

示例:使用Swift挂钩UIViewController的viewDidDisappear:方法

override func viewDidLoad() {
    super.viewDidLoad()
    let imp: @convention(block) (UIViewController, Bool) -> Void = { (vc, flag) in
        vc.callOriginalMethod {
            vc.viewDidDisappear(flag)
        }
        print(vc)
    }
    rootVC = navigationController?.children.first
    hookID = rootVC?.hookMethod(#selector(UIViewController.viewDidDisappear(_:)), impBlock: imp)
}

许可证

MIT许可证。