Flipper Zero 二维码显示应用 flipperzero-qrcode 实战指南:从 .qrcode 文件制作、模式选择到源码级原理解析

发布时间:2026/9/13 19:07:55
Flipper Zero 二维码显示应用 flipperzero-qrcode 实战指南:从 .qrcode 文件制作、模式选择到源码级原理解析 Flipper Zero 二维码显示应用 flipperzero-qrcode 实战指南从 .qrcode 文件制作、模式选择到源码级原理解析【免费下载链接】FlipperPlayground (and dump) of stuff I make or modify for the Flipper Zero项目地址: https://gitcode.com/GitHub_Trending/fl/FlipperFlipper Zero 的 64×64 像素小屏幕也能稳定展示可供手机扫码识别的二维码。本文以开源仓库 Flipper 中收录的flipperzero-qrcode应用v1.1.0为对象完整讲解.qrcode文件格式、四种编码模式Numeric / Alpha-Numeric / Binary / Kanji的取舍、Wi-Fi 二维码的实战写法、应用操作与 fbt 编译流程并结合源码深入解析其自动模式探测、容量表驱动的版本/ECC 选择、屏幕渲染与交互逻辑。读完本文你可以自行制作任意内容的 Flipper 二维码文件并理解小屏二维码的容量上限与踩坑点。一、应用背景与定位flipperzero-qrcode是一个运行在 [Flipper Zero](https://link.gitcode.com/i/04dc8c860d635fe1ed41a6ced4f0a0b7/blob/41fc08dbc4c53cf2c87dd4f2de3d3a5fe3eb016f/Applications/Custom (UL, RM)/Unleashed/ReadMe.md?utm_sourcegitcode_repo_files) 上的外部应用.fap核心功能只有一个把文本消息实时渲染成二维码显示在屏幕上。它是社区作品作者 Bob Matcuk即 README 中提到的 bmatcuk在其 v1.1.0 时代曾以源码 预编译 fap的形式分发。从仓库收录情况看该应用源码以压缩包形式归档在 flipperzero-qrcode-1.1.0 目录下含flipperzero-qrcode-1.1.0.zip压缩包内共 10 个文件主体是qrcode.c/qrcode.h二维码编码核心库基于 ricmoo/QRCode源自 Project Nayuki 的 QR-Code-generator约 32 KB 源码qrcode_app.c应用主逻辑文件加载、模式探测、渲染、按键交互约 20 KBapplication.famFAP 应用的构建清单scripts/面向 CI 的固件版本检查/更新脚本。这是一个文件驱动、纯离线的应用它不联网生成二维码而是读取 SD 卡上预置的文本文件在本机完成编码与渲染因此完全适合在无法联网的场合使用。二、安装与目录约定2.1 安装方式README 给出的安装方式是把编译好的qrcode.fap复制到 SD 卡的apps/Tools目录与application.fam中声明的fap_categoryTools一致然后在 SD 卡根目录新建qrcodes文件夹。使用 qFlipper 等工具时操作步骤为将qrcode.fap拖入apps/Tools返回 SD 卡根目录与infrared、nfc等目录同级新建名为qrcodes的文件夹。qrcodes这个目录名并非随意约定它由源码中的宏直接硬编码#define QRCODE_FOLDER ANY_PATH(qrcodes) #define QRCODE_EXTENSION .qrcode参见 qrcode_app.c解压后第 14–15 行。应用启动时会自动以ANY_PATH(qrcodes)作为文件浏览器的base_path只展示该目录下的.qrcode文件。2.2 文件浏览与命令行参数qrcode_app入口qrcode_app.c第 473 行起支持两种启动方式无参数启动弹出内置文件浏览器dialog_file_browser_show定位到qrcodes目录文件过滤器为.qrcode扩展名且hide_ext true隐藏扩展名显示带参数启动如果传入p且非空直接以该路径作为文件路径加载显示完二维码后按 Back 即退出不会循环回到浏览器。while (true) { if (p strlen(p)) { furi_string_set(file_path, (const char*)p); // 直接使用传入路径 } else { ... dialog_file_browser_show(...); // 否则弹出文件浏览器 } ... if (p strlen(p)) break; // 带参启动看完即退 }这一设计意味着该应用可以被其他应用或脚本以指定文件路径的方式拉起属于可复用的组件式入口。三、.qrcode 文件格式详解3.1 文件模板.qrcode文件本质是纯文本文件内容格式如下Filetype: QRCode Version: 0 Message: your content here对应源码中的常量#define QRCODE_FILETYPE QRCode #define QRCODE_FILE_VERSION 0文件加载过程qrcode_load_file第 383 行起使用 FlipperFormat 解析flipper_format_file_open_existing打开文件flipper_format_read_header读取头部校验Filetype必须等于QRCode且Version必须等于0否则直接报错Incorrect file format or versionflipper_format_read_string(file, Message, temp_str)读取Message:字段把Message字符串交给qrcode_load_string编码生成二维码。Version: 0是文件格式版本号当前固定为 0与二维码的版本1–11是两个完全不同的概念不要混淆。该字段用于将来文件格式演进时的兼容性判断。3.2 Message 的编码流程qrcode_load_string第 298 行起是整个应用最核心的函数其处理流程是计算消息长度len自动探测模式依次调用is_numeric和is_alphanumeric判断消息是否为纯数字或字母数字否则默认使用 Binary字节模式uint8_t mode MODE_BYTE; if (is_numeric(cstr, len)) mode MODE_NUMERIC; else if (is_alphanumeric(cstr, len)) mode MODE_ALPHANUMERIC;最小版本选择从 version 0 开始在MAX_LENGTH[mode][ecc][version]容量表中查找能容纳len的最小版本优先使用小版本以最大化每个模块module的像素尺寸提升扫码成功率最大 ECC 选择在最小版本下从ECC_HIGH3向下寻找能容纳消息的最高纠错级别调用rebuild_qrcode完成编码。这三步可以概括为最小版本 该版本下最高纠错策略——这是 README 提到自动选择最佳模式的底层实现。四、四种编码模式与容量权衡4.1 模式总览二维码标准定义了四种数据编码模式本应用支持前三种模式允许字符容量相对典型用途Numeric数字仅0–9基准最高电话号码、纯数字 IDAlpha-Numeric字母数字数字、大写字母、空格及$%*-./:约为数字模式的 60%纯大写的域名如HTTP://EXAMPLE.COMBinary字节/二进制8-bit 字节Latin-1约为数字模式的 40%比字母数字少约 30%含路径的 URL、混合大小写文本Kanji日文汉字日文 Shift-JIS 汉字—本应用不支持模式常量定义于 qrcode.h解压后第 51–53 行#define MODE_NUMERIC 0 #define MODE_ALPHANUMERIC 1 #define MODE_BYTE 2注意get_mode_charqrcode_app.c第 88 行仍为MODE_KANJI3保留了K字符映射但编码库本身不产生该模式。4.2 Numeric 模式只包含数字。这是容量最高的模式适合电话号码、学号、订单号等纯数字数据。README 特别提醒想用数字模式就绝不要在文件里混入任何多余标点空格、连字符、括号都会让探测器切换到更低效的模式。4.3 Alpha-Numeric 模式字符集为数字0–9、大写字母A–Z、空格以及$%*-./:九个符号。探测逻辑见is_alphanumericqrcode_app.c第 220 行起其允许字符集与编码库getAlphanumericqrcode.c第 102 行起严格一致。适合编码 URL 的场景仅域名部分且使用大写例如HTTP://EXAMPLE.COM。因为域名通常不含大小写敏感信息、又大量使用.和/等合法符号正好落在字母数字字符集内。但如果 URL 带有路径通常区分大小写就必须退回 Binary 模式。4.4 Binary 模式名为二进制实际指按 8-bit 字节编码。二维码标准规定文本使用 ISO-8859-1Latin-1编码而不是现代常见的 UTF-8。这带来一个实用约束为保持标准兼容消息应限于拉丁字母、数字和符号某些扫码器会自动嗅探 UTF-8 从而能识别中文等内容但这属于可能可用而非标准行为不能保证所有扫码器都能读。容量方面Binary 模式比 Numeric 模式少约 60% 容量比 Alpha-Numeric 少约 30%。4.5 Kanji 模式与屏幕容量上限Kanji 模式不受支持原因是底层 QRCode 库ricmoo 版的限制。这是 README 明确声明的事实。另外应用对二维码版本做了硬上限MAX_QRCODE_VERSION 11qrcode_app.c第 23 行原因也在源码注释中写得很清楚/** * Maximum version is 11 because the f0 screen is only 64 pixels high and * version 12 is 65x65. Version 11 is 61x61. */ #define MAX_QRCODE_VERSION 11Flipper Zero 屏幕仅 64 像素高版本 11 二维码为 61×61 模块是屏幕能容纳的最大尺寸版本 1265×65已超出屏幕。若消息超过版本 11 的容量加载会失败并提示Message is too long.too_long标志位触发见render_callback第 178–181 行。4.6 容量表数字背后的硬约束应用内置了一张按模式 × ECC 级别 × 版本1–11组织的最大字符长度表MAX_LENGTHqrcode_app.c第 26–48 行。下表摘录各模式在 ECC Low 下的容量分布可直观看出小屏二维码能塞多少数据版本数字字母数字二进制14125175255154106737022415411上限772468321以版本 11 ECC Low 为例最多只能编码 321 个字节Binary 模式若把 ECC 提到 High容量进一步降至 137 字节。这就是 README 强调屏幕小、数据多时很多扫码器读不出来的根源。五、Wi-Fi 二维码实战5.1 标准格式绝大多数手机系统支持扫描二维码直接连接 Wi-Fi。Wi-Fi 二维码的消息遵循工业通用格式Filetype: QRCode Version: 0 Message: WIFI:S:ssid;P:password;T:encryption;字段说明字段含义取值S:网络名SSID你的 Wi-Fi 名称P:密码Wi-Fi 密码T:加密方式WPA、WEP开放网络填NoneH:隐藏网络标记可选true表示网络不广播 SSID;字段分隔符每个字段以分号结尾几种常见变体开放网络无密码T:填None并可去掉P:password;段隐藏网络在末尾追加H:true;。5.2 特殊字符转义如果 SSID 或密码包含\;,:中任意字符必须在其前面加反斜杠\进行转义。例如SSID 为wifiball、隐藏不广播、密码为pa$$:word、WPA 加密则消息为Message: WIFI:S:wifiball;P:pa$$\:word;T:WPA;H:true;这里$不需要转义不在转义字符集内而密码中的:必须写成\:。5.3 其他实用消息示例根据 README 中作者的实测作者成功让 iPhone 读取了电话号码、Wi-Fi 信息和 URL最高到版本 11 二维码可参考以下消息写法# 电话号码纯数字 → Numeric 模式容量最优 Message: TEL:1234567890 # URL域名部分大写 → Alpha-Numeric 模式 Message: HTTP://EXAMPLE.COM注意电话号码建议采用TEL:前缀的行业标准格式但任何纯数字消息本身也会触发最高效的 Numeric 模式。六、应用操作指南6.1 基本操作流程应用启动后自动打开文件浏览器并定位到qrcodes目录选择文件用方向键上下在.qrcode文件间移动按中间键OK确认二维码随即全屏显示查看统计按右键显示二维码统计信息隐藏统计按左键隐藏返回浏览按 Back 键返回文件浏览器退出应用在文件浏览器中按 Back 键退出。6.2 统计面板Version / ECC / Mode按右键后屏幕右侧显示三项信息对应render_callback第 136–174 行的绘制逻辑VerVersion二维码版本号直接对应二维码的物理尺寸模块数 17 4 × versionECC纠错级别取值为LLow约 7%、MMedium约 15%、QQuartile约 25%、HHigh约 30%。它决定二维码对污损、脏屏、划痕的抵抗能力ModMode编码模式显示NNumeric、AAlpha-Numeric、BBinary、KKanji。模式字符与 ECC 字符的映射分别见get_mode_char与get_ecc_charqrcode_app.c第 74–96 行。6.3 手动调整 Version 与 ECC统计面板下还可以手动改参数input_callback与主循环第 503–573 行实现用上/下方向键在Ver和ECC两项之间切换选中右侧出现▶指示符按 OK 进入编辑模式选中项旁出现上下箭头编辑模式下上/下方向键增减数值Version可在min_version消息能容纳的最小版本与 11 之间增减ECC可在 0L与当前版本允许的最高值之间增减——若版本已大于最小版本最高可到H代码第 532 行uint8_t max_ecc instance-set_version instance-min_version ? instance-max_ecc_at_min_version : ECC_HIGH;即体现升级版本可解锁更高纠错的逻辑再次按 OK 确认并重新生成二维码rebuild_qrcode或改回数值后按 OK 取消。作者自述该功能mostly added for my own amusement and testing但理论上有一个实际用途如果默认参数下扫码器读不出默认 ECC 低于最高的H可以把 Version 1 再设 ECC 为H通过更高纠错冗余提高容错率——效果因扫码器而异。6.4 失败提示加载失败时屏幕显示 Could not load qrcode.若因消息过长超过版本 11 容量还会追加一行 Message is too long.render_callback第 176–181 行。七、从源码编译7.1 环境与目录编译需要 Flipper Zero 固件仓库flipperzero-firmware。传统流程如下git clone gitgithub.com:flipperdevices/flipperzero-firmware.git cd flipperzero-firmware/applications_user git clone gitgithub.com:bmatcuk/flipperzero-qrcode.git把本应用源码克隆进固件的applications_user目录后回到固件根目录用 fbt 构建cd .. ./fbt fap_qrcodefbt 会自动安装依赖并编译产物为build/f7-firmware-D/.extapps/qrcode.fapfbt 输出会显示实际的 .fap 路径将来若有变化以输出为准。7.2 应用清单application.fam 的字段解读application.fam压缩包内以 Flipper 应用清单 DSL 声明了应用的全部元数据App( appidqrcode, nameqrcode, fap_version(1,1), fap_descriptionDisplay qrcodes, fap_authorBob Matcuk, apptypeFlipperAppType.EXTERNAL, entry_pointqrcode_app, stack_size2 * 1024, cdefines[APP_QRCODE], requires[gui, dialogs], fap_categoryTools, fap_iconicons/qrcode_10px.png, fap_icon_assetsicons, )关键字段的工程含义apptypeFlipperAppType.EXTERNAL编译为外部.fap无需刷固件即可运行entry_pointqrcode_app对应qrcode_app.c中的int32_t qrcode_app(void* p)入口函数stack_size2 * 1024应用栈 2 KB——二维码编码是 CPU 密集但栈占用很小的纯算法任务这也是它能以 .fap 方式运行的前提requires[gui, dialogs]依赖 GUI屏幕渲染与 Dialogs文件浏览器两个系统服务fap_categoryTools决定 .fap 在应用菜单中的归属分类Tools 工具类。7.3 二维码编码库qrcode.c 的内部结构qrcode.c是 ricmoo/QRCode 库的移植版MIT 协议派生自 Project Nayuki 的 QR-Code-generator C 实现并被原作者小幅修改以修复编译错误。其内部值得注意的实现点容量表第 43–67 行存放了NUM_ERROR_CORRECTION_CODEWORDS、NUM_ERROR_CORRECTION_BLOCKS、NUM_RAW_DATA_MODULES三张覆盖版本 1–40 的表并支持LOCK_VERSION宏裁剪锁定版本可跳过大部分表以节省内存未锁定时宏值为 0BitBucket 位流结构第 164 行起定义BitBucket用位偏移实现紧凑的码字写入对外 APIqrcode.h第 86–91 行uint16_t qrcode_getBufferSize(uint8_t version); int8_t qrcode_initText(QRCode *qrcode, uint8_t *modules, uint8_t version, uint8_t ecc, const char *data); int8_t qrcode_initBytes(QRCode *qrcode, uint8_t *modules, uint8_t version, uint8_t ecc, uint8_t *data, uint16_t length); bool qrcode_getModule(QRCode *qrcode, uint8_t x, uint8_t y);本应用统一走qrcode_initBytesrebuild_qrcodeqrcode_app.c第 280 行把消息按字节数组编码。QRCode 结构体qrcode.h第 70–77 行记录版本、尺寸、ECC、模式、掩码及模块位图。7.4 渲染与交互的线程模型应用采用 Flipper 标准的渲染回调 输入回调 消息队列模型qrcode_app.crender_callback在 GUI 线程被调用负责把模块位图画到屏幕pixel_size height / size计算每个模块的像素边长模块为 1 像素时用canvas_draw_dot、更大时用canvas_draw_box第 127–131 行并在显示统计时把二维码左移让出右侧 65 像素栏位第 123 行input_callback只把短按事件投递进FuriMessageQueue容量 8主循环在furi_message_queue_get中阻塞消费避免在回调里做重活渲染与主循环之间通过FuriMutex互斥保护共享的qrcode/message状态。这一架构保证了在每帧全量重绘位图最多 61×61 模块的情况下交互仍然顺滑。7.5 配套脚本压缩包内scripts/提供两个 CI 辅助脚本check-firmware.sh接收固件仓库路径用 git tag 对比当前固件版本与上次构建版本输出是否有新版本update-firmware.sh按新固件版本更新 release 工作流配置并自动打 tag、推送。它们服务于固件升级后自动重建 .fap的自动化流水线普通使用者可忽略。八、实用建议与已知限制综合 README 与源码给出如下经验总结控制消息长度屏幕物理上限决定了版本上限 11Binary 模式下消息超过 321 字节即无法显示纯数字消息则可以放宽到 772 字符为模式优化消息纯数字就删掉所有标点域名用大写以命中 Alpha-Numeric 模式路径类 URL 只能用 Binary 模式且受 Latin-1 约束扫码器的宽容度差异很大作者实测 iPhone 可读取最高版本 11 的二维码含电话号码、Wi-Fi 信息、URL但小屏二维码整体上对老旧/低端扫码器不友好脏屏会加剧问题善用统计面板遇到读不出的场景可手动 Version 1 并将 ECC 提到H提高容错冗余Wi-Fi 消息务必转义SSID/密码含\;,:时必须加反斜杠否则手机可能解析失败。九、参考资料应用说明文档flipperzero-qrcode-1.1.0/README.md应用源码归档flipperzero-qrcode-1.1.0.zip内含qrcode_app.c、qrcode.c、qrcode.h、application.famFlipper Zero 项目仓库说明ReadMe.md应用安装相关Flipper 官方 qFlipper 桌面工具可在固件官方文档中查阅使用方式文中源码引用均基于仓库内归档的 v1.1.0 源码包若在更新的固件版本上使用请以该固件对应的构建输出为准。【免费下载链接】FlipperPlayground (and dump) of stuff I make or modify for the Flipper Zero项目地址: https://gitcode.com/GitHub_Trending/fl/Flipper创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考