跳到主要内容

Flet FastAPI 和异步 API 改进

· 阅读需 9 分钟

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(默认使用),HypercornDaphne

只需告诉 Flet 导出 ASGI 应用程序:

main.py
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(默认),htmlauto
  • FLET_WEB_USE_COLOR_EMOJI - 设置为 trueTrue1 以加载带有彩色表情符号的 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()

API变更

大多数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.loopPage.executor属性分别提供当前事件循环和线程执行器。

API变更

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讨论区创建一个新话题。

祝你愉快!