记 Flet 开发版构建失败的常见问题解决

Creeper19472

Flet 是一个允许利用 Python 来编写和构建 Flutter 应用的框架。如果你在寻找使用 Python 构建图形化界面应用的解决方案的话,除了尝试我们已经耳熟能详的 Tkinter 和 Qt 等框架之外,Flet 也是一个很有吸引力的选择——它支持一次编写,多端部署,能够有效地节省那些为了为桌面端和移动端分别进行适配所需要消耗的大量时间。

不过,呃……如果你真的试图投身于其中,那么你将不可避免地碰上一系列问题,因为 Flet 在无法带来对 Flutter 本身问题的修正的同时,自己还会带来很多问题。而说实话,Flet 的社群活跃度并不是很高,对于国际社群是如此,在中文圈就更加惨不忍睹了。尽管 Flet 的主要开发者只有寥寥几人,但在过去的数个月中,Flet 还是发生了一些值得注意的大版本迭代,而这些迭代所造成的影响似乎还是尚未有任何中文文章介绍过的。我或许会在之后的某个时候讨论这些改动中非常值得注意的地方,但对于本文而言,我将重点就在使用最新开发版本的 Flet 构建应用时所可能遇到的各种问题进行简述。本文假定你要构建的代码不存在问题。

1. 找不到对应的分支

当运行 flet build 命令时发生以下错误:

1
The 0.82.3 branch of repository https://github.com/flet-dev/flet-build-template.git could not found, have you made a typo?

这是由上游的 flet-build-template 仓库尚未创建具有和此开发版相对应的名称的分支所导致的。这种事情时常发生,特别是对于开发版本而言。尽管我正试图请求开发者们添加对自动向下检索功能的支持,但在那样的功能实现之前,为了解决这个问题,要么根据官方文档的提示显式地指定一个你确认可以正常完成构建的 Reference,要么自行 fork 一份构建模板,为这个 fork 手动添加需要的分支(一种通常的做法是从能找到的具有最新版本号的分支创建而来),然后再将要使用的构建模板手动配置为你所拥有的 fork 仓库。你将可能看到这种做法在之后的开发过程中显得好处多多。

你也可以顺带向 Flet 提出 Issue,提醒他们记得解决这个问题——但最好不要指望他们能够尽快处理它。

2. 未定义的方法

1
2
3
4
[16:53:30] Building Windows application...                                     
../flutter-packages/flet_datatable2/lib/src/datatable2.dart(193,12):
error GE5CFE876: The method 'ConstrainedControl' isn't defined for
the type '_DataTable2ControlState'.

这通常是由 Flet 即使在开发版也仍然拉取仅与最新的正式版相匹配的 Flutter 包导致的。Flet 仅在每个正式版发布时才向 pub.dev 推送新的包版本,如果开发版在这段窗口期内添加了对 Flutter 包部分的改动(例如增加了新的控件或修改了已有控件的实现),便容易引发上面的问题。你也可能发现在开发版中新添加的控件在构建后变为 Unknown control: ...问题,这同样可能是由上述的原因所致。

为了解决这个问题,请在项目的 pyproject.toml 中显式指定依赖到 Flet 的 Git 仓库:

1
2
[tool.flet.flutter.pubspec.dependency_overrides]
flet = { git = { url = "https://github.com/flet-dev/flet.git", ref = "main", path = "packages/flet" } }

官方文档说明见此

3. 使用高版本 Python 引入的新功能

尽管 Flet 在其 PyPI 页上标榜自身为可在 Python 3.10 及以上所有版本运行的包,但其在构建时却仅使用 Python 3.12 为应用的内置环境,因而导致由版本不同产生的各种兼容性问题,特别是当你使用了一些仅有高版本 Python 才有的写法的时候(例如 @warnings.deprecated()于 Python 3.13 引入)。这样的兼容性问题一时还难以被定位。

为了解决这个问题,要么去除对那些仅在 Python 更高版本才可用的功能的依赖,要么自行为新版 Python 构建提供支持(上游与此相关的计划遥遥无期)——但这个过程非常复杂,以至于完全可以单开一篇文章来讨论。CFMS 目前就通过这种方案得以使用 Python 的最新特性和改进。另一种未经测试的方法是采用 flet pack 进行规避,因为它似乎采用了不同的封装机制。

4. 意外地使用了更旧的 Flet 版本

出于未知的原因,Flet 在构建时依赖的工具之一,serious-python,在运行pip install时似乎不能分辨到底需要安装的是各依赖项的预发布版本还是正式版本,导致构建产生的应用中仍在使用旧版本(正式版)的 Flet,并引发与第三部分所述类似的莫名其妙的问题。一种做法是直接修改 serious-python 的实现,在 src\serious_python\bin\package_command.dart 中,将

1
2
3
4
5
6
7
8
9
10
await runPython([
'-m',
'pip',
'install',
'--upgrade',
...pipArgs,
'--target',
sitePackagesDir,
...requirements
], environment: pipEnv);

改为:

1
2
3
4
5
6
7
8
9
10
11
await runPython([
'-m',
'pip',
'install',
'--pre',
'--upgrade',
...pipArgs,
'--target',
sitePackagesDir,
...requirements
], environment: pipEnv);

然后按照与前述第二部分相同的方法在你项目的 pyproject.toml 中指定 dependency_overrides 即可。如果这样仍不奏效的话,也可以尝试修改 flet-build-template{{cookiecutter.out_dir}}/pubspec.yaml 下对 serious-python 依赖关系的定义。

评论