手把手教你开发 JSDebugger 插件:从 JD_REGISTER_PLUGIN 宏到全局 JS 函数
2026/8/18 14:09:54 网站建设 项目流程

手把手教你开发 JSDebugger 插件:从 JD_REGISTER_PLUGIN 宏到全局 JS 函数

【免费下载链接】JSDebuggerJavaScript-Based Debugger For Inspecting Running State Of Your Application项目地址: https://gitcode.com/gh_mirrors/js/JSDebugger

JSDebugger 是一款基于 JavaScript 的 iOS 应用运行时调试工具,它最大的亮点是:不需要手动定义任何 JSExport,就能在 JavaScript 里直接调用任意 Objective-C 方法,随时查看并修改 App 的运行状态。而让 JSDebugger 如此灵活的秘密武器,正是它的插件机制。本文将以新手友好的方式,带你完整走一遍 JSDebugger 插件开发流程——从认识 JD_REGISTER_PLUGIN 宏,到让自定义函数出现在 JS 全局环境中。

什么是 JSDebugger 插件机制?🤔

JSDebugger 把"扩展调试能力"这件事完全交给了插件。官方内置了两个非常实用的插件:

  • choose():遍历堆内存,找出指定类在运行时的所有实例
  • introspect():检查某个对象的所有属性信息

这两个函数在 JS 里用起来就像普通全局函数一样自然:

var vc = choose(ViewController)[0]; // 找到所有 ViewController 实例 var info = introspect(vc); // 查看它的全部属性

它们不是写死在引擎里的,而是通过一套统一的插件机制注册进去的。你完全可以照着它们的样子,写出属于自己的插件。

插件机制的三个关键角色 🧩

JSDebugger 插件机制由三部分构成:

角色职责源码位置
JDFunctionPlugin 协议规定插件必须实现的方法Source/Core/Plugin/JDFunctionPlugin.h
JDFunctionPluginManager收集并注册所有插件Source/Core/Plugin/JDFunctionPlugin.m
JD_REGISTER_PLUGIN 宏一行代码完成"声明 + 注册"同上

JDFunctionPlugin 协议:插件的"身份证" 📇

协议只要求实现两个方法:

  • key:这个插件在 JS 中叫什么名字(比如"choose"
  • function:这个插件对应的 C 回调函数指针

JDFunctionPluginManager:插件的"大管家" 🧑‍💼

它是一个单例,内部维护一个插件数组。addPlugin:负责收集插件,registerPluginsIntoContext:负责把收集到的插件全部写入 JS 全局对象,本质就是用 JavaScriptCore 的JSObjectMakeFunctionWithCallback为每个插件创建一个全局函数。引擎启动时(Source/Core/JDEngine.mstart方法)会自动调用它,所以你完全不需要手动干预。

JD_REGISTER_PLUGIN 宏:三行代码解决注册 ⚡

宏的完整定义是理解插件机制的核心,建议收藏:

#define JD_REGISTER_PLUGIN(IMP, NAME) \ FOUNDATION_EXTERN void JDRegisterPlugin(Class pluginClass); \ + (void)load {JDRegisterPlugin(self);} \ - (NSString *)key {return @NAME;} \ - (JSObjectCallAsFunctionCallback)function {return IMP;}

拆开看,它其实帮我们自动完成了三件事:

  1. 声明注册函数JDRegisterPlugin
  2. +load时机自动注册:类一被加载,就立刻把自己交给插件管理器,无需手动调用
  3. 自动实现协议方法key返回宏里的 NAME,function返回宏里的 IMP 函数指针

也就是说,你只需要写一行JD_REGISTER_PLUGIN,插件就自动被收编进系统了,就是这么简单。🎯

认识官方内置插件:choose 与 introspect 🔍

choose的完整实现约 150 行(C++ 与 Objective-C 混合),核心是通过遍历 malloc 内存区域、比对 isa 指针来定位目标类的实例。但它的插件声明部分只有一行

JD_REGISTER_PLUGIN(&choose, "choose");

introspect更简洁,本质是把对象的所有属性转成数组返回:

JD_REGISTER_PLUGIN(&introspect, "introspect");

参考源码:JDChoose.mm、JDIntrospect.mm。

手把手开发第一个 JSDebugger 插件 🛠️

现在轮到你了!我们来做一个简单但完整的示例:给 JS 增加一个version()函数,返回当前 App 的版本号。

第一步:创建插件类并遵守协议

新建一个 Objective-C 类,声明遵守JDFunctionPlugin协议,并引入头文件。

第二步:写 C 回调函数

实现一个JSObjectCallAsFunctionCallback类型的 C 函数。当 JS 里调用version()时,这个函数就会被触发,并返回一个 JSValueRef:

static JSValueRef version(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef *exception) { // 返回一个 JS 字符串 "1.0.0" return JSValueMakeString(ctx, JSStringCreateWithUTF8CString("1.0.0")); }

第三步:用宏注册

@implementation里写一行即可:

JD_REGISTER_PLUGIN(&version, "version");

第四步:启动引擎并在 JS 中调用 🚀

App 启动时调用[[JDEngine engine] start];,之后在 JS 里就能直接使用:

var v = version(); console.log(v); // 输出 1.0.0

四个实用小贴士 💡

  1. 注册时机是+load:插件类只要被链接进工程就会自动注册,无需手动初始化任何东西。
  2. IMP 参数必须是函数指针:注意宏里传的是&version取地址,不是方法实现。
  3. 注册后的函数不可删除:插件写入全局对象时带有kJSPropertyAttributeDontDelete属性,在 JS 里delete是无效的。
  4. 先用官方 demo 验证:可以运行JSDebuggerDemo/demo.js,里面已经演示了choose()等函数的完整用法,是很好的入门参考。

如何快速跑起来体验插件开发 🏃

最简单的方式是用 CocoaPods 集成(参考JSDebugger.podspecJSDebuggerDemo/Podfile),也可以直接 clone 官方 Demo 工程:

git clone https://gitcode.com/gh_mirrors/js/JSDebugger

打开 JSDebuggerDemo 工程后,配合Playground 热加载功能(JDLocalFileObserver监听文件变化,保存即自动重新执行 JS),改一行脚本马上看到效果,插件开发调试的体验会非常丝滑。✨

结语 🎉

JD_REGISTER_PLUGIN宏到全局 JS 函数,JSDebugger 的插件机制把"给调试器添加新能力"这件事压缩到了极致:一个 C 函数 + 一行宏。掌握了它,你就能按需定制自己的调试工具箱——无论是批量查找对象、动态修改 UI,还是注入自定义调试命令,都能信手拈来。快去动手试试吧!

【免费下载链接】JSDebuggerJavaScript-Based Debugger For Inspecting Running State Of Your Application项目地址: https://gitcode.com/gh_mirrors/js/JSDebugger

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

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

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

立即咨询