BlockHook
使用libffi挂钩Objective-C blocks。它是一个强大的Blocks方面的AOP工具。BlockHook可以在调用block之前/代替/之后运行您的代码。BlockHook甚至可以在block dealloc时通知您。您可以使用BlockHook跟踪块的整个生命周期!
想要挂钩传递给方法的blocks吗?试试BlockTracker!
🌟 特性
- 易于使用。保持您的代码清晰。
- 支持4种钩子模式:之前、代替、之后和废弃。
- 允许您修改返回值和参数。
- 支持调用原始实现。
- 可以在任何时候移除钩子。
- 遍历块的所有钩子令牌。
- 提供块泛型名称。
- 自我管理令牌。
- 支持自定义结构。
- 支持 Carthage 和 CocoaPods。
🔮 示例
BlockHook 需要 libffi 库,支持 iOS、tvOS 和 macOS。您可以运行 BlockHookSample iOS
、BlockHookSample tvOS
或 BlockHookSample 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。
📚 文章
- 使用Libffi Hook Objective-C Block
- 使用结构体实现的BlockHook
- 使用撤销实现的BlockHook
- 使用私有数据实现的BlockHook
- 使用调用的BlockHook(1)
- 使用调用的BlockHook(2)
👨💻 作者
yulingtianxia, [email protected]
👮🏻 许可证
BlockHook 受 MIT 许可证保护。有关更多信息,请参阅 LICENSE 文件。
感谢 MABlockClosure 和 Aspects!