Flet FastAPI 和异步 API 改进
Flet 使编写动态的实时 Web 应用程序变得非常有趣!
Flet 0.21.0 进一步改进了 Web 应用程序开发体验以及在 Flet 应用中使用 asyncio API 的体验。
以下是Flet 0.21.0的新功能:
用Uvicorn的FastAPI取代内置Web服务器
从Flet诞生之初开始,用于服务Web应用的内置Web服务器是用Go编写的,名为“Fletd”。当你运行flet run --web
命令时,它会在后台启动。Fletd是Flet Python轮子的一部分,增加了几兆字节的大小。此外,Python应用使用WebSockets与Fletd Web服务器通信,有时会增加明显的开销。
在Flet 0.10.0中,我们添加了对FastAPI的支持,以使用AsyncIO API构建“严肃的”Web应用。
现在,在Flet 0.21.0中,内置Web服务器已被完全移除,取而代之的是FastAPI和Uvicorn。Fletd不再是Flet分发版的一部分。
使用FastAPI意味着不再有通信开销,因为Web服务器是Flet应用的一部分。此外,你不需要做任何额外的步骤即可使用FastAPI在生产环境中托管你的应用——只需使用相同的ft.app(main)
命令运行你的应用。
flet_fastapi
包已被弃用,其内容已移至flet
包中的flet.fastapi
模块。如果你在Flet应用中使用了FastAPI,请将:
import flet_fastapi
替换为:
import flet.fastapi as flet_fastapi
使用任何 ASGI Web 服务器进行托管
你可以使用任何兼容 ASGI 的服务器托管你的 Flet Web 应用程序,如 Uvicorn(默认使用),Hypercorn 或 Daphne。
只需告诉 Flet 导出 ASGI 应用程序:
import flet as ft
def main(page: ft.Page):
page.add(ft.Text("Hello ASGI!"))
app = ft.app(main, export_asgi_app=True)
然后用 Hypercorn 运行:
hypercorn main:app --bind 0.0.0.0:8000
Web应用环境变量
Web 应用程序托管的每个方面都可以通过环境变量控制:
FLET_FORCE_WEB_SERVER
- 设置为true
强制运行应用程序作为 Web 应用程 序。在无头 Linux 主机上自动设置。FLET_SERVER_PORT
- 运行应用程序的 TCP 端口。如果程序在 Linux 服务器上运行或设置了FLET_FORCE_WEB_SERVER
,则为8000
;否则为随机端口。FLET_SERVER_IP
- 监听 Web 应用程序的 IP 地址,例如127.0.0.1
。默认是0.0.0.0
- 绑定到所有服务器 IP。FLET_ASSETS_DIR
- 应用程序 "assets" 目录的绝对路径。FLET_UPLOAD_DIR
- 应用程序 "upload" 目录的绝对路径。FLET_MAX_UPLOAD_SIZE
- 允许上传文件的最大大小,以字节为单位。如果未指定,则不受限制。FLET_SECRET_KEY
- 签署临时上传 URL 的密钥。FLET_WEB_APP_PATH
- 域名后的 URL 路径,用于托管 Web 应用程序,例如/apps/myapp
。默认是/
- 在根目录下托管应用程序。FLET_SESSION_TIMEOUT
- 会话的生命周期,以秒为单位。默认是3600
。FLET_OAUTH_STATE_TIMEOUT
- 完成 OAuth Web 流程的最长允许时间,以秒为单位。默认是600
。FLET_WEB_RENDERER
- Flutter 渲染模式:canvaskit
(默认),html
或auto
。FLET_WEB_USE_COLOR_EMOJI
- 设置为true
、True
或1
以加载带有彩色表情符号的 Web 字体。FLET_WEB_ROUTE_URL_STRATEGY
-path
(默认)或hash
。FLET_WEBSOCKET_HANDLER_ENDPOINT
- WebSocket 处理程序的自定义路径。默认是/ws
。FLET_UPLOAD_HANDLER_ENDPOINT
- 上传处理程序的自定义路径。默认是/upload
。FLET_OAUTH_CALLBACK_HANDLER_ENDPOINT
- OAuth 处理程序的自定义路径。默认是/oauth_callback
。
异步优先框架
Flet 现在是一个异步优先框架,这意味着你不必决定你的应用程序是完全同步还是异步,你可以在同一个应用程序中混合使用同步和异步方法。
例如,在 Flet 0.21.0 中,你可以这样编写一个应用程序:
import flet as ft
import time
import asyncio
def main(page: ft.Page):
def handler(e):
time.sleep(3)
page.add(ft.Text("Handler clicked"))
async def handler_async(e):
await asyncio.sleep(3)
page.add(ft.Text("Async handler clicked"))
page.add(
ft.ElevatedButton("Call handler", on_click=handler),
ft.ElevatedButton("Call async handler", on_click=handler_async)
)
ft.app(main)
在上面的示例中,点击一个按钮由“阻塞”处理程序处理,而点击第二个按钮调用异步处理程序。第一个处理程序在threading.Thread
中运行,而第二个处理程序在asyncio.Task
中运行。
此外,请注意在async def
处理程序中不再需要使用await page.add_async()
,而是可以使用常规的page.add()
。
大多数Page.<method>_async()
和Control.<method>_async()
方法已被弃用,应使用其Page.<method>()
和Control.<method>()
对应方法。
唯一的例外是返回结果的方法,例如Audio
控制中的那些方法:在异步事件处理程序中仍然必须使用异步方法。
自定义控件 API 规范化
在这个 Flet 版本中,我们还重新审视了在 Python 中编写自定义控件的 API。
因此,UserControl
类已被弃用。你只需继承具有适合你需求的布局的特定控件。
例如,Countdown
自定义控件只是一个Text
,可以如下实现:
import asyncio
import flet as ft
class Countdown(ft.Text):
def __init__(self, seconds):
super().__init__()
self.seconds = seconds
def did_mount(self):
self.running = True
self.page.run_task(self.update_timer)
def will_unmount(self):
self.running = False
async def update_timer(self):
while self.seconds and self.running:
mins, secs = divmod(self.seconds, 60)
self.value = "{:02d}:{:02d}".format(mins, secs)
self.update()
await asyncio.sleep(1)
self.seconds -= 1
def main(page: ft.Page):
page.add(Countdown(120), Countdown(60))
ft.app(main)
注意使用self.page.run_task(self.update_timer)
启动新任务。
控件开发者还必须使用self.page.run_thread()
方法在线程中启动新后台作业。
如果你想生成自己的任务或线程,Flet通过Page.loop
和Page.executor
属性分别提供当前事件循环和线程执行器。
Control._before_build_command()
被Control.before_update()
取代
Control.build()
现在不应返回任何控件,而必须更新继承的控件属性,例如:
def build():
self.controls.append(ft.Text("Something"))
Control.did_mount_async()
和Control.will_unmount_async()
已被弃用。请使用Control.did_mount()
和Control.will_unmount()
。
新的Cupertino控件
此Flet版本添加了更多Cupertino控件,使你的应用在iOS上更加出色:
CupertinoActivityIndicator
CupertinoActionSheet
CupertinoSlidingSegmentedButton
CupertinoSegmentedButton
CupertinoTimerPicker
CupertinoPicker
CupertinoDatePicker
CupertinoContextMenu
无障碍性改进
现在Flet已经完全实现了Semantics
控件和新的SemanticsService
控件。
应用生命周期更改事件
新增了 Page.on_app_lifecycle_state_change
事件,允许监听应用程序生命周期的变化。
例如,当应用变为活动状态(切换到前台)时,你现在可以使用最新信息更新UI。此事件适用于iOS、Android、所有桌面平台和Web!
以下是识别的应用程序生命周期转换:
SHOW
RESUME
HIDE
INACTIVE
PAUSE
DETACH
RESTART
阅读有关每个生命周期状态的更多信息。
这是一个如何使用此事件的小示例:
import flet as ft
def main(page: ft.Page):
def app_lifecycle_change(e: ft.AppLifecycleStateChangeEvent):
if e.state == ft.AppLifecycleState.RESUME:
print("Update UI with fresh data!")
page.on_app_lifecycle_state_change = app_lifecycle_change
page.add(ft.Text("Hello World"))
ft.app(target=main)
Flet 0.21.0版本有一些重大变化。升级到它,测试你的应用,并让我们知道它的运行情况。加入Flet Discord服务器或在Flet GitHub讨论区创建一个新话题。
祝你愉快!