BlockHook 1.5.12

BlockHook 1.5.12

杨晓宇维护。



BlockHook 1.5.12

BlockHook

Platform CI Status Version Carthage compatible codecov Codacy Badge GitHub release Twitter Follow

BlockHook

使用libffi挂钩Objective-C blocks。它是一个强大的Blocks方面的AOP工具。BlockHook可以在调用block之前/代替/之后运行您的代码。BlockHook甚至可以在block dealloc时通知您。您可以使用BlockHook跟踪块的整个生命周期!

想要挂钩传递给方法的blocks吗?试试BlockTracker

🌟特性

  • 易于使用。保持您的代码清晰。
  • 支持4种钩子模式:之前、代替、之后和废弃。
  • 允许您修改返回值和参数。
  • 支持调用原始实现。
  • 可以在任何时候移除钩子。
  • 遍历块的所有钩子令牌。
  • 提供块泛型名称。
  • 自我管理令牌。
  • 支持自定义结构。
  • 支持 Carthage 和 CocoaPods。

🔮示例

BlockHook 需要 libffi 库,支持 iOS、tvOS 和 macOS。您可以运行 BlockHookSample iOSBlockHookSample tvOSBlockHookSample macOS 目标。

🐒如何使用

Just Hook

您可以使用 4 种模式(在/代替/之后/死亡)来 Hook 块。该方法返回 BHToken 实例以获取更多控制。您可以移除 BHToken,或设置自定义返回值到其 retValue 属性。调用 invokeOriginalBlock 方法将调用块的原始实现。

- (BHToken *)block_hookWithMode:(BlockHookMode)mode
                     usingBlock:(id)block

BlockHook 易于使用。它的 API 以 Aspects 为例。这里提供了一个完整的 BlockHook 使用示例Here

这是一个在所有模式下 Hook 块的示例。您可以将块返回值从 8 改为 15。然后移除一些 Hook 并检查是否成功。最后我们在块析构时得到回调。

NSObject *z = NSObject.new;
int(^block)(int x, int y) = ^int(int x, int y) {
    int result = x + y;
    NSLog(@"%d + %d = %d, z is a NSObject: %@", x, y, result, z);
    return result;
};
    
BHToken *token = [block block_hookWithMode:BlockHookModeDead|BlockHookModeBefore|BlockHookModeInstead|BlockHookModeAfter usingBlock:^(BHInvocation *invocation, int x, int y) {
    int ret = 0;
    [invocation getReturnValue:&ret];
    switch (invocation.mode) {
        case BlockHookModeBefore:
            // BHInvocation has to be the first arg.
            NSLog(@"hook before block! invocation:%@", invocation);
            break;
        case BlockHookModeInstead:
            [invocation invokeOriginalBlock];
            NSLog(@"let me see original result: %d", ret);
            // change the block imp and result
            ret = x * y;
            [invocation setReturnValue:&ret];
            NSLog(@"hook instead: '+' -> '*'");
            break;
        case BlockHookModeAfter:
            // print args and result
            NSLog(@"hook after block! %d * %d = %d", x, y, ret);
            break;
        case BlockHookModeDead:
            // BHInvocation is the only arg.
            NSLog(@"block dead! token:%@", invocation.token);
            break;
        default:
            break;
    }
}];
    
NSLog(@"hooked block");
int ret = block(3, 5);
NSLog(@"hooked result:%d", ret);
// remove token.
[token remove];
NSLog(@"remove tokens, original block");
ret = block(3, 5);
NSLog(@"original result:%d", ret);

以下是日志

hooked block
hook before block! invocation:<BHInvocation: 0x600003668940>
3 + 5 = 8, z is a NSObject: <NSObject: 0x6000034245a0>
let me see original result: 8
hook instead: '+' -> '*'
hook after block! 3 * 5 = 15
hooked result:15
remove tokens, original block
hook before block! invocation:<BHInvocation: 0x60000366c7c0>
3 + 5 = 8, z is a NSObject: <NSObject: 0x6000034245a0>
hook after block! 3 * 5 = 8
original result:8
block dead! token:<BHToken: 0x600000422910>

块拦截器

有时您希望在用户登录后再路由到其他组件。为了拦截块而不需要修改路由器的代码,您可以使用块拦截器。

NSObject *testArg = [NSObject new];
NSObject *testArg1 = [NSObject new];
    
NSObject *(^testblock)(NSObject *) = ^(NSObject *a) {
    return [NSObject new];
};
    
[testblock block_interceptor:^(BHInvocation *invocation, IntercepterCompletion  _Nonnull completion) {
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        NSObject * __unsafe_unretained arg;
        [invocation getArgument:&arg atIndex:1];
        NSLog(@"Original argument:%@", arg);
        [invocation setArgument:(void *)&testArg1 atIndex:1];
        completion();
    });
}];
    
testblock(testArg);

📲安装

鲸鱼Pods

鲸鱼Pods 是用于Cocoa项目的一个依赖管理器。你可以使用以下命令安装它

$ gem install cocoapods

要使用鲸鱼Pods将BlockHook集成到Xcode项目中,请在你的 Podfile 中指定它

source 'https://github.com/CocoaPods/Specs.git'
platform :ios, '8.0'
use_frameworks!
target 'MyApp' do
	pod 'BlockHook'
end

需要将 "MyApp" 替换为你的项目名称。

然后,运行以下命令

$ pod install

Carthage

Carthage 是一个去中心化的依赖关系管理器,用于构建您的依赖关系并提供二进制框架。

您可以使用以下命令使用 Homebrew 安装 Carthage

$ brew update
$ brew install carthage

要使用 Carthage 将 BlockHook 集成到您的 Xcode 项目中,请在您的 Cartfile 中指定它

github "yulingtianxia/BlockHook"

运行 carthage update 构建框架,并将构建的 BlockHook.framework 拖放到您的 Xcode 项目中。

手册

导入libffi后,只需将两个文件 BlockHook.h/m 添加到您的项目中。

❤️贡献者

  • 如果您需要帮助或想问一个一般性的问题,请开启一个issue。
  • 如果找到了bug,请开启一个issue。
  • 如果您有功能请求,请开启一个issue。
  • 如果您想做出贡献,请提交一个pull request。

📚文章

👨‍💻 作者

yulingtianxia, [email protected]

👮🏻 许可证

BlockHook 受 MIT 许可证保护。有关更多信息,请参阅 LICENSE 文件。

感谢 MABlockClosure 和 Aspects!