用 JavaScript 为 Flipper Zero 开发应用:Momentum Firmware 内置 JS 脚本引擎完全指南

发布时间:2026/9/16 12:47:58
用 JavaScript 为 Flipper Zero 开发应用:Momentum Firmware 内置 JS 脚本引擎完全指南
用 JavaScript 为 Flipper Zero 开发应用Momentum Firmware 内置 JS 脚本引擎完全指南【免费下载链接】Momentum-Firmware Feature-rich, stable and customizable Flipper Firmware项目地址: https://gitcode.com/GitHub_Trending/mo/Momentum-FirmwareJavaScript 已经成为 Flipper Zero 上最平易近人的应用开发方式无需 C/C 功底、无需在 PC 上搭建编译环境写好一个.js文件拷入设备即可从Apps/Scripts菜单直接运行。本文以 Momentum Firmware 内置的 JS 脚本引擎为主线结合仓库源码js_thread.c、js_modules.c、js_app.c 等讲解其运行时架构、内置函数、模块系统与 SDK 兼容机制并完整演示从创建脚本到在设备菜单和 CLI 中运行第一个应用的全过程。一、为什么 Flipper Zero 需要一门脚本语言在 JavaScript 支持加入之前为 Flipper Zero 开发应用的门槛相当高需要掌握 C/C、配置一套交叉编译的开发环境还要研读大量既有应用源码与文档。这对嵌入式开发者来说驾轻就熟但对其他背景的开发者并不友好。Momentum Firmware 在固件中集成了内置脚本引擎直接运行 JavaScript——这一世界上最普及的编程语言之一。你可以创建脚本文件、与他人分享并直接从 Flipper Zero 的Apps/Scripts菜单启动无需在 PC 上编译。JavaScript 应用可以与 Flipper Zero 的各类资源交互包括GUI图形界面对话框、菜单、文本输入、数字输入、文件选择器等按钮按键输入USB-HID 设备模拟键盘/鼠标见 badusb 模块GPIO通用输入输出引脚UART 接口串口通信以及通知LED/振动/蜂鸣、存储、Sub-GHz、红外、i2c、SPI、USB 磁盘等更多外设从仓库的 application.fam 可以完整看到这些能力以模块插件的形式挂在 JS 引擎之下下文会逐一展开。二、技术底座mJS 嵌入式脚本引擎JavaScript 支持基于mJS 脚本引擎mjs 的源码位于仓库 lib/mjs 目录。mJS 最初就是为微控制器设计的对系统资源的利用非常高效。按官方文档描述mJS 仅需不到 50k 的 Flash 空间和 2k 的 RAM这对于资源受限的嵌入式环境至关重要。在保留 mJS 核心特性的同时Momentum 还增加了一些实用改进例如对紧凑二进制数组compact binary arrays的支持。仓库中的 array_buf_test.js 示例脚本就是专门演示二进制数组用法的。注意与浏览器内置的现代 JavaScript 引擎相比mJS 存在一些功能限制。具体的能力边界与限制细节以 mJS 官方文档为准。此外仓库 documentation/js/ReadMe.md 也提醒人工维护的文档可能与实际引擎能力存在出入引擎真正可用的 API 以 fz-sdk 包中的 TypeScript 类型定义.d.ts 和 examples 示例脚本 为准。三、运行时架构脚本是如何在线程中被执行的JS 脚本并不是在应用主线程里同步解释执行的而是被放进一个独立的 Furi 线程中运行。看 js_thread.c 中的js_thread_run()JsThread* js_thread_run(const char* script_path, JsThreadCallback callback, void* context) { JsThread* worker malloc(sizeof(JsThread)); worker-path furi_string_alloc_set(script_path); worker-thread furi_thread_alloc_ex(JsThread, 8 * 1024, js_thread, worker); worker-app_callback callback; worker-context context; furi_thread_start(worker-thread); return worker; }关键信息脚本运行在名为JsThread的独立线程中栈大小为 8 KB。线程启动后调用js_thread()js_thread.c该函数完成以下初始化分配CompositeApiResolver同时挂载固件 API 与应用 API供 FFI 解析符号通过mjs_create()创建 mJS 虚拟机实例在全局对象上注册一组内置函数通过mjs_exec_file()执行脚本文件并把脚本路径写入全局__filename、目录写入__dirname运行结束后统一销毁虚拟机、卸载模块、释放 resolver。3.1 内置全局函数js_thread()在创建虚拟机后向全局对象注册了以下内置函数js_thread.c内置函数作用print(...)输出文本。输出会通过回调送往前台设备屏幕控制台或 CLIdelay(ms)以毫秒为单位阻塞延时。底层用线程标志等待实现可被停止事件打断parseInt(str, base)按指定进制解析整数默认十进制ffi_address(name)获取指定 C 符号的内存地址配合 FFI 使用require(name)加载内置模块或外部插件模块console.log / warn / error / debug(...)分级日志输出对应 FURI_LOG 的 I/W/E/D 级别sdkCompatibilityStatus(major, minor)返回compatible/firmwareTooOld/firmwareTooNewisSdkCompatible(major, minor)返回布尔值脚本期望的 JS SDK 版本与固件是否兼容checkSdkCompatibility(major, minor)不兼容时弹出对话框询问用户是否继续doesSdkSupport([feature, ...])检查固件是否支持给定的扩展特性列表checkSdkFeatures([feature, ...])存在不支持的特性时询问用户是否继续运行此外全局还暴露了console对象以及__filename、__dirname两个路径全局变量。print与console.*的实现都能在 js_thread.c 中找到——例如js_console_warn本质是FURI_LOG_Wjs_console_error本质是FURI_LOG_E方便调试时与系统日志对接。3.2 可中断的延时与停止机制delay()的实现值得一提它并没有使用裸的furi_delay_ms()而是通过furi_thread_flags_wait()等待同时监听ThreadEventStop标志js_thread.c。这意味着脚本在执行delay()期间也可以被停止——停止线程时会设置停止标志delay返回后引擎立即退出。线程的启动与停止分别由js_thread_run()/js_thread_stop()负责js_thread.c。3.3 错误处理与输出脚本执行出错时错误消息与堆栈追踪会通过回调以JsThreadEventError/JsThreadEventErrorTrace事件上报。在设备屏幕上运行时js_app.c 会对堆栈追踪做压缩处理只保留第一行、去掉完整路径仅显示文件名并在末尾提示 See logs for full trace。正常结束则打印--- DONE ---出错打印--- ERROR ---。四、应用入口从 Apps/Scripts 菜单运行脚本JS 运行器应用JS Runner本身也是一个 FAP 应用定义在 application.famappidjs_appentry_pointjs_app。其入口函数js_app()js_app.c的默认浏览路径是EXT_PATH(apps/Scripts)即/ext/apps/Scripts/。运行流程若通过参数指定了脚本路径直接使用该路径否则打开文件浏览器过滤条件为.js扩展名并显示js_script图标js_app.c选中脚本后控制台视图打印Running 脚本名随后js_thread_run()启动脚本线程脚本输出实时显示在设备屏幕上直到运行结束或用户退出。整个应用由两个视图组成JsAppViewLoading加载视图与JsAppViewConsole控制台视图控制台视图来自 views/console_view.c用于把print()的输出渲染到屏幕上。五、通过 CLI 运行脚本除了设备菜单脚本还可以通过CLI命令行接口在 PC 上远程运行——这对调试尤其方便你可以在电脑上直接编写、测试代码无需在 PC 与设备之间来回切换。CLI 命令的实现位于 js_app.c 的js_cli_execute()注册为CLI_COMMAND_INTERFACE(js, ...)。用法js /ext/apps/Scripts/first_app.jsCLI 模式下的行为细节不带参数时输出用法提示Usage: js path文件不存在时报错Can not open file path运行开始提示Running script path, press CTRLC to stop按CTRLC可随时中断脚本通过轮询管道断开状态实现与屏幕模式不同print()的全部输出直接送往 CLI而不是设备屏幕出错时打印---- ERROR ----、堆栈追踪Trace:并退出正常结束打印Script done!。CLI 入口在 application.fam 中以cli_js插件entry_pointcli_js_ep的形式单独注册仅面向 f7 目标。六、模块系统内置模块与外部插件require()是脚本访问硬件能力的关键入口。模块加载逻辑实现在 js_modules.c整体流程为剥掉可选前缀模块名若以vendor/fz-sdk/开头如next-flip/fz-sdk/gpio前缀会被忽略只按后面的名字查找查重同名模块已加载则报错查找内置模块在modules_builtin[]数组中匹配js_modules.c查找外部插件若内置模块中没有则把模块名中的/替换为__拼出路径/ext/apps_data/js_app/plugins/js_name.fal通过插件管理器动态加载 FAP 插件js_modules.c。外部插件若依赖其他未加载模块会加载失败其提供的 API 表还会被动态加入 resolver执行构造函数模块找到后调用其 create 构造函数返回 JS 对象给脚本。6.1 内置模块当前固件内置两个模块flipper与tests后者仅在单元测试构建下启用。flipper模块的实现见 modules/js_flipper.c提供API说明flipper.getModel()获取设备型号名flipper.getName()获取设备自定义名称未设置时返回Unknownflipper.getBatteryCharge()获取当前电池电量百分比flipper.firmwareVendor固件厂商标识字符串flipper.jsSdkVersion固件内置的 JS SDK 版本号数组[major, minor]6.2 插件模块目录从 application.fam 可以看到JS 引擎的能力通过大量 FAP 插件扩展每个插件对应一组脚本 API模块覆盖能力event_loop事件循环modules/js_event_loopgui及其视图插件对话框、子菜单、文本输入、数字输入、按钮面板、弹窗、菜单、列表、字节输入、文本框、文件选择器、小部件、图标、加载、空屏modules/js_guinotificationLED、振动、蜂鸣通知modules/js_notification.cbadusbUSB HID 键盘/鼠标模拟serialUART 串口通信gpio通用输入输出math数学库扩展storage文件系统读写vgmIMUICM42688P姿态传感器subghzSub-GHz 射频收发infrared红外信号发送blebeaconBLE 信标广播usbdiskUSB 大容量存储盘i2cI2C 总线通信spiSPI 总线通信这些模块在脚本中统一通过require(模块名)引入。例如 notify.jslet notify require(notification); notify.error(); delay(1000); notify.success(); delay(1000); for (let i 0; i 10; i) { notify.blink(red, short); delay(500); }而 load_api.js 则展示了如何用require()加载一个导出对象的模块对象字面量直接作为模块返回值。七、SDK 兼容性机制让脚本在多种固件上都能工作由于同一份 JS 脚本可能运行在官方固件、Momentum 及其他合规自定义固件上引擎提供了运行时 SDK 兼容性检查。相关实现集中在 js_modules.c版本兼容脚本通过sdkCompatibilityStatus(major, minor)声明期望的 JS SDK 版本固件侧按JS_SDK_MAJOR/JS_SDK_MINOR比较js_modules.c期望版本低于固件 →firmwareTooNew期望版本高于固件 →firmwareTooOld相等 →compatible。特性兼容固件声明了一个extra_features特性列表js_modules.c包括扩展模块blebeacon、i2c、spi、infrared-send、subghz、usbdisk、vgm扩展特性gui-textinput-illegalsymbols、storage-virtual、usbdisk-createimage。脚本可以用doesSdkSupport([...])检测这些特性是否存在用checkSdkFeatures([...])在脚本开头做强制检查——若固件不支持会弹出对话框Outdated Firmware 或 Outdated Script询问用户是返回还是继续运行js_modules.c。这正是官方 fz-sdk README 中推荐的做法使用扩展特性时用if (doesSdkSupport([feature-name])) { ... }包裹保证脚本在官方固件上也能优雅降级。八、实战创建并运行你的第一个 JS 应用下面完整走一遍从零创建脚本到在设备上运行的流程。你需要一台 Flipper Zero、一台 PC、一根 USB 线。8.1 创建脚本文件新建文本文件first_app.js粘贴以下代码并保存print(start); delay(1000); print(1); delay(500); print(2); delay(500); print(3); delay(500); print(end);这段代码做的事情输出文本start等待 1 秒依次输出数字1、2、3每个数字后停顿 0.5 秒输出文本end。print()是内置函数用于输出文本括号中是要输出的字符串——它不需要引入任何 JS 模块可以在应用的任何位置使用。delay()同样是内置函数参数为毫秒1000 毫秒 1 秒因此 1 秒延时写作10000.5 秒写作500。更多内置函数清单见 Built-in functions。8.2 将文件拷贝到 Flipper Zero用 USB 线将 Flipper Zero 连接到 PC打开qFlipper应用进入File manager标签页打开路径SD Card/apps/Scripts/把first_app.js拖入该窗口。拷贝完成后脚本就可以在设备上运行了若目录不存在可自行创建或参考仓库中 examples/apps/Scripts 的目录结构。8.3 方式一从设备菜单运行在 Flipper Zero 菜单中进入Apps → Scripts这里会列出SD Card/apps/Scripts/文件夹中的所有脚本选择要运行的脚本按OK键运行。设备屏幕会按照print()与delay()的定义以指定间隔依次显示这些字符串。8.4 方式二通过 CLI 远程运行CLI 运行方式非常适合调试——你可以在 PC 上直接编写和测试代码无需在 PC 与设备之间来回切换。用 USB 线连接 Flipper Zero 到 PC通过推荐的方式进入 CLI串口终端等输入js命令把path替换为设备上脚本的实际路径js /ext/apps/Scripts/first_app.js与从设备 UI 运行不同CLI 模式下所有print()输出都会发送到命令行终端而不是设备屏幕——这让日志查看和调试更加方便。8.5 下一步掌握了基础运行方式后可以继续阅读 使用 JavaScript SDK 开发应用了解如何用 TypeScript 类型、SDK 工具链组织更复杂的项目。九、仓库内置示例脚本仓库在 examples/apps/Scripts/Examples 中打包了丰富的示例脚本随 JS Runner 应用作为资源分发见 application.fam 中的resourcesexamples覆盖了大部分模块的用法基础delay.js延时、math.js数学、stringutils.js字符串、console.js、path.jsGUIgui.js多种界面控件通信uart_echo.js/uart_echo_8e1.jsUART 回环含 8E1 校验模式、bad_uart.js存储storage.js、load.js/load_api.js模块加载、usbdisk.jsUSB 磁盘硬件外设gpio.js、i2c.js、spi.js、infrared-send.js红外发送、subghz.jsSub-GHz、blebeacon.jsBLE 信标系统能力notify.jsLED/振动/蜂鸣通知、badusb_demo.jsUSB 键盘模拟、event_loop.js事件循环数据array_buf_test.js紧凑二进制数组另外 interactive.js 是一个交互式示例可用于验证脚本与界面控件的双向交互。十、用 TypeScript SDK 开发更复杂的应用对于较大的项目Momentum 提供了基于 TypeScript 的fz-sdk包位于 applications/system/js_app/packages/fz-sdk它是官方 Flipper Zero JS SDK 的分支为 Momentum 的扩展 API 补充了类型定义。其 README 明确说明为官方 JS SDK 编写的脚本可以直接在 Momentum Firmware 上运行。使用交互式向导创建新项目npx next-flip/create-fz-app-mntmlatest然后进入项目目录并启动开发流程cd my-flip-app npm start也可以使用pnpm或yarn。SDK 的版本号采用 semver 语义major.minor 与目标 Flipper Zero JS SDK 版本对应例如用 SDK0.1.0编写的应用兼容0.1及以上、1.0以下的所有固件版本。每个 API 的版本历史记录在其 JSDoc 注释中官方强烈建议组合使用sdkCompatibilityStatus、isSdkCompatible、checkSdkCompatibility来声明并校验兼容性。所有 API 的类型定义.d.ts是引擎实际能力的最可靠参考因为手工维护的文档可能存在滞后。结语从内置脚本引擎到模块插件体系再到 SDK 兼容性检查Momentum Firmware 为 JavaScript 应用提供了一条从零基础脚本到工程化 TypeScript 项目的完整路径。无论你只是想快速写一个小工具还是希望复用官方与社区生态中的 JS 模块都可以从SD Card/apps/Scripts/下的第一个first_app.js开始让 Flipper Zero 按你的脚本行事。【免费下载链接】Momentum-Firmware Feature-rich, stable and customizable Flipper Firmware项目地址: https://gitcode.com/GitHub_Trending/mo/Momentum-Firmware创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考