Flet 应用启动核心:flet.run() 函数深度解析与实战指南
【免费下载链接】fletBuild realtime web, mobile and desktop apps in Python only. No frontend experience required.项目地址: https://gitcode.com/gh_mirrors/fl/flet
flet.run()是 Flet 框架中启动应用的统一入口:无论你的目标是桌面窗口、Web 服务还是移动端嵌入式运行,它都能根据参数与环境自动选择合适的传输通道并拉起应用。本指南以仓库 API 文档 run.md 所引用的flet.run为骨架,结合其实现源码 app.py,逐一拆解每个参数的含义、底层运行机制与环境变量,并给出可在当前仓库示例中直接验证的实战用法。
一、flet.run 在 Flet 中的定位
flet.run()是 Flet 应用的生命周期入口函数。它接收一个以Page为唯一参数的处理器(handler),在该处理器中你可以构建界面、绑定事件并执行业务逻辑,然后由run()负责与 Flet 客户端(桌面窗口、浏览器、移动端)建立连接、维护会话并驱动界面更新。
从源码看,run()定义于 sdk/python/packages/flet/src/flet/app.py,并通过 sdk/python/packages/flet/src/flet/init.py 以flet.run的名字暴露给用户。值得注意的是,Flet 1.0 采用 PEP 562 惰性导入策略(见__init__.py头部注释),import flet不再立即加载全部约 270 个模块,flet.run在首次访问时才被导入,因此直接使用ft.run(main)是零额外开销的。
最小可用示例
仓库示例应用大量采用ft.run(main)这种写法,例如 sdk/python/examples/apps/7guis/counter/main.py:
import flet as ft def main(page: ft.Page): page.title = "Counter" # ... 构建界面与事件处理 ... ft.run(main)完整函数签名
def run( main: AppCallable, before_main: Optional[AppCallable] = None, name: str = "", host: Optional[str] = None, port: int = 0, view: Optional[AppView] = AppView.FLET_APP, assets_dir: Optional[str] = "assets", upload_dir: Optional[str] = None, web_renderer: WebRenderer = WebRenderer.AUTO, route_url_strategy: RouteUrlStrategy = RouteUrlStrategy.PATH, no_cdn: Optional[bool] = False, export_asgi_app: Optional[bool] = False, )其中AppCallable是同步或异步回调的类型别名:它接受单个Page参数,返回值被忽略(见 app.py 中的定义)。
二、参数逐项详解
以下是flet.run()全部参数的说明与源码级解读(参数默认值与语义以 app.py 中的 docstring 为准):
| 参数 | 类型 | 默认值 | 作用 |
|---|---|---|---|
main | AppCallable | 必填 | 应用入口,接收一个Page参数的函数或协程 |
before_main | AppCallable | None | 在Page创建之后、main执行之前调用 |
name | str | "" | 应用/页面名称,用于 Web 场景下的 URL 路径 |
host | str | None | Web 服务器绑定的主机/IP |
port | int | 0 | TCP 端口;为0时由系统自动选择可用端口 |
view | AppView | AppView.FLET_APP | 应用呈现模式(桌面窗口 / 浏览器等) |
assets_dir | str | "assets" | 应用资源目录路径 |
upload_dir | str | None | 上传文件保存目录 |
web_renderer | WebRenderer | WebRenderer.AUTO | Web 渲染器类型 |
route_url_strategy | RouteUrlStrategy | RouteUrlStrategy.PATH | URL 路由策略(path或hash) |
no_cdn | bool | False | 是否不从 CDN 加载 CanvasKit、Pyodide 与字体 |
export_asgi_app | bool | False | 为True时返回配置好的 ASGI 应用而非运行事件循环 |
回调参数:main 与 before_main
main:应用入口。run()内部通过__get_on_session_created(app.py)构造会话回调,在该回调中依据处理器类型分派执行:
if inspect.iscoroutinefunction(main): await main(session.page) elif inspect.isasyncgenfunction(main): async for _ in main(session.page): await session.after_event(session.page) elif inspect.isgeneratorfunction(main): for _ in main(session.page): await session.after_event(session.page) else: main(session.page) # 同步函数 await session.after_event(session.page)也就是说,main可以是普通同步函数、协程函数、异步生成器、同步生成器中的任意一种,框架都会正确处理并保证在处理器返回后调用session.after_event()刷新页面。若main抛出未捕获异常,框架会记录Unhandled error in main() handler日志并通过session.error()上报到客户端。
before_main:在Page创建后、main执行前运行的钩子,常用于注入依赖、初始化会话级状态。
name、host、port:Web 服务定位参数
name:页面名称,会拼接到 Web URL 路径中。实际生效值还受环境变量FLET_WEB_APP_PATH影响——当name为空而该环境变量非空时,以环境变量为准(见__get_page_name,app.py)。host:Web 服务器绑定地址。源码中url_host = "127.0.0.1" if host in [None, "", "*"] else host,即默认绑定本机回环地址。port:0表示自动分配。在强制 Web 服务器模式下(force_web_server=True),若端口仍为0则使用8000(见 app.py)。
assets_dir 与 upload_dir:资源与上传目录
assets_dir默认值为常量DEFAULT_ASSETS_DIR = "assets"(app.py)。相对路径会基于当前脚本目录解析为绝对路径(export_asgi_app=True时则基于当前工作目录,见__get_assets_dir_path的relative_to_cwd参数,app.py)。- 源码还兼容 PyInstaller "onefile" 打包场景:当
"_MEI" in __file__时,相对路径基于可执行文件所在目录解析。 - 若默认
assets目录不存在,框架仅记录 debug 日志(不告警);若显式指定了不存在的目录,则记录assets_dir does not exist警告,并将该目录置空。 upload_dir同理支持相对路径解析(app.py)。- 两者均支持环境变量覆盖:
FLET_ASSETS_DIR优先级最高,且永远不会被静默丢弃。
三、呈现模式:AppView 枚举
view参数控制应用以何种方式呈现。其可选值定义在 sdk/python/packages/flet/src/flet/controls/types.py:
| 枚举值 | 字符串值 | 行为 |
|---|---|---|
AppView.WEB_BROWSER | "web_browser" | 以 Web 服务器方式运行,并自动在用户浏览器中打开 |
AppView.FLET_APP | "flet_app" | 在 Flet 桌面窗口中运行(默认) |
AppView.FLET_APP_WEB | "flet_app_web" | 桌面窗口 + Web 服务器后端 |
AppView.FLET_APP_HIDDEN | "flet_app_hidden" | 启动隐藏的 Flet 桌面窗口 |
桌面窗口模式的启动依赖flet_desktop包(run_async中通过ensure_flet_desktop_package_installed()按需确保安装,并调用open_flet_view_async打开窗口,见 app.py)。
四、Web 渲染器与路由策略
WebRenderer:Web 端渲染器选择
web_renderer用于 Web 托管场景,定义于 types.py:
AUTO(默认):由运行时自动选择。WebAssembly 构建下 Chromium 系浏览器优先使用 skwasm,其他浏览器回退到 CanvasKit;默认 Web 构建则始终使用 CanvasKit。CANVAS_KIT:CanvasKit 渲染器,兼容性最好,是默认 Web 构建的标准渲染器;Flet 每次 UI 更新都会在 JavaScript 与 Dart 之间交换字节缓冲区,CanvasKit 在这种交换上显著更快。SKWASM:仅 WebAssembly 构建可用,渲染性能可能更优,但跨 JS/Dart 边界的字节缓冲交换较慢,且需要浏览器与服务器满足 WebAssembly 及(多线程渲染时)SharedArrayBuffer 安全配置要求。
RouteUrlStrategy:URL 路由策略
route_url_strategy仅影响 Web 托管应用,定义于 types.py:
PATH(默认):路由存放在浏览器 pathname 中,URL 形如https://example.com/store。此策略通常要求 Web 服务器将未匹配的请求重写到index.html,以保证深链接与页面刷新可用。HASH:路由存放在 URL 锚点片段中,URL 形如https://example.com/#/store。当无法配置托管服务器做 pathname 重写时,该策略是实用之选。
五、底层运行机制:四种传输通道的自动选择
flet.run()最终调用asyncio.run(run_async(...))(app.py)。在run_async内部(app.py),传输通道按以下优先级选择:
is_pyodide() 且非嵌入式 → PyodideConnection(浏览器内嵌执行) FLET_DART_BRIDGE_PORT 且嵌入式 → dart_bridge 进程内传输 嵌入式,或 view ∈ {FLET_APP, FLET_APP_HIDDEN, None} 且未强制 Web → Socket 服务器 其余情况 → FastAPI/uvicorn Web 服务器- Pyodide 通道:在浏览器内直接运行 Python(
is_pyodide()为真时),通过PyodideConnection建立连接(app.py)。 - dart_bridge 进程内通道:嵌入式场景下设置
FLET_DART_BRIDGE_PORT时启用(app.py)。它与 Socket 服务器使用相同的 MsgPack 帧协议,但通过进程内字节通道传输,省去了 socket 文件与内核上下文切换。从源码注释可见,Android 进程复用场景下_DartBridgeServerHandle会通过dart_bridge.add_session_restart_handler监听 Dart VM 重启,并透明地在新端口上重建连接。 - Socket 服务器:桌面/嵌入式模式默认通道(
FletSocketServer),支持FLET_SERVER_UDS_PATH环境变量指定 Unix Domain Socket(app.py)。 - Web 服务器:基于 FastAPI/uvicorn,由
flet_web包中的serve_fastapi_web_app提供服务(app.py),负责加载 Web 前端、处理页面 URL、资源与上传目录。
此外,run_async为桌面/Web 进程注册了SIGINT与SIGTERM信号处理器,收到信号后通过terminate事件请求优雅退出,并在finally中确保关闭连接(app.py)。
六、环境变量一览
flet.run()/run_async()的行为受以下环境变量影响(均可在 app.py 源码中核实):
| 环境变量 | 作用 |
|---|---|
FLET_FORCE_WEB_SERVER | 为真时强制使用 Web 服务器模式(等价于view=WEB_BROWSER) |
FLET_SERVER_PORT | 覆盖 Web 服务器端口 |
FLET_SERVER_IP | 覆盖 Web 服务器绑定主机 |
FLET_SERVER_UDS_PATH | Socket 服务器改用 Unix Domain Socket |
FLET_WEB_APP_PATH | 覆盖name参数,决定 Web URL 路径段 |
FLET_ASSETS_DIR | 覆盖assets_dir(优先级最高) |
FLET_DISPLAY_URL_PREFIX | 应用启动时按prefix + page_url + view打印 URL,且不再自动打开浏览器 |
FLET_DART_BRIDGE_PORT | 嵌入式场景启用进程内 dart_bridge 通道 |
FLET_LOG_LEVEL | 设置日志级别;flet run -v即通过该变量让框架日志输出到控制台 |
其中FLET_FORCE_WEB_SERVER在 Linux 服务器环境(is_linux_server())下会被自动置真,这是桌面窗口在无显示服务环境下无法启动时的兜底行为(app.py)。
七、run 与 run_async:同步与异步入口
flet.run()与flet.run_async()是一对孪生入口(后者文档位于 run_async.md),区别在于:
run():同步 API,内部用asyncio.run()包装run_async,适合在脚本__main__块中直接调用,也是仓库示例(如 7guis、cookbook 等)的标准写法。run_async():协程 API,须在既有事件循环中await,适合集成到异步应用(如 FastAPI、异步测试框架)中。其参数与run()完全一致,但没有export_asgi_app参数。- 两者都接受字符串形式的枚举参数(如
view="web_browser"),内部通过AppView(...)、WebRenderer(...)、RouteUrlStrategy(...)自动完成类型转换。
在既有事件循环中嵌入:export_asgi_app
export_asgi_app=True是run()独有的集成模式:此时run()不会启动事件循环,而是返回一个配置好的 FastAPI ASGI 应用(依赖flet_web包中的get_fastapi_web_app,见 app.py)。这使 Flet 页面能够直接挂载到用户自己的 FastAPI/ASGI 服务器中,与已有的路由、中间件共存。该模式下资源路径基于当前工作目录解析,适用于服务器端部署。
八、实战模式小结
结合仓库示例与源码行为,可总结出以下常用模式:
- 桌面应用(默认):
ft.run(main),view保持AppView.FLET_APP,自动启动 Flet 桌面窗口。 - 浏览器运行:
ft.run(main, view=ft.AppView.WEB_BROWSER),启动 Web 服务器并打开浏览器;亦可通过flet runCLI 配合--web等选项达成(参见 CLI 文档)。 - 无界面服务端:设置
FLET_FORCE_WEB_SERVER=1,或使用host="0.0.0.0"让外部设备可访问;多用户场景下建议结合 FastAPI 集成文档 使用export_asgi_app=True托管。 - 异步应用:在协程中
await ft.run_async(main, ...),支持async def main(page)乃至异步生成器形式的处理器。 - Pyodide/嵌入式:
run()自动检测 Pyodide 环境与FLET_DART_BRIDGE_PORT,无需额外代码即可在浏览器内或嵌入式宿主中运行。
九、延伸阅读与源码导航
- API 文档骨架:run.md(由 CrocoDocs 组件从 docstring 生成,生成管线见 tools/crocodocs/src/crocodocs/generate.py)
- 核心实现:sdk/python/packages/flet/src/flet/app.py
- 枚举类型定义:sdk/python/packages/flet/src/flet/controls/types.py
- 异步入口文档:run_async.md
- 真实调用示例:sdk/python/examples/apps/7guis/counter/main.py
- 入口相关教程:running-app.md
- 打包部署参考:packaging 相关文档
【免费下载链接】fletBuild realtime web, mobile and desktop apps in Python only. No frontend experience required.项目地址: https://gitcode.com/gh_mirrors/fl/flet
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考