Flipper Zero 二次开发

这篇主要记录一下 Flipper Zero 的二次开发流程。现在先不碰完整固件源码,主要基于三方优化系统 Momentum 做 External App,也就是最后生成 .fap 插件,放到 SD 卡里运行。

目前基于三方优化系统 Momentum 来进行学习,该系统被公认为目前三方里比较好用的一版。

一、上位机、固件和文件系统

Windows 上位机安装。

本地安装包原来放的是:

1
flipper zero电脑管理软件.exe

安装三方固件时,用的是 Momentum 的更新包:

1
flipper-z-f7-update-mntm-dev-42630e91.tgz

这里不要再在文章里直接引用本机 Downloads 路径。博客部署之后读不到本地路径,所以只记录文件名,实际文件按自己的电脑位置导入即可。

image-20260217102130536

文件系统大概长这样:

image-20260217102208985

这里后面会用到的是 SD 卡里的 apps 目录。External App 编译出来之后,本质上就是把 .fap 文件放进对应分类目录,比如 apps/Tools

二、开发环境

先创建工作目录:

1
2
mkdir FlipperZero_Dev
cd FlipperZero_Dev

创建或者进入虚拟环境。原来我这里写的是直接激活:

1
conda activate flipper_dev

如果这个环境还没有建,可以先建一个再激活:

1
2
conda create -n flipper_dev python=3.11
conda activate flipper_dev

安装 ufbt

1
pip install ufbt

下载 Momentum 对应的 SDK:

1
ufbt update

这一步会把后面编译 External App 需要的工具链和 SDK 拉下来。后面如果换了固件版本,SDK 最好也跟着更新一次,不然容易出现 API 或 ABI 对不上的问题。

三、创建项目与配置

创建项目文件夹,比如这里叫 app01

1
2
mkdir app01
cd app01

执行创建命令:

1
ufbt create appid=my_first_app

my_first_app 是这个 APP 的 ID。这个 ID 后面会影响生成的 .fap 文件名,也会和配置里的入口函数绑定,所以一开始就尽量别乱改。

进入项目文件夹之后执行:

1
ufbt vscode_dist

这个命令主要是给 VS Code 生成开发时需要的配置,方便代码补全和跳转。

项目里比较核心的是应用配置。这里先用一个最小可跑的版本:

1
2
3
4
5
6
7
8
9
10
11
12
App(
appid="my_first_app",
name="My First App",
apptype=FlipperAppType.EXTERNAL,
entry_point="my_first_app_app",
c_defines=["APP_MY_FIRST_APP"],
requires=["gui"],
stack_size=2 * 1024,
order=20,
fap_icon="images/icon_10x10.png",
fap_category="Tools",
)

注释版放这里,后面回看配置时比较方便:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
App(
# 核心身份信息
# APP 的唯一 ID,必须是全小写,不能有空格,建议用下划线
# 这个 ID 会决定编译出的文件名,比如 my_app.fap
appid="my_first_app",

# 在 Flipper 菜单里显示的名字,支持空格和大小写
name="My First App",

# APP 类型
# EXTERNAL: 最常用的第三方插件类型,存储在 SD 卡
# PLUGIN: 系统内部插件,一般不用
apptype=FlipperAppType.EXTERNAL,

# C 语言代码中的入口函数名
# 必须和 .c 文件里 int32_t xxx(void* p) 的名字一字不差
entry_point="my_first_app_app",

# 栈内存大小,默认是 1024,也就是 1KB
# 如果 APP 变量很多或者容易死机,可以先改成 2*1024 或 4*1024
stack_size=2 * 1024,

# 依赖的系统库
# "gui": 几乎所有带界面的 APP 都需要
# "storage": 如果需要读写 SD 卡文件
# "dialogs": 如果需要弹出系统对话框
requires=["gui"],

# 预编译宏定义
# 可以在 C 代码里用 #ifdef APP_MY_FIRST_APP 来判断
c_defines=["APP_MY_FIRST_APP"],

# 菜单图标路径
# 必须是相对于本配置文件的路径,通常要求 10x10 像素的 1-bit PNG
# 如果没有这个文件,编译会报错,可以先删掉这行,用系统默认图标
fap_icon="images/icon_10x10.png",

# APP 分类,决定它出现在 Flipper 的哪个菜单文件夹里
# 常见值有 "Assets", "Games", "GPIO", "Infrared", "Music", "NFC",
# "RFID", "Sub-GHz", "Tools", "USB", "Weather", "Bluetooth"
fap_category="Tools",

# Momentum/App Store 相关信息
fap_author="Your Name",
fap_version=(1, 0),
fap_description="This is a demo app for Momentum firmware.",
)

官方模板大概是这个写法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
App(
appid="template", # Must be unique
name="App template", # Displayed in menus
apptype=FlipperAppType.EXTERNAL,
entry_point="template_app",
stack_size=2 * 1024,
fap_category="Examples",
# Optional values
# fap_version="0.1",
fap_icon="template.png", # 10x10 1-bit PNG
# fap_description="A simple app",
# fap_author="J. Doe",
# fap_weburl="https://github.com/user/template",
fap_icon_assets="images", # Image assets to compile for this application
)

这里有几个配置容易对不上:

  • appid 会影响生成文件名,比如 my_first_app.fap
  • entry_point 必须和 C 文件里的入口函数名一致。
  • requires=["gui"] 这种依赖要和代码里实际用到的模块同步。
  • fap_icon 如果写了,就必须真的有这个文件,而且格式要满足要求。
  • fap_category="Tools" 决定最后应该把 .fap 放到 apps/Tools 下面。

代码文件重命名为:

1
my_first_app.c

这里文件名本身不是最关键的,关键是里面的入口函数要和 entry_point="my_first_app_app" 对上。

四、编译和安装

编译直接执行:

1
ufbt

编译完之后,把生成的文件复制到 Flipper Zero 的 SD 卡目录:

1
dist/my_first_app.fap

目标位置是:

1
apps/Tools

放进去之后,就可以在 Flipper Zero 的 Tools 分类里看到这个 APP。

image-20260217142048767

image-20260217142130414

图标和名字能看到,说明配置和 .fap 基本已经对上了。

image-20260217142147567

五、设置主菜单快捷键

接下来,把这个设置成主菜单快捷键。

Settings 里面找到 Desktop,然后进 Keybinds Setup。在 Press 里找到想绑定的按键,再把它绑定到 External App 里面的 Tools,选择自己写的 app。

image-20260217143024474

比如说我绑定的是下键短按。来到海豚画面的时候,点按下键就可以直接进入这个 app。

六、为什么先写 External App

Flipper Zero 的软件生态由集成在固件内部的 Main App 和存储在 SD 卡上的 External App,也就是 FAP 插件共同构成。Main App 比如 Sub-GHz 或 NFC,属于系统核心,启动快,也在主菜单里,但开发门槛很高。任何微改都需要克隆很大的源码,还要承担重刷固件导致变砖的风险。

作为第三方的 Tools 插件,本质上都是 External App。它们通过 Loader 服务动态加载到内存运行,虽然分类上被放在 Tools 文件夹下,但功能调用上和系统应用差别没有想象中那么大。

我这里选择 External App 的原因很简单:它把应用逻辑和系统内核拆开了。用 ufbt 就能快速构建和调试,开发周期短很多,而且安全性更高。即使代码崩了,通常也只是退出程序,不会破坏设备固件。

这种形式生成的 .fap 文件也方便分发。别人不需要刷机,直接放到对应目录就能用。后面要做创意功能、硬件交互、自定义工具,External App 是比较合适的起点。

参考

2025最强入门:Flipper Zero开发实战指南—从固件到应用全流程-CSDN博客

FAQ | Momentum Firmware