Flipper Zero Unleashed Firmware JavaScript 引擎入门:用 mJS 为设备编写脚本应用

发布时间:2026/9/13 14:55:07
Flipper Zero Unleashed Firmware JavaScript 引擎入门:用 mJS 为设备编写脚本应用 Flipper Zero Unleashed Firmware JavaScript 引擎入门用 mJS 为设备编写脚本应用【免费下载链接】unleashed-firmwareFlipper Zero Unleashed Firmware项目地址: https://gitcode.com/GitHub_Trending/un/unleashed-firmware本文以 documentation/js/js_about.md 为主线系统介绍 Unleashed 固件内置的 JavaScript 脚本引擎它基于专为微控制器设计的 mJS 引擎让开发者无需搭建 C/C 工具链即可为 Flipper Zero 编写应用。读完本文你将理解该引擎的架构与资源特性掌握从创建脚本文件、拷贝到设备、通过菜单或 CLI 运行到使用内置函数与外部 JS 模块的完整开发链路。为什么在固件里内置 JavaScript 引擎在 JavaScript 支持引入之前为 Flipper Zero 编写应用通常需要 C/C 技能、配置交叉编译环境并研读现有应用源码与文档。这对嵌入式开发者而言习以为常但对来自其他背景的开发者门槛较高。Unleashed 固件因此在固件中集成了一个内置脚本引擎来运行 JavaScript——这门世界上使用最广泛的语言之一——使应用开发显著更加亲民。带来的直接变化是你可以创建脚本文件、与其他人分享并直接从 Flipper Zero 的Apps/Scripts菜单启动它们完全不需要在 PC 上进行编译。脚本以纯文本形式存放在 microSD 卡的SD Card/apps/Scripts/目录中设备上的 JS Runner 应用负责发现与执行。从源码结构看JS 运行时被组织为独立的 Flipper 应用模块其应用清单定义在 applications/system/js_app/application.fam 中其中js_app即 JS Runner是面向图形界面的外部应用cli_js则作为 CLI 插件提供命令行入口二者共用 js_app.c、js_thread.c 等同一套执行核心。引擎底座为微控制器而生的 mJSJavaScript 支持建立在 mJS 脚本引擎 之上。mJS 最初即为微控制器设计对系统资源的使用非常高效——占用不到 50KB 的 Flash 空间和 2KB 的 RAM——这使它能够轻松容纳在 Flipper Zero 的 STM32WB55 资源预算内。Unleashed 固件保留了 mJS 的核心特性并在此基础上加入了一些实用改进例如对紧凑二进制数组compact binary arrays的支持。mJS 的源码位于仓库的 lib/mjs 目录其构建脚本 lib/mjs/SConscript 将该库编译为静态库并导出了mjs_core_public.h、mjs_exec_public.h、mjs_object_public.h、mjs_string_public.h、mjs_array_public.h、mjs_primitive_public.h、mjs_util_public.h、mjs_array_buf_public.h等头文件作为 SDK 接口供上层应用调用。[!note] 与浏览器内置的现代 JavaScript 引擎相比mJS 存在一些功能限制。关于能力与局限的细节请参阅 mJS 的官方文档。脚本执行线程与资源模型从 js_thread.c 的实现可以看到每个脚本在独立的JsThread中执行线程由furi_thread_alloc_ex(JsThread, 8 * 1024, js_thread, worker)创建分配8KB 栈空间脚本路径、执行回调与上下文被封装进JsThread结构体furi_thread_start启动后立即返回执行期间可通过js_thread_stop()向线程投递ThreadEventStop事件标志来中止脚本见 js_thread.c。每次脚本运行时执行核心会完成以下初始化流程见 js_thread.c创建CompositeApiResolver注册固件 API 与应用 API 两个解析接口供 FFI外部函数接口按名称解析 C 函数地址调用mjs_create创建解释器实例创建模块管理器js_modules_create向全局对象注入内置函数print、delay、parseInt、ffi_address、require、console对象及 SDK 兼容性系列函数并设置__filename、__dirname全局变量设置 FFI 解析器与执行标志轮询器用于响应停止请求调用mjs_exec_file执行脚本文件并根据返回错误码通过回调上报Done/Error/ErrorTrace事件。JavaScript 应用可以访问哪些设备资源JavaScript 应用可以与 Flipper Zero 的各类资源交互包括GUI视图、控件与对话框由 js_gui 模块提供按钮读取设备物理按键输入USB-HID 设备模拟键盘badusb 模块、鼠标等GPIO读取与控制引脚js_gpio 模块UART 接口串口收发数据js_serial 模块此外还包括存储js_storage、Sub-GHz 射频js_subghz、红外js_infrared、通知/振动js_notification、数学函数js_math等大量能力。这些能力全部通过JS 模块JS modules对外暴露。模块使用 C/C 编写以保证执行效率随固件分发并以FALFlipper Application File格式编译存储在 microSD 卡上。完整的模块清单定义在 applications/system/js_app/application.fam其中包括模块功能领域源码位置flipper设备信息型号、名称、电量applications/system/js_app/modules/js_flipper.cgui及 16 个视图插件界面与控件loading、submenu、text_input、widget、dialog 等applications/system/js_app/modules/js_guinotificationLED、振动、声音提示applications/system/js_app/modules/js_notification.cbadusbUSB 键盘模拟applications/system/js_app/modules/js_badusb.cserial串口收发applications/system/js_app/modules/js_serial.cgpioGPIO 与 PWMapplications/system/js_app/modules/js_gpio.cmath数学函数applications/system/js_app/modules/js_math.cstorage文件系统访问applications/system/js_app/modules/js_storage.csubghz、infrared、vgm、blebeacon、usbdisk、i2c、spi射频、红外、运动传感器、BLE 信标、USB 存储、I2C/SPI 总线applications/system/js_app/modules例如内置的flipper模块通过furi_hal_version_get_model_name()、furi_hal_version_get_name_ptr()与 Power 服务读取设备信息向 JS 暴露getModel()、getName()、getBatteryCharge()、firmwareVendor与jsSdkVersion五个成员见 js_flipper.c。模块的加载机制require()在使用任何 JS 模块的方法之前必须先通过require()函数导入该模块将其加载进 RAM。加载逻辑实现在 js_modules.c其查找顺序为内置模块flipper以及单元测试构建下的tests被静态编译进运行时见 js_modules.c无需额外加载外部模块按模块名映射为MODULES_PATH即/ext/apps_data/js_app/plugins下的js_name.fal文件通过plugin_manager_load_single以插件形式动态加载模块名中的/会被替换为__以兼容 SDK 的flipperdevices/fz-sdk/module命名前缀。为节省 RAM 并提升性能应避免加载用不到的模块所有已加载模块会在应用执行结束后自动卸载见 js_modules.c 的销毁流程。示例let notify require(notification); notify.success(); print(success notification);创建你的第一个 JavaScript 应用下面通过一个输出序数并带延迟的简单脚本体验从创建到运行的完整流程。你只需要一台 Flipper Zero、一台 PC 和一根 USB 数据线。第一步创建脚本文件新建文本文件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 模块可在应用的任何位置直接使用。从 js_thread.c 的实现看它会把所有参数统一转成字符串通过JsThreadEventPrint回调交给 UI 或 CLI 通道输出delay()实现延时括号内给出以毫秒为单位的延时时间。1000 毫秒等于 1 秒所以 1 秒延时写作 10000.5 秒写作 500。其底层通过furi_thread_flags_wait实现能在等待期间响应停止信号见 js_thread.c。[!note] 内置函数的完整列表见 documentation/js/js_builtin.md。第二步把文件拷贝到 Flipper Zero用 USB 数据线将 Flipper Zero 连接到 PC打开qFlipper应用进入File manager文件管理器标签页打开路径SD Card/apps/Scripts/将文件拖放进 qFlipper 窗口。至此脚本已经就绪可以运行了。第三步运行脚本运行脚本有两种方式从 Flipper Zero 菜单运行或从 PC 通过 CLI 远程运行。方式一从设备菜单运行在 Flipper Zero 菜单中进入Apps → Scripts这里会列出SD Card/apps/Scripts/目录下的所有脚本选中要运行的脚本按OK键执行。此时设备屏幕会按print()与delay()的定义以指定间隔逐行显示字符串。从 js_app.c 的入口实现看JS Runner 应用会打开EXT_PATH(apps/Scripts)目录使用 Dialogs 文件浏览器过滤.js文件图标为I_js_script_10px选中后在控制台视图JsConsoleView中显示Running name提示并启动脚本线程。脚本异常时应用会将堆栈信息压缩为单行仅保留文件名见 js_app.c显示在屏幕上完整跟踪则需要查看日志。方式二通过 CLI 运行CLI 是基于文本的接口适合调试场景——你可以远程编写和测试代码无需在 PC 与设备之间来回切换。用 USB 数据线连接 Flipper Zero 到 PC使用推荐的方式进入 CLI输入js path命令其中path为脚本在设备上的路径js /ext/apps/Scripts/first_app.js与在设备 UI 中运行不同通过 CLI 运行时print()的所有输出都会发送到 CLI 终端而不是设备屏幕。CLI 命令的实现位于 js_app.cjs_cli_execute会校验参数与文件是否存在随后在子线程中执行脚本将print输出逐行回传到 CLI脚本结束后打印Script done!运行中可按CTRLC停止出错时则会打印---- ERROR ----与堆栈信息后自动退出。内置函数与运行时能力一览除print()与delay()外运行时还提供了以下内置能力完整参考见 documentation/js/js_builtin.md函数/对象说明示例require(name)加载模块插件let serial require(serial);load(path[, scope])运行一个 JS 文件并返回其值load(/ext/apps/Scripts/script.js);chr(num)ASCII 字符编码转字符串chr(65); // Adie(msg)带消息退出 JavaScriptdie(Some error occurred);parseInt(str[, base])字符串转数字可指定进制parseInt(7b, 16); // 123console.log/warn/error/debug与print类似但仅输出到串口控制台并带日志级别console.log(hi);Number.toString([base])数字转字符串可指定进制(123).toString(16); // 0x7bArrayBuffer/ 类型化数组byteLength、slice()支持Uint8Array、Int16Array、Uint32Array等视图Uint8Array([1,2,3]).buffer.slice(0, 1)Arraylength、push()、splice()arr.splice(1); // [2, 3]Stringlength、charCodeAt()、at()、indexOf()、slice()、toUpperCase()、toLowerCase()Example.indexOf(amp); // 2__dirname/__filename当前脚本所在目录 / 当前脚本完整路径print(__dirname); // /ext/apps/Scripts其中console对象与 SDK 兼容性函数见下文由 js_thread.c 在初始化时注入全局作用域console.log等分别通过FURI_LOG_I/W/E/D写入固件日志对应 js_thread.c。脚本与固件的 SDK 兼容性检查随着固件与 JS SDK 版本演进老脚本在新固件或新脚本在老固件上可能无法正常运行。为此运行时内置了 5 个兼容性检查函数实现在 js_modules.c函数行为sdkCompatibilityStatus(major, minor)返回compatible、firmwareTooOld或firmwareTooNewisSdkCompatible(major, minor)上述判断的布尔版本checkSdkCompatibility(major, minor)版本不兼容时弹出对话框询问用户是否继续执行doesSdkSupport([feature, ...])检查解释器是否支持全部指定特性checkSdkFeatures([feature, ...])特性不支持时询问用户是否继续版本比较逻辑见 js_modules.c期望主版本低于固件 SDK 版本判定为firmwareTooNew固件太新期望主版本高于固件版本、或主版本相同但次版本更高则判定为firmwareTooOld否则视为兼容。运行时支持的特性列表extra_features数组见 js_modules.c包含gpio-pwm、gui-widget、serial-framing、blebeacon、i2c、spi、infrared-send、subghz、usbdisk、vgm等。不兼容时弹出的确认对话框由 js_modules.c 实现显示警告图标与 This script may not work as expected 文案用户可选择Go back放弃执行或Run anyway继续运行。使用 JavaScript SDK 提升开发效率直接通过 qFlipper 反复拷贝、运行脚本进行调试较为繁琐。更高效的方式是使用Flipper Zero JavaScript SDK——一套以 NPM 包flipperdevices/fz-sdk形式分发的开发工具主要特性详见 documentation/js/js_developing_apps_using_js_sdk.md单命令加载并运行应用代码补全需支持 Language Server 的编辑器/IDE如 VS CodeJS 代码压缩器minifier。安装与初始化在 PC 上安装Node.js npmSDK 依赖 Node.js 运行时在准备存放项目的文件夹中打开终端运行以下命令创建应用模板并引入 SDK该命令会启动交互式向导需要指定项目名称并选择包管理器npx flipperdevices/create-fz-applatest完成后项目文件夹中会生成应用模板、SDK 包、全部依赖与配置应用代码位于index.ts文件中。运行与更新应用连接 Flipper Zero 后在应用目录中执行npm start该命令会把 JS 文件拷贝到设备并立即运行print()的输出会直接显示在终端中。修改代码后再次执行npm start即可完成更新——只要设备仍保持连接新版本会自动启动设备上的旧.js文件也会被替换。代码补全与压缩器代码补全由于项目基于 TypeScript 开发编辑器可提供更准确的补全与类型检查减少查阅文档的频率JS minifier通过移除空格、制表符、换行等冗余字符并缩短变量名来减小文件体积可使脚本运行略微加速且不改变逻辑缺点是压缩后的报错信息难以阅读因此默认关闭。需要时在应用目录的fz-sdk.config.json5中设置minify: true脚本在上传到设备前即被压缩。与原生 Flipper JavaScript 的差异使用 JS SDK 时开发语言是TypeScript代码与基础 Flipper JS 存在差异需要注意以下几点模块导入不再使用let module require(module);而是import * as module from flipperdevices/fz-sdk/module;多源码文件SDK 目前不支持多个.ts文件之间的互相导入可以使用load()但这样做无法获得 TypeScript 类型检查类型转换部分 Flipper JS 函数会返回泛型类型例如eventLoop.subscribe()的回调参数是泛型Item必要时需先转换再使用例如内联转换stringitem或用新类型声明let text item as string;。执行npm start时脚本会被转译transpile成普通 JavaScript 并按需压缩——如果要与他人分享脚本应分享这份转译后的产物。进阶阅读与下一步内置函数完整参考documentation/js/js_builtin.md创建并运行第一个脚本的详细指南documentation/js/js_your_first_js_app.mdJS SDK 开发指南documentation/js/js_developing_apps_using_js_sdk.md使用 JS 模块的入门说明documentation/js/js_using_js_modules.md各模块的 API 文档如 flipper、gpio、gui、storage、serial、badusb、notification、math 等见 documentation/js 目录下的js_*.md系列文件JS 运行时与全部模块的源码实现applications/system/js_app底层 mJS 引擎源码lib/mjs从设备菜单运行脚本到 CLI 远程调试再到基于 npm 的 TypeScript 开发链路Unleashed 固件已经为不同背景的开发者铺设了一条完整的 JavaScript 应用开发路径——无需交叉编译只需一份.js文件就能让 Flipper Zero 按你的脚本运行起来。【免费下载链接】unleashed-firmwareFlipper Zero Unleashed Firmware项目地址: https://gitcode.com/GitHub_Trending/un/unleashed-firmware创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考