跳到主要内容

Flet 打包更新

· 阅读需 10 分钟
Feodor Fitsner
Flet 创始人和开发者

问题

当您将 Flet 程序打包成在移动设备(或桌面设备)上运行的 Python 程序时,生成的包(.apk、.ipa、.exe、.app)包含您的 Python 程序、Python 解释器和 Python 标准库

如果您的程序只使用 Python 标准库,那么打包过程相对简单——Flet 会将您的代码压缩并将 Flutter 应用程序与为目标平台(Android 或 iOS)编译的 Python 解释器和标准库组合在一起。

然而,当您的 Flet 程序使用第三方包时,可能会出现问题,而这些包有数千个发布在 PyPI 或 Conda 上。

第三方包有两种类型:

纯 Python 包

“纯 Python”包是仅包含 Python 代码的包,不包括用 C、C++、Rust 或其他语言编写的扩展。您只需要一个 Python 解释器和 Python 标准库即可运行纯 Python 包,而无需关心您的操作系统或平台。

此类包的示例:httpxclickrichrequests

要验证包是否纯粹,请在 PyPI 上找到该包并导航到其“下载文件”页面。如果在“已构建分发”部分下只有一个以 -py3-none-any.whl 结尾的 wheel,那么很可能它是一个纯 Python 包,可以在任何带有 Python 的设备上“按原样”运行。

我们说*“可能”*是因为该纯包可能依赖于非纯包,例如 pydantic 是一个纯包,但它需要使用 Rust 编写的 pydantic-core 非纯包才能正常工作。

非纯 Python 包

“非纯 Python”包是部分或全部用 C、C++、Rust 或其他语言编写并必须为其运行的平台编译为机器码的包。

此类包的示例:cryptographyopencv-pythonnumpymsgpack

在非纯包的“下载文件”页面上,您会发现为各种平台预构建的轮子:macOS、Windows、Linux。

当您运行 pip install <package> 时,pip 会尝试根据轮子后缀查找特定平台和 Python 版本的轮子。

这是包开发者提供的礼貌行为,为多个平台提供预编译的轮子。某些平台可能缺少轮子,或者没有轮子——只有“源分发”中的 .tar.gz 包含包源代码。

从源代码构建包很难

要安装仅具有源代码分发的包,pip 会尝试使用安装的编译器、链接器、库和 SDK 在您的机器上构建非 Python 代码。然而,这个过程可能既漫长又容易出错。编译后的代码库可能很大,并且您的机器可能缺少所需的库或工具链。

还没有适用于 iOS 和 Android 的轮子

PyPI 上还没有适用于 iOS 和 Android 的预构建轮子,并且 PyPI 的验证过程不允许包开发者上传这些轮子,因为 iOS 和 Android 都不是 Python 的正式支持平台。

有一个过程(PEP 730PEP 738)将为 Python 3.13 添加对 iOS 和 Android 的正式支持,因此,希望开发者体验将有所改善。

包依赖关系

纯 Python 包可以导入或依赖非纯包,在将您的 Flet 应用程序打包以在移动设备上运行时,您应该牢记这一点。

例如,supabase 包用于访问 Supabase API,是一个依赖于 pydantic 包的纯包,而 pydantic 包本身依赖于用 Rust 编写的 pydantic-core 非纯包。因此,要运行使用 Supabase API 的 Flet 应用程序,打包过程应该能够找到适合目标平台的预构建轮子。如果 PyPI 没有该轮子,那么要么是 Flet 开发人员在他们的服务器上构建该轮子并托管它,要么是您在自己的机器上构建该轮子。

要查看包的依赖关系图,您可以使用 pipgrip

使用 --tree 选项运行它以获得依赖关系树视图:

$ pipgrip --tree fastapi

fastapi (0.110.3)
├── pydantic!=1.8,!=1.8.1,!=2.0.0,!=2.0.1,!=2.1.0,<3.0.0,>=1.7.4 (2.7.1)
│ ├── annotated-types>=0.4.0 (0.6.0)
│ ├── pydantic-core==2.18.2 (2.18.2)
│ │ └── typing-extensions!=4.7.0,>=4.6.0 (4.11.0)
│ └── typing-extensions>=4.6.1 (4.11.0)
├── starlette<0.38.0,>=0.37.2 (0.37.2)
│ └── anyio<5,>=3.4.0 (4.3.0)
│ ├── idna>=2.8 (3.7)
│ └── sniffio>=1.1 (1.3.1)
└── typing-extensions>=4.8.0 (4.11.0)

当前方法

我们在4 个月前发布了打包的第一个版本,自那时以来,我们意识到初始方法存在多个缺陷,需要改进。

当您使用当前版本的 Flet 运行 flet build apk 时,它会下载为 Android(或如果使用 flet build ipa 运行时为 iOS)预构建的 Python 运行时和标准库。

对于非纯包,例如 numpy,Flet 要求您使用 Kivy 的“Python for Android”(p4a)工具自行构建这些包,然后提供一个路径到预构建包可以找到的“p4a”分发包。

这是问题 #1 - 您被迫与在您的机器上安装“p4a”工具并编译 Python 模块的复杂过程作斗争。

问题 #2 - 来自 p4a 的 dist 目录中的所有包将被包含在最终的应用程序包中 - 它可能包含无关的包和其他垃圾。

问题 #3 - 非纯包必须在运行 flet build 命令之前构建。您必须分析应用程序的所有依赖项,并分离出必须使用 p4a 构建的内容。

问题 #4 - p4a 的“配方”可能非常旧或缺失。您希望旧版本的包适用于您的应用程序,尝试编写“配方”并希望它能工作,或者在 Kivy 存储库中提交新配方的请求。

当您完成使用 p4a 构建非纯包时,Flet 要求您在 requirements.txt 中仅指定纯包,这在纯包直接或间接依赖于非纯包时不起作用(请参见上述示例) - 这是问题 #5。有一个最近的例子说明了这个问题:flet buildrequirements.txt 中用 flet-embed 替换 flet,但它无法知道是否有第三方包依赖于 flet,因此会安装 flet-embed 和不适用于移动设备的 flet。这不是解决方案,而是一个黑客!

打包 2.0

在 Flet 打包实现的下一次迭代中,我们将放弃 Kivy 并用 Mobile Forge 取而代之。Mobile Forge 是由 Beeware 团队基于他们在 Briefcase 和 Chaquopy 上的经验创建的。Mobile Forge 是一个用于二进制 Python 包的打包

工具的清洁实现,依赖于 crossenv

Mobile Forge 和 crossenv 的主要承诺是,大多数现有的非纯 Python 包将能够通过简单地添加一个 meta.yaml 文件的配方来为 iOS 和/或 Android 编译,而无需任何黑客或补丁。

我们将使用 Mobile Forge 为 iOS 和 Android 预构建最流行的非纯 Python 包,并在我们自己的公共存储库中托管它们。您将能够使用该工具来构建和贡献其他不在我们存储库中的包。

我们在 Flet 讨论中创建了一个新的“包”类别,您可以在其中发布、投票和讨论适用于 Flet 的非纯(本机)Python 包的请求(在发布之前请查看规则)。Flet 的目标是提供最全面的预构建 Python 包目录,并使添加新包的过程尽可能友好和透明。

新版本的 flet build 将使用自定义的虚拟 pip 索引。此索引将分析依赖项,检测非纯包,并提供 pip 移动包。对于所有其他包,它将回退到 PyPI。

希望新的打包版本将在几周内可用。在我们工作期间,我们鼓励您访问并查看您需要的包是否在那里。提交请求或为现有包投票将帮助我们优先处理包的“配方”。

谢谢!

控件和主题增强

· 阅读需 6 分钟
Henri Ndonko
Flet 贡献者和维护者

在发布 Flet 0.21.0 一个多月后,我们很高兴地宣布发布 Flet 0.22.0。

此版本带来了许多增强、错误修复和弃用功能:

增强功能

这是本次发布的主要关注点之一。我们进行了两种类型的增强:

控件增强

我们遍历了现有控件的长列表,并在可能的情况下公开了更多属性 - PR #2882。这将为您提供更多对 Flet 控件的控制,以便在您的优秀应用程序中使用。

以下是完整列表:

  • AppBar: elevation_on_scroll, exclude_header_semantics, force_material_transparency, is_secondary, shadow_color, surface_tint_color, clip_behavior, title_spacing, toolbar_opacity, title_text_style, toolbar_text_style, shape
  • AlertDialog: action_button_padding, clip_behavior, icon_padding, shadow_color, surface_tint_color
  • Banner: content_text_style, margin, elevation, divider_color, shadow_color, surface_tint_color, on_visible
  • CupertinoListTile: leading_size, leading_to_title
  • CupertinoSegmentedButton: click_color
  • CupertinoSwitch:on_label_color, off_label_color
  • CupertinoTimerPicker: item_extent
  • Chip: surface_tint_color, color, click_elevation, clip_behavior, visual_density, border_side
  • Divider: leading_indent, trailing_indent
  • ExpansionTile: dense, enable_feedback, visual_density
  • Card: clip_behavior, is_semantic_container, show_border_on_foreground, variant
  • Checkbox: border_side, semantics_label, shape, splash_radius, is_error, visual_density, mouse_cursor
  • CircleAvatar: on_image_error
  • DataTable: clip_behavior
  • DatePicker: on_entry_mode_change
  • Draggable: on_drag_complete, on_drag_start
  • DragTarget: on_move
  • Dropdown: fill_color, hint_content, icon_content, elevation, item_height, max_menu_height, icon_size, enable_feedback, padding, icon_enabled_color, icon_disabled_color, on_click
  • ElevatedButton: clip_behavior
  • FloatingActionButton: clip_behavior, enable_feedback, focus_color, foreground_color, disabled_elevation, elevation, focus_elevation, highlight_elevation, hover_elevation, mouse_cursor
  • GridView: cache_extent, clip_behavior, semantic_child_count
  • IconButton: alignment, disabled_color, focus_color, enable_feedback, hover_color, padding, splash_color, splash_radius, focus_color, mouse_cursor, visual_density
  • Image: exclude_from_semantics, filter_quality
  • ListTile: enable_feedback, horizontal_spacing, min_leading_width, min_vertical_padding, selected_color, selected_tile_color, style, title_alignment, icon_color, text_color, shape, visual_density, mouse_cursor, title_text_style, subtitle_text_style, leading_and_trailing_text_style
  • ListView: cache_extent, clip_behavior, semantic_child_count
  • NavigationBar: animation_duration, overlay_color
  • NavigationDrawerDestination: bgcolor
  • NavigationDestination: bgcolor
  • NavigationRail: selected_label_text_style, unselected_label_text_style
  • NavigationRailDestination: indicator_color, indicator_shape
  • Option: alignment, on_click
  • OutlinedButton: clip_behavior
  • Page: locale_configuration
  • PopupMenuItem: height, padding, mouse_cursor
  • PopupMenuButton: bgcolor, clip_behavior, elevation, enable_feedback, icon_color, shadow_color, surface_tint_color, icon_size, padding, splash_radius, shape, on_open, on_cancel
  • ProgressBar: border_radius, semantics_label, semantics_value
  • ProgressRing: semantics_label, semantics_value, stroke_cap, stroke_align
  • Radio: focus_color, hover_color, overlay_color, splash_radius, toggleable, visual_density, mouse_cursor
  • SearchBar: keyboard_type, view_surface_tint_color, autofocus
  • SelectionArea: on_change
  • Slider: interaction, overlay_color, mouse_cursor, secondary_track_value, secondary_active_color
  • Stack: alignment, fit
  • SnackBar: clip_behavior, shape, on_visible, action_overflow_threshold
  • Switch: hover_color, splash_radius, overlay_color, track_outline_color, mouse_cursor
  • Tabs: divider_height, enable_feedback, indicator_thickness, is_secondary, mouse_cursor, clip_behavior
  • TextField: fill_color, hover_color
  • TimePicker: orientation, on_entry_mode_change
  • Tooltip: enable_tap_to_dismiss, exclude_from_semantics
  • VerticalDivider: leading_indent, trailing_indent

如果您觉得有些功能缺失且需要添加,请随时告诉我们。

查看我写的关于 Page.locale_configuration 的文章这里

主题增强

用于应用程序主题设置的 Theme 类在浅色和深色模式下得到了进一步增强。 引入了许多新主题 - PR #2955

查看主题指南 这里

Rive 动画

Rive 是一个非常流行的实时交互设计和动画工具。 新引入的 Rive 控件允许您在应用程序中加载和可视化任何 Rive 动画。

动画的来源 (Rive.src) 可以是本地资源文件或 URL - 如常所述,这完全取决于你的需求。

父控件

根据 #952 的请求,已添加访问任何控件父级的功能:Control.parent

阅读更多内容 这里

错误修复

成功修复了以下问题:

  • #2560 - Dropdown.bgcolor 未得到视觉上的尊重
  • #2740 - CircleAvatar 无法与本地资产图像一起使用
  • #2781 - Linux 上引发了 'FletSocketServer' 错误
  • #2826 - PopupMenuItem.data 未得到尊重
  • #2839 - ExpansionTile.initially_expanded 无视觉效果
  • #2867 - PopupMenuButton 始终显示“显示菜单”工具提示
  • 在某些 Python 版本上,您可能会看到 RuntimeError('Event loop is closed'),通常在关闭应用程序窗口时显示。Python-dev 团队最近修复了这一 asyncio 相关的问题,但该修复仅存在于 2024 年发布的版本中。因此,如果您遇到此问题,请下载最新的 Python 版本之一并替换您环境中使用的版本。

特别感谢 Flet 动态社区报告他们遇到的所有问题。我们将继续努力解决剩余的问题。

弃用

如前面在有关 Flet v0.21.0 的 公告 中提到的,所有弃用将在版本 1.0 中完全从 API 中删除 - 因此您有足够的时间来更新您的应用程序。

您无需完全记住哪些内容已弃用,因为我们添加了 DeprecationWarnings,它们将直接显示在您的控制台中(不会破坏您的应用程序)。

文档

Flet 文档已重新组织,以便于导航(特别是对于初学者/新用户)。

升级到 Flet 0.22.0,测试您的应用程序,并告诉我们您对新增功能的看法。 如果您有任何问题,请加入 Flet Discord 服务器 或在 Flet GitHub 讨论 中创建一个新主题。

祝您使用 Flet 愉快!

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

祝你愉快!

Flet 自适应 UI 和自定义控件发布

· 阅读需 5 分钟
Feodor Fitsner
Flet 创始人和开发者

🥰 情人节快乐,亲爱的朋友们!🥰

我们刚刚发布了 Flet 0.20.0,重点如下:

  1. 自适应 UI。
  2. 使用第三方 Flutter 包扩展 Flet 应用。
  3. 新控件:Video(耶!)、AudioRecorder 和一系列 Cupertino 风格控件。Flet 现在包含 97 个内置控件!
注意

Flet 0.20.0 包含一个新的 Video 控件。虽然 macOS 和 Windows 已经包含所有测试 Flet 应用所需的媒体库,但在 Linux 上需要安装 libmpv 包。在 Ubuntu/Debian 上可以通过以下命令安装:

sudo apt install libmpv-dev mpv

自适应 UI

自适应控件允许编写具有单个代码库的应用程序,这些应用程序在运行的平台不同时具有不同的外观和行为。

截至目前,Flet 提供了 11 个自适应控件。要使控件自适应,可以将其 adaptive 属性设置为 True

在 Flet 0.20.0 中,我们为所有类似容器的控件引入了 adaptive 属性。 在容器上设置 adaptive=True 会将此属性传播到所有子自适应控件。

Page 添加了 design 属性,使您可以对控件的设计语言进行细粒度控制,其值可以为:ft.PageDesign.ADAPTIVEft.PageDesign.MATERIALft.PageDesign.CUPERTINO

只需设置 page.design = ft.PageDesign.ADAPTIVE,即可使您的应用在 iOS 和 Android 设备上看起来都很棒:

iPhone

Android

集成现有的 Flutter 包

目前 Flet 提供了近 100 个控件,但如您所想,并不是每个 Flutter 库/小部件都可以添加到核心 Flet 库中,Flet 团队也无法在可接受的时间范围内独自完成。

同时,我们也不希望让选择 Flet 来构建其下一个商业或企业应用的早期采用者处于他们的进展依赖于 Flet 团队是否有时间和愿意实现他们所需的 Flutter 控件的情况。

在 Flet 0.20.0 中,我们重新构建了 Flutter 核心包,并确定了可供第三方开发者使用的 API 来添加他们自己的用 Dart 编写的 Flet 控件。

我们目前正在编写 API 文档,但您现在可以通过查看 VideoAudio 控件的 Dart 源代码来了解如何实现自定义 Flutter 包。

简而言之,您需要创建一个新的 Flutter 包,其中包含并导出两个方法:

void ensureInitialized();
Widget createControl(CreateControlArgs args);

参见 ensureInitialized()createControl()Video 控件实现。

在 Python 方面,您需要创建一个从 Control(非可视或叠加控件)或 ConstrainedControl 继承的新类。

参见 Python 中 Video 类的实现。

要在构建 Flet 应用时集成自定义 Flutter 包,使用 flet build 命令,您可以使用 --include-packages 选项或在 Flet 应用根目录下的 pubspec.yaml 文件中列出额外的包。

Video 控件

Video 控件在一个单独的 Flutter 包中实现。

要构建包含 Video 控件的 Flet 应用,请在 flet build 命令中添加 --include-packages flet_video,例如:

flet build apk --include-packages flet_video

Flet 0.20.0 是一个相对较大的 版本,可能会破坏一些东西。

升级到 Flet 0.20.0,测试您的应用,并通过加入 Flet Discord 服务器 或在 Flet GitHub 讨论 中创建新线程来告诉我们您的想法。

祝您愉快!

将应用打包进行分发

· 阅读需 4 分钟
Feodor Fitsner
Flet 创始人兼开发者

亲爱的朋友们!在今年的最后一篇文章中,我想感谢大家对 Flet 项目的贡献,无论是散发信息,提交拉取请求,加入 Discord 讨论还是发送烦人的错误报告!

在你们的极好支持下,我们在 2023 年取得了很多成就:

  • 70 多个控件(特别感谢 @ndonkoHenri 的巨大贡献)。
  • GitHub 上获得 7,700 颗星。
  • Discord 上有 2,150 名用户和社区版主(感谢你们!)。
  • Flet 与 Pyodide 的集成,用于纯客户端的 Python 应用——没有其他框架能为 Pyodide 提供更好的用户界面!
  • Flet 应用已上线 AppStore 和 Google Play——这是在移动设备上测试的好方法,也是 Flet 应用被接受的实际证明。
  • ……最后……隆重宣布……🥁🥁🥁 flet build 命令来了!🎉🎉🎉

🎄 "新年版" 🎄 的 Flet 0.18.0 刚刚发布,这个版本允许在所有平台上打包您的 Flet 应用进行分发:iOS、Android、Web、macOS、Windows 和 Linux!

一个命令玩转所有!

现在闭环完成了:您可以使用 Flet CLI 创建 (flet create)、运行 (flet run) 和构建 (flet build) 您的 Flet 应用。

Flet CLI 提供了 flet build 命令,该命令允许将 Flet 应用打包成独立的可执行文件或安装包以便分发。

flet build 命令取代了 flet pack(打包成桌面应用)和 flet publish(打包成静态网站)命令,并允许将您的 Flet 应用转换为 Android 或 iOS 包、桌面应用和静态网站。

对于构建桌面应用,flet build 不再依赖于 flet pack 使用的 PyInstaller,而是使用 Flutter SDK 生成一个快速、离线、完全可定制的(带有您自己的图标、关于对话框和元数据)Windows、Linux 和 macOS 的可执行文件,其中嵌入了 Python 运行时并在进程中运行。

flet publish 相比,使用 flet build 构建的静态网站加载速度更快,因为所有 Python 依赖项现在都打包成一个单一的归档文件,而不是在运行时通过 micropip 拉取。flet build web 还会检测内置在 Pyodide 中的原生 Python ,如 bcrypthtml5libnumpy 等,并从 Pyodide 包注册表中安装它们。

查看 打包应用以便分发 指南,获取关于 flet build 命令的完整信息。

请通过加入 Flet Discord 服务器 或在 Flet GitHub 讨论区 创建新话题,让我们知道您的想法。

祝大家新年快乐!节日愉快!