Flipper Zero JavaScript 应用脚手架:使用 create-fz-app 快速创建与运行 JS App
【免费下载链接】flipperzero-firmwareFlipper Zero firmware source code项目地址: https://gitcode.com/GitHub_Trending/fl/flipperzero-firmware
导读
本指南围绕 Flipper Zero 官方 JavaScript SDK 的脚手架工具@flipperdevices/create-fz-app展开,介绍如何在本地用一条命令交互式生成一个完整的 JS 应用工程、通过npm start一键完成编译、上传与在真机上运行。读完本文,你将掌握 Flipper Zero JS App 从"空目录"到"屏幕弹出 Hello 对话框"的完整开发闭环,并理解脚手架背后的模板结构、fz-sdk.config.json5配置语义以及 SDK 的构建与串口上传原理。
一、脚手架工具是什么
create-fz-app是 Flipper Zero 官方发布在 npm 上的交互式脚手架包(包名@flipperdevices/create-fz-app),用于在本地生成一个可运行的 JavaScript 应用工程,目标运行环境是 Flipper Zero 设备内置的 JS 解释器(mjs)。该包与@flipperdevices/fz-sdk(官方类型声明与构建/上传工具链)配套使用,两者的源码均位于本仓库的 applications/system/js_app/packages/ 目录下。
从源码看,脚手架的核心逻辑非常轻量(create-fz-app/index.js):通过prompts交互式收集用户输入,然后把内置的template/模板目录复制到目标文件夹,用项目名替换模板中的<app_name>占位符,最后调用所选包管理器执行依赖安装。包本身依赖极少,仅prompts与replace-in-file(见 package.json),这意味着它只负责"生成工程",真正的编译与上传由模板中引入的fz-sdk完成。
二、快速开始:三分钟创建并运行第一个应用
2.1 创建工程
在任意空目录下执行官方推荐命令:
npx @flipperdevices/create-fz-app@latestnpx会自动从 npm 拉取最新版脚手架并启动交互式向导,期间会依次询问三个问题:
- 项目名称(默认
my-flip-app):生成后即作为目录名; - 包管理器选择:
npm/pnpm/yarn三选一; - 确认创建(默认确认)。
确认后,工具会复制模板文件、将模板内所有<app_name>占位符替换为你的项目名(对应源码中的replaceInFileSync({ files:${name}/**/*, from: /<app_name>/g, to: name })),然后自动执行pnpm install/npm install/yarn install安装依赖。若目标目录已存在同名文件或目录,向导会额外询问是否继续覆盖(源码中通过fs.rmSync(name, { recursive: true, force: true })实现删除重建,因此请谨慎操作)。
2.2 运行到 Flipper Zero
进入生成的项目目录并启动:
cd my-flip-app npm start如果你在创建时选择了pnpm或yarn,完全可以使用pnpm start/yarn start代替npm start,三个包管理器对工具链完全等价。
npm start实际执行的是模板 package.json 中定义的两步流水线:
"build": "tsc && node node_modules/@flipperdevices/fz-sdk/sdk.js build", "start": "npm run build && node node_modules/@flipperdevices/fz-sdk/sdk.js upload"即:先用 TypeScript 编译器检查并产出 JS,再调用fz-sdk的build命令打包,最后用upload命令把产物通过串口写入 Flipper Zero 并立即运行。
2.3 运行前提
- 需要 Node.js 环境(脚手架与 SDK 均为 Node 工具链);
- Flipper Zero 需通过 USB 连接到电脑,并处于命令行模式(CLI 会话),以便
upload通过串口交互; - 首次使用时会通过串口在设备上创建
/ext/apps/Scripts/目录存放脚本(详见下文配置与上传原理)。
三、生成的工程模板剖析
脚手架内置的模板文件位于仓库的 applications/system/js_app/packages/create-fz-app/template/ 目录,生成后的工程包含四个关键文件。理解它们,就等于掌握了 Flipper Zero JS App 的最小工程结构。
3.1fz-sdk.config.json5:构建与上传配置
这是整个工程的枢纽配置,使用 JSON5 语法(支持注释),包含build与upload两大段:
{ build: { // 编译产物的输出路径 output: "dist/<app_name>.js", // 是否压缩以减小文件体积(以牺牲可读性和错误信息清晰度为代价) minify: false, // 若已通读文档、确认可自行处理版本检查,可设为 false enforceSdkVersion: true, }, upload: { // 上传来源文件;若构建后无额外处理,应与 build.output 一致 input: "dist/<app_name>.js", // 上传到设备上的目标路径 output: "/ext/apps/Scripts/<app_name>.js", }, }各配置项说明(对应 fz-sdk.config.json5 模板源码):
| 配置项 | 含义 | 默认行为 |
|---|---|---|
build.output | 打包产物路径,同时是upload.input的默认来源 | dist/<app_name>.js |
build.minify | 是否启用 esbuild 压缩输出 | false,保留可读性与错误信息 |
build.enforceSdkVersion | 是否在产物头部注入 SDK 版本兼容性检查 | true,强烈建议保持开启 |
upload.output | 脚本在设备上的存放位置 | /ext/apps/Scripts/<app_name>.js |
其中enforceSdkVersion对应 fz-sdk/sdk.js 中的实现:构建时会读取 SDK 自身版本号,并在产物最前面注入一行checkSdkCompatibility(major, minor);,由设备端 JS 运行时在执行脚本时校验 SDK 兼容性,避免因 API 变更导致运行期崩溃。
3.2index.ts:开箱即用的示例应用
模板自带一个可直接运行的对话框示例(template/index.ts),演示了 Flipper Zero JS App 的标准骨架:
// import modules // caution: `eventLoop` HAS to be imported before `gui`, and `gui` HAS to be // imported before any `gui` submodules. import * as eventLoop from "@flipperdevices/fz-sdk/event_loop"; import * as gui from "@flipperdevices/fz-sdk/gui"; import * as dialog from "@flipperdevices/fz-sdk/gui/dialog"; // a common pattern is to declare all the views that your app uses on one object const views = { dialog: dialog.makeWith({ header: "Hello from <app_name>", text: "Check out index.ts and\nchange something :)", center: "Gonna do that!", }), }; // stop app on center button press eventLoop.subscribe(views.dialog.input, (_sub, button, eventLoop) => { if (button === "center") eventLoop.stop(); }, eventLoop); // stop app on back button press eventLoop.subscribe(gui.viewDispatcher.navigation, (_sub, _item, eventLoop) => { eventLoop.stop(); }, eventLoop); // run app gui.viewDispatcher.switchTo(views.dialog); eventLoop.run();这个示例刻意展示了三条重要约定:
- 导入顺序有强约束:
eventLoop必须先于gui导入,gui必须先于任何gui子模块导入——这是 fz-sdk 类型声明中的硬性要求,破坏顺序会导致运行时错误; - 事件循环驱动:所有交互都通过
eventLoop.subscribe订阅视图输入事件完成,中心键与返回键都会停止事件循环从而退出应用; - 视图管理器:
gui.viewDispatcher.switchTo()负责切换当前显示的视图。
@flipperdevices/fz-sdk的完整类型声明位于仓库 applications/system/js_app/packages/fz-sdk/,覆盖gui(dialog、submenu、text_input、widget、byte_input 等十余种视图)、event_loop、flipper、gpio、storage、serial、badusb、math、notification等模块,是开发时最重要的类型参考。
3.3package.json与tsconfig.json
package.json:声明@flipperdevices/fz-sdk(^1.0)与typescript(^5.6.3)两个开发依赖,以及上文提到的build/start脚本;tsconfig.json:面向 Flipper Zero JS 运行时的编译配置,target: "ES2015"、noLib: true(不使用 Node 类型库)、types: [],并把 SDK 的global.d.ts显式纳入编译,保证设备端全局 API 的类型可用。设备端的 JS 解释器仅支持受限的 ECMAScript 子集,因此工具链在打包时会主动"禁用"大量现代语法特性(见下文),开发者应尽量编写 ES5/ES2015 风格的代码。
四、SDK 构建与上传的底层原理
npm start调用的sdk.js位于 applications/system/js_app/packages/fz-sdk/sdk.js,这是理解整个工具链的关键文件。
4.1build:面向嵌入式运行时的 esbuild 打包
build命令基于 esbuild 完成三件事:
- 以
./dist/index.js(即 tsc 的编译产物)为入口,按tsconfig.json配置打包成单个 CommonJS 文件,输出到config.output; - 通过
external: ["@flipperdevices/fz-sdk/*"]把 SDK 模块声明为外部依赖——SDK 不打包进产物,而是由设备端运行时按需解析(这也是为什么 import 顺序如此重要); - 最关键的是
supported配置:显式将arrow、async-await、class、template-literal、optional-chain、nullish-coalescing、destructuring、for-of等数十项现代语法特性全部设为false,仅保留const-and-let。这意味着任何依赖现代 JS 语法的代码都会在构建阶段被拒绝,从源头保证产物与 Flipper Zero 内置解释器的语法能力兼容。
打包完成后,脚本会在产物头部拼接let exports = {};,并根据enforceSdkVersion注入版本检查调用,最终写回输出文件。
4.2upload:串口发现、写入与启动
upload命令实现了一条完整的"写盘-运行"链路:
- 发现设备:通过
SerialPort.list()枚举串口,优先按serialNumber以flip_前缀识别 Flipper Zero;针对部分 Windows 驱动不报告序列号的情况,回退到按 STM32 VCP 的VID 0483 : PID 5740匹配。若同时连接多台设备,会弹出选择框; - 建立连接:以
230400波特率打开串口,等待 CLI 提示符>:出现; - 写入脚本:依次执行
storage remove清除旧文件、storage write_chunk <path> <size>声明写入块大小、随后发送文件内容,等待写入完成; - 启动应用:执行
js <path>命令启动脚本,实时转发设备输出到终端,并在脚本退出(出现Script done!)后自动结束进程。
这条链路意味着你甚至可以把生成的dist/*.js手动复制到设备/ext/apps/Scripts/目录后自行运行,upload只是把这个过程自动化了。
五、版本兼容性约定
脚手架配套的fz-sdk包遵循一套明确的版本语义(见 fz-sdk/README.md):包版本号的 major.minor 与其所面向的 Flipper Zero JS SDK 版本一致,并遵循 semver。例如,用 SDK 版本0.1.0编译的应用,兼容0.1至1.0(不含1.0)之间的 SDK 版本。
每个 API 的版本历史记录在其 JSDoc 注释中。SDK 强烈建议开发者根据场景组合使用sdkCompatibilityStatus、isSdkCompatible、assertSdkCompatibility等运行时 API 做兼容性检查——这也是模板默认开启enforceSdkVersion的原因:把版本检查内联进产物,确保设备端与工具链版本匹配时应用才允许运行,将兼容性问题提前暴露在启动阶段。
六、下一步:深入 JS 开发
脚手架生成的工程是探索 Flipper Zero JS API 的最佳起点。本仓库的 documentation/js/ 目录提供了完整的模块级参考,包括:
- js_developing_apps_using_js_sdk.md:基于 JS SDK 开发应用的总体流程;
- js_event_loop.md 与 js_gui.md:事件循环与 GUI 视图体系;
- js_gui__dialog.md、js_gui__submenu.md、js_gui__widget.md 等:各视图组件的独立用法说明;
- js_storage.md、js_gpio.md、js_serial.md:文件系统、GPIO、串口等硬件能力访问。
结合 fz-sdk 的类型声明(IDE 中可直接获得智能提示),你可以从模板的对话框示例出发,逐步替换为菜单、文本输入、文件浏览器等更复杂的界面,构建真正可用的设备端工具应用。
【免费下载链接】flipperzero-firmwareFlipper Zero firmware source code项目地址: https://gitcode.com/GitHub_Trending/fl/flipperzero-firmware
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考