ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

JRSwizzle新特性解析:withBlock如何优雅Hook方法?NSInvocation机制深度揭秘

JRSwizzle新特性解析:withBlock如何优雅Hook方法?NSInvocation机制深度揭秘 JRSwizzle新特性解析withBlock如何优雅Hook方法NSInvocation机制深度揭秘【免费下载链接】jrswizzleone-stop-shop for all your method swizzling needs项目地址: https://gitcode.com/gh_mirrors/jr/jrswizzleJRSwizzle 是一款 Objective-C 方法交换Method Swizzling工具库其 v1.1.0 版本新增的withBlock 特性让开发者可以只用一个 Block 就优雅地 Hook 任意方法并借助 NSInvocation 机制灵活修改参数、调用原实现、读取返回值。本文将带你快速搞懂 withBlock 方法 Hook 的原理与用法。为什么要用 withBlock 来做方法 Hook传统的 objc 方法交换需要三步写一个影子方法、声明到分类里、再手动交换实现。而 JRSwizzle 经典的 jr_swizzleMethod:withMethod:error: 接口虽然只需一行调用但 Hook 逻辑仍然要提前写成独立方法不够灵活。v1.1.0 新增的 jr_swizzleMethod:withBlock:error: 和 jr_swizzleClassMethod:withBlock:error: 解决了这个问题Hook 逻辑直接写进 Block 里还能在 Hook 内部暂停原方法、改参数、拿返回值非常适合埋点、监控、A/B 测试等场景。快速上手3 步完成 withBlock 方法交换1️⃣ 安装 JRSwizzle 依赖项目自带 JRSwizzle.podspec用 CocoaPods 即可引入MIT 协议iOS 4.3 / OS X 10.6pod JRSwizzle也可以直接 clone 源码仓库git clone https://gitcode.com/gh_mirrors/jr/jrswizzle2️⃣ 写 Hook 代码完成方法交换以 HookinitWithCoder:为例完整示例见 JRSwizzle.h 的注释__block NSInvocation *invocation nil; invocation [MyView jr_swizzleMethod:selector(initWithCoder:) withBlock:^(id obj, NSCoder *coder) { NSLog(before %, obj); [invocation invokeWithTarget:obj]; // 这里才执行原实现 id ret nil; [invocation getReturnValue:ret]; // 拿到返回值 NSLog(after %, ret); return ret; } error:nil];注意两个关键点用__block修饰 invocation因为 Block 内部要引用这个还没赋值完的变量必须先调用[invocation invokeWithTarget:]类方法则直接[invocation invoke]才能执行原方法否则原逻辑会被跳过。3️⃣ Hook 类方法一行切换Hook 类方法时换成 jr_swizzleClassMethod:withBlock:error: 即可它会自动把 invocation 的 target 设为类本身Block 里直接[classInvocation invoke]就能调用原类方法。源码揭秘withBlock 方法交换的 4 个关键步骤核心实现只有 15 行左右位于 JRSwizzle.m拆解如下第 1 步Block 转函数指针IMP blockIMP imp_implementationWithBlock(block);运行库把 Block 包装成一个可直接调用的实现IMP。这样 Block 就能冒充一个 ObjC 方法。第 2 步动态注册唯一选择器NSString *blockSelectorString [NSString stringWithFormat:_jr_block_%_%p, ...]; SEL blockSel sel_registerName([...]);JRSwizzle 用_jr_block_原方法名_Block内存地址拼出一个临时选择器并注册到运行库保证多次 Hook 互不冲突——同一方法可以被 Hook 多次。第 3 步把 Block 挂载成类方法class_addMethod(self, blockSel, blockIMP, origSelMethodArgs);复用原方法的类型编码type encoding注册临时方法同时基于同一份类型信息构造好 NSMethodSignature生成返回给用户的NSInvocation对象。第 4 步复用经典 swizzling 完成交换[self jr_swizzleMethod:origSel withMethod:blockSel error:nil];最后调用项目里久经考验的 经典方法交换实现它先检查继承方法陷阱这正是 JRSwizzleTest/ 中 Scenario 7/8 测试覆盖的场景必要时用class_addMethod把继承方法提升到当前类再交换 IMP。NSInvocation 在这里的角色它就像一个可暂停、可改参、可读取返回值的方法调用遥控器。withBlock 接口把 invocation 返回给调用方Block 执行时就拥有了完整的调用控制权——这就是 深度 Hook 与普通 Hook 的本质区别。性能注意事项与实用建议要点说明⚠️ 性能NSInvocation 本身开销不小官方 README 也明确提示not the fastest of APIs高频调用的方法不建议用 withBlock可改用经典 withMethod 接口✅ 时机方法交换应尽早执行推荐load或initialize且每次只交换一次多次交换会叠加 Hook✅ 恢复再次用同一接口交换一次即可还原Block 版可传回原逻辑再交换或以原方法换回✅ 排查出错时通过error参数读取诊断信息JRSwizzle 的错误提示非常详细见 SetNSError 宏总结JRSwizzle 的 withBlock 特性把方法交换 参数拦截 返回值读取三件事压缩进一段 Block 代码底层通过imp_implementationWithBlock将 Block 变成方法实现动态注册临时选择器后复用经典 swizzling 完成交换再借NSInvocation把调用控制权交还给你。对于埋点、兼容性补丁、第三方库行为定制等场景它是目前最轻量的 objc 方法 Hook 方案之一。相关源码导航接口声明JRSwizzle.hBlock 版交换实现JRSwizzle.m经典交换与继承方法处理JRSwizzle.m测试用例JRSwizzleTest/JRSwizzleTest.m项目介绍与版本历史README.markdown【免费下载链接】jrswizzleone-stop-shop for all your method swizzling needs项目地址: https://gitcode.com/gh_mirrors/jr/jrswizzle创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表