JSPatch扩展机制详解:1行代码动态加载扩展,3行代码支持自定义Struct类型
2026/9/19 13:47:02 网站建设 项目流程

JSPatch扩展机制详解:1行代码动态加载扩展,3行代码支持自定义Struct类型

【免费下载链接】JSPatchJSPatch bridge Objective-C and Javascript using the Objective-C runtime. You can call any Objective-C class and method in JavaScript by just including a small engine. JSPatch is generally used to hotfix iOS App.项目地址: https://gitcode.com/gh_mirrors/js/JSPatch

🔥JSPatch 扩展机制是 JSPatch 动态化引擎最实用的进阶能力:JSPatch 通过 Objective-C 运行时桥接 JavaScript 与 iOS 原生代码,常用于 iOS App 热修复(hotfix)。而它的**扩展机制(JPExtension)**让你只需1 行代码动态加载扩展,就能解锁 Block 回调、C 函数调用、协议实现等高级能力;再配合defineStruct接口,3 行代码即可支持自定义 Struct 类型在 JS 与 OC 之间自由转换。本文将用最短路径带你吃透这套机制。

什么是 JSPatch 扩展机制?

JSPatch 的核心是一个极小的引擎,源码仅 3 个文件:

  • JPEngine.h
  • JPEngine.m
  • JSPatch.js

引擎本身只负责"JS 调 OC 方法"这件事,而 Block 回调、C 函数调用、协议定义等高级功能,全部以**扩展(Extension)**的形式独立放在Extensions/目录中。

每个扩展都继承自JPExtension基类(定义见 JPEngine.h),它要求实现一个类方法:

+ (void)main:(JSContext *)context;

这个方法的职责是:往 JS 引擎的JSContext里"注入"若干全局函数(如block()defineCFunction())。注入后,你的 JS 脚本就能直接调用这些函数——这就是 JSPatch 扩展机制的完整原理

1行代码动态加载扩展:addExtensions 完整指南

🚀 加载扩展只需要一行代码,调用JPEngine的类方法:

[JPEngine addExtensions:@[@"JPBlock", @"JPCFunction", @"JPProtocol"]];

addExtensions:的实现在 JPEngine.m:它会遍历传入的类名数组,通过NSClassFromString找到对应的扩展类,并逐个调用其main:方法完成注入。

⚠️ 新手常见误区:

  • 顺序要求:必须先把扩展的源码加入工程编译,再调用addExtensions:
  • 类名即字符串:数组元素是类名字符串,写错会静默失败,注意检查;
  • 加载时机:建议放在startEngine之后、执行任何 JS 脚本之前。

内置扩展清单:按需加载即可

扩展源码位置提供的 JS 能力
JPBlockExtensions/JPBlock/block()从 JS 向 OC 传递 Block 回调
JPCFunctionExtensions/JPCFunction/JPCFunction.hdefineCFunction()调用系统 C 函数
JPStructPointerExtensions/JPCFunction/JPStructPointer.mnewStruct()/pvalStruct()操作 Struct 指针
JPProtocolExtensions/JPProtocol.hdefineProtocol()用 JS 定义并实现协议
JPNumberExtensions/JPNumber.h修复 iOS 7 下NSNumber的精度问题
JPLockerExtensions/JPLocker.h跨 JS/OC 互斥锁,解决多线程调用冲突
JPDispatchExtensions/JPDispatch.h补充 GCD 调度函数
JPCleanerExtensions/JPCleaner.hcleaner帮助 JS 持有对象正确释放

所有扩展源码集中在 Extensions/ 目录,可按需挑选,保持包体积最小。

3行代码支持自定义Struct类型:defineStruct 使用教程

CGRect、CGPoint、CGSize、NSRange 这 4 个 Struct 是 JSPatch 内置支持的(在 JPEngine.m 的JPForwardInvocation中硬编码处理)。但业务里经常遇到自定义 Struct,怎么办?

✨ 调用JPEnginedefineStruct:接口(声明见 JPEngine.h),3 行代码搞定:

[JPEngine defineStruct:@{ @"name": @"MyPoint", @"types": @"ff", @"keys": @[@"x", @"y"] }];

三个键的含义:

含义示例
nameOC 中的 Struct 类型名@"MyPoint"
types各成员的类型编码串(f=float,d=double,i=int……)@"ff"表示两个 float
keysJS 侧对应的属性名@[@"x", @"y"]

注册之后效果立竿见影:

  • OC 方法返回该 Struct 时,JS 里自动得到一个普通对象:{x: 10, y: 20}
  • JS 向 OC 方法传入该 Struct 时,直接传 JS 对象即可,引擎自动还原为 C 内存布局。

注册逻辑见 JPEngine.m:定义被存入_registeredStruct字典,JPForwardInvocation转发调用时会按类型编码自动完成双向转换。

Struct 指针也能操作:newStruct 与 pvalStruct

如果 OC 方法接收的是Struct 指针(如CGPoint *),则需要额外一步:先newStruct分配内存,再传指针,用完用pvalStruct读取——实现在 JPStructPointer.m:

var p = newStruct("CGPoint", {x: 1, y: 2}); // 分配并填充 var v = pvalStruct("CGPoint", p); // 读回 {x:1, y:2}

进阶:3行JS调用系统C函数

JSPatch 扩展机制不止于 Struct。加载JPCFunction扩展后,可在 JS 里声明并调用任意系统 C 函数(如 CoreFoundation 的CFStringCreateWithCString),核心源码见 JPCFunction.m。它借助 JPLibffi/(libffi)完成函数签名解析,因此自定义 Struct 也能作为 C 函数的参数与返回值传递。

新手避坑清单 📌

  1. 忘记加扩展源码addExtensions:只是"加载",前提是扩展的 .m 文件已加入编译,否则NSClassFromString返回空;
  2. types 写错defineStruct的类型编码串必须与 C 内存布局严格一致,floatfdoubled,差一个字符都会导致数据错乱;
  3. 多线程冲突:JS 与 OC 并发访问时,建议同时加载JPLocker扩展;
  4. 对象释放:JS 侧创建的 OC 对象若需提前释放,配合JPCleaner使用。

小结

  • 1 行代码addExtensions:→ 动态加载 JSPatch 扩展,按需解锁 Block、C 函数、协议等能力;
  • 3 行代码defineStruct:→ 让自定义 Struct 类型在 JS 与 OC 之间无缝互转;
  • 所有扩展源码位于 Extensions/,核心调度逻辑在 JPEngine.m,建议对照源码阅读本文,理解会更深。

掌握 JSPatch 扩展机制,你的 iOS 热修复与动态化玩法将再上一个台阶 🎉

【免费下载链接】JSPatchJSPatch bridge Objective-C and Javascript using the Objective-C runtime. You can call any Objective-C class and method in JavaScript by just including a small engine. JSPatch is generally used to hotfix iOS App.项目地址: https://gitcode.com/gh_mirrors/js/JSPatch

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询