目录

常见问题与解答

目录

简介

本页面收集了关于 Flutter 一些大家常见问题的解答。你可能还会想要查看下面一些特别的答疑:

什么是 Flutter?

Flutter 是 Google 的便携式 UI 工具包,帮助你在移动、web、桌面端创造高质量的绝妙原生体验的应用。 Flutter 可以和世界上的开发人员和开发组织广泛使用的那些现存代码一起使用,并且是开源的、免费的。

哪些人会用到 Flutter?

对于用户来说,Flutter 将美妙的应用带到了生活中。

对于开发者来说,Flutter 降低了应用开发的入门门槛。它加速了应用开发的过程,减少了跨平台开发的成本以及复杂度。

对于设计师来说,Flutter 提供了一个能够实现高保真度用户体验的画布。 Fast 公司评价 Flutter 是 一个设计灵感的源泉,提供了将概念转换为生产代码的能力,却没有典型的框架强加的妥协。 Flutter 同时也是一个能提高生产力的原型工具,例如可拖入文件加载的 FlutterFlow 和基于 Web 的 IDE Zapp!

对于工程主管以及雇主来说,Flutter 可以将不同平台的应用开发者,统一为一个 移动端、前端和桌面端应用程序 的团队,共同建立品牌,并在单个代码库中打造的多个平台的应用程序。 Flutter 加速了跨平台下开发以及同步发布进程的开发进度。

我需要拥有怎样的开发经验才能使用 Flutter?

如果你熟悉面向对象概念 (类、方法、变量等) 和指令式编程概念 (循环、条件等) ,你会发现 Flutter 很容易上手。

就我们亲历过的例子来说,编程经验并不丰富的人们一样可以学习并使用 Flutter 进行原型设计和应用开发。

我可以用 Flutter 构建怎样的应用?

Flutter 设计为了让移动应用能够运行在 Android 与 iOS,以及在 web 和桌面端运行可交互式的应用。

如果你的应用强烈需要表达出品牌个性,Flutter 会非常适合。不过,即便你想要打造的应用看起来像是股票平台那样复杂,也可以使用 Flutter 来构建。

Flutter 的 软件包生态 支持绝大多数硬件(包括摄像头、GPS、网络以及储存)以及服务(例如支付、云储存、验证以及 广告)。

谁创造了 Flutter?

Flutter 是一个开源项目,由 Google 和开发社区共同创造。

谁在使用 Flutter?

Google 内部和外部的开发者使用 Flutter 为 Android 和 iOS 构建精美的原生应用。你可以访问 案例页面 来了解一些知名的开发者 / 组织。

Flutter 有哪些独到之处?

Flutter 与大多数用来构建移动应用的工具不同,因为它既不使用 WebView,也不使用设备附带的 OEM Widget,而是使用自己的高性能渲染引擎来绘制 Widget。

Flutter 与其它工具的不同之处还在于,它只有一层简洁的 C/C++ 代码,在这之上,Flutter 使用 Dart (一种现代化的、简洁的面向对象语言) 实现其大部分系统功能 (布局、手势、动画、框架、Widget 等),这种语言使得开发者可以轻松地进行阅读、更改、替换或删除。这些特性都为开发者提供了巨大的系统控制权限,同时显著降低了访问大多数系统功能的门槛。

我需要使用 Flutter 来构建我的下一个应用吗?

Flutter 1 于 2018 年 12 月推出, Flutter 2 于 2021 年 3 月 3 日发布, Flutter 3 于 2023 年 5 月 10 日发布。至今为止,成千上万使用了 Flutter 的应用已经被安装到了数亿台设备中。请通过成功 案例页面 了解知名开发者们的成果。

Flutter 进行了高质量的持续交付更新,优化了稳定性、性能以及一些常见的用户需求。

Flutter 能够为我们提供什么?

Flutter SDK 里有什么?

Flutter 包括了:

  • 针对移动应用深度优化的 2D 渲染引擎,具备出色的文字支持功能

  • 现代响应式风格框架

  • Material Design 风格及 iOS 风格丰富的 widget 组件

  • 用于单元测试和集成测试的 API

  • 原生平台交互性和插件 API 可以连接系统及第三方 SDK

  • Headless 测试运行器,用于在 Windows、Linux 和 Mac 上运行测试

  • 用于测试、调试和分析你的应用程序的 Flutter DevTools

  • 命令行工具,用于创建、开发、测试和编译你的应用程序

用 Flutter 开发时可以使用哪些编辑器或 IDE?

可以通过插件的方式使用 Android StudioIntelliJ IDEAVS Code 开发 Flutter 应用。请参阅 边界配置 以了解如何初始化,以及 Android Studio/IntelliJVS Code 如何使用 plugin 的小提示。

你也可以在命令行中使用 flutter 命令,并配合能编辑 Dart 语言的编辑器 进行开发。

Flutter 里存在开发框架吗?

是的,Flutter 自带了现代化的开发框架,灵感正是来自 React。 Flutter 的框架旨在实现分层、可定制 (以及灵活的开发选项)。开发者可以选择仅使用框架的一部分,或是使用另外的框架。

Flutter 里存在 Widget 吗?

是的,Flutter 自带了一套 高品质的 Material Design 和 Cupertino (iOS 风格) Widget、布局和主题。当然,这些 Widget 只是一个起点。 Flutter 的设计目的就是,让你轻松创建自己的 Widget,或是定制现有的 Widget。

Flutter 支持 Material Design 吗?

是的,Flutter 和 Material 团队密切合作,完全支持 Material Theming。你可以通过 widget 目录 了解支持 Material 2 和 3 的 widget。

Flutter 带有测试框架吗?

是的,Flutter 提供用于编写单元和集成测试的 API。了解更多有关 Flutter 测试的信息请查看 测试 Flutter 应用

我们使用自己的测试功能来测试我们的 SDK,每次提交代码前我们都会测量提交的 测试覆盖率

Flutter 是否附带调试工具?

Flutter 本身附带了 调试工具(也称为 Dart DevTools)。你可以在 调试 FlutterFlutter DevTools 文档中了解更多信息。

Flutter 是否带有依赖注入 (dependency injection) 的框架?

我们并没有提供相关解决方案,但是这里有许多包提供了依赖注入或服务定位的能力,例如 injectableget_itkiwiriverpod

技术篇

Flutter 是使用什么技术构建的?

Flutter 使用 C、C++、Dart、Skia (2D 渲染引擎) 以及 Impeller (iOS 默认的渲染引擎) 构建。你可以参阅下面这张 架构图 来理解其主要构建。若你需要了解 Flutter 的分层架构,请阅读 架构概览

Flutter 如何在 Android 上运行我的代码?

引擎的 C 和 C++ 代码使用 Android 的 NDK 编译。 Dart 代码 (SDK 的和你写的) 都是预先 (ahead-of-time, AOT) 编译成本地 ARM 及 x86 库。这些库被包含在一个 Android “runner” 项目中,然后整套内容被编译成一个 APK。当应用启动时,它会加载 Flutter 库。任何渲染、输入或事件处理等都会 delegate 给编译好的 Flutter 和应用代码。这个工作机制与很多游戏引擎颇为相似。

调试模式时,Flutter 使用虚拟机 (VM) 来运行 Dart 代码(因此这时会显示 “Debug” 字样,以提醒开发者速度会稍微变慢),这样便可以启用有状态热重载 (Stateful Hot Reload),它能够让你无需重新编译整个应用就能看到代码变更带来的变化。当运行该模式时,你可以看到一个 “debug” banner 在你应用的右上角。请记住,这时的性能并不是最终发布应用时的性能。

Flutter 如何在 iOS 上运行我的代码?{#run-ios}

引擎的 C 和 C++ 代码使用 LLVM 编译。Dart 代码 (SDK 的和你的) 都是预先 (ahead-of-time, AOT) 编译成本地 ARM 库。这些库被包含在一个 iOS “runner” 项目中,然后整套内容被编译成一个 .ipa。当应用启动时,它会加载 Flutter 库。任何渲染、输入或事件处理等都会代理给编译好的 Flutter 和应用代码。这个工作机制与很多游戏引擎颇为相似。

在 debug 模式下,Flutter 使用虚拟环境 (VM) 来运行代码,使其可以保持状态并且可以热重载,这个功能让你可以在无需重新编译的前提下立刻看到新代码生效的结果。在 debug 模式下,你会看到右上角有一个 “debug” 的横幅条,它会提醒你 debug 模式下的性能并不代表 release 模式的性能。

Flutter 是否会使用操作系统内置的 widget?

不会。相反,Flutter 自己提供了一套 widget (包括 Material Design 和 iOS 风格的 Cupertino widget),由 Flutter 的框架和引擎负责管理和渲染。你可以在这里浏览 Flutter widget 目录

我们希望最终能够产生出更高质量的应用。如果我们直接使用 OEM 自带的 widget,那么 Flutter 应用的质量和性能将受到这些 widget 质量的限制。

例如,在 Android 中,有一组硬编码的手势和固定的计算规则来区别它们。在 Flutter 中,你可以编写自己的手势识别器,它在 手势系统 中拥有最高的优先级。此外,由不同人创作的两个 widget 可以进行协调,以便消除手势的歧义。

如今的应用设计趋势表明,很多设计师和用户都需要动效丰富的 UI,同时富有品牌表现力。为了实现这种级别的美学定制化设计,Flutter 在架构上就会倾向于直接驱动像素,而不是交给 OEM widget 来处理。

由于使用相同的渲染器、框架和 widget,就意味着你能更加轻松地同时发布 iOS 和 Android 版本应用,而无需耗费精力和成本来规划和同步两套独立的代码库和功能集。

另外,使用单一的语言、单个框架和同一组适用于所有 UI 的库(无论你的 UI 在每个移动平台上都各有不同还是基本一致),也有助于帮助你降低应用开发和维护成本。

我的移动 OS 更新并加入新的 widget 时会怎么样?

Flutter 团队密切关注来自 iOS 和 Android 的 widget 使用和需求情况,且会与社区合作,对新的 widget 提供构建支持。这些支持可能会以这些形式来提供给开发者: 较低层级的框架功能、新的可编辑组合的 widget,或全新的 widget 实现。

Flutter 的分层架构旨在支持众多 widget 库,我们鼓励并支持社区构建和维护 widget 库。

我的移动 OS 更新并加入新的平台功能时会怎么样?

Flutter 的互操作 (interop) 和插件 (plugin) 系统旨在使开发者能够立即访问新的移动操作系统特性和功能。开发者不必等待 Flutter 团队提供新系统功能的访问接口,而是自己第一时间即可使用。

我能使用哪些操作系统开发 Flutter 应用?

Flutter 支持使用 Linux、Mac 和 Windows 进行开发。

Flutter 是用哪种语言写成的?

Dart 是一个现代化高度发展,并为终端应用专门优化的语言。底层图形框架和 Dart 虚拟机在 C/C++ 中实现。

Flutter 为什么选择使用 Dart?

在最初的开发阶段,Flutter 团队调研了很多开发语言和运行时,最终在框架和小部件中采用了 Dart。 Flutter 主要基于四个维度进行评估,并同时考虑了框架作者、开发人员和终端用户的需求。我们发现许多语言都满足了一些要求,但 Dart 在我们所有的评估维度上都获得了高分,并且满足了我们的所有要求和标准。

Dart 运行时和编译器支持 Flutter 的两个关键功能的组合:基于 JIT 的高效开发,允许在具有类型的语言中进行形参更改,以及保持状态的热重载;还有 AOT 编译器,可产出高效的 ARM 代码,为生产部署带来快速启动和可观的性能。

此外,我们还有幸与 Dart 社区展开了密切合作,Dart 社区积极投入资源改进 Dart,以便在 Flutter 中更易使用。例如,当我们采用 Dart 时,该语言还没有用于生成原生二进制文件的 AOT 工具链,这些工具有助于实现稳定的高性能表现,但在 Dart 团队为 Flutter 构建了这些工具后,这个缺失已经不复存在了。同样,Dart VM 之前是针对吞吐量进行的优化,但团队现在正在针对延迟进行优化,这对于解决 Flutter 的工作负载更为重要。

在评估时,Dart 在以下主要标准上得分很高:

开发人员生产力
Flutter 的主要价值之一,是通过让开发人员用同一套代码,创建适用于 iOS 和 Android 的应用而节省开发资源。使用高生产力的语言加速开发,并提升 Flutter 的吸引力。这对于我们的框架团队和开发人员都很重要。 Flutter 本身的大部分内容所用的语言都和我们提供给用户的一样,所以我们要让十万行代码保持生产力,而不会牺牲框架和部件对我们开发人员的可达性和可读性。

面向对象
对于 Flutter 而言,我们需要一种适合创建可视化用户体验的语言。这个领域中沉淀了数十年的面向对象构建 UI 框架的经验。虽然我们可以使用非面向对象语言,但这意味着,为了解决几个难题,我们要 “重新发明轮子”。此外,绝大多数开发者都拥有面向对象开发的经验,因此可以更轻松地学习如何使用 Flutter 进行开发。

稳定可期的高性能表现
我们希望开发者能够通过 Flutter 创建快速而流畅的用户体验。为了实现这一点,我们需要能够在每个动画帧期间运行大量的最终开发者代码。这意味着我们需要的语言一方面既要拥有高性能,另一方面又需要避免因周期性的中断而影响帧率,即 “可期性”。

快速内存分配
Flutter 框架使用的函数式流程,很大程度上依赖于下层的内存分配器高效地对小型的、短生命周期的内容进行内存分配。这个流程是使用支持这种分配机制的语言进行开发的,在缺少这个机制的语言中无法有效运作。

Flutter 可以运行任意的 Dart 代码吗?

Flutter 可以运行那些没有直接或间接导入了 dart:mirrorsdart:html 的库。

Flutter 引擎有多大?

2021 年 3 月,我们实测了一个 最简版本的 Flutter 应用 (即不含 Material 组件,只包含一个使用 flutter build apk --split-per-abi 构建的 Center widget 的 app)压缩且 Bundle 一个 release 的 APK, ARM64 下是 4.6 MB,ARM32 下是 4.3 MB。

在 ARM32 下,核心的引擎大约占 3.4 MB,框架和应用的代码大约是 765 KB,许可证文件大约是 58 KB,必要的 Java 代码(classes.dex)是 120 KB。上述数据均为经过压缩处理之后的大小。

在 ARM64 下,核心的引擎大约占 4.0 MB,框架和应用的代码大约是 659 KB,许可证文件大约是 58 KB,必要的 Java 代码(classes.dex)是 120 KB。上述数据均为经过压缩处理之后的大小。

这些数字是由 AndroidStudio 内置的 apkanalyzer 实测得出。

在 iOS 平台上,跟据 App Store Connect 的数据,同一应用的发布 IPA 在 iPhone X 上的下载文件体积为 10.9 MB。 IPA 比 APK 大,主要是因为 Apple 加密了 IPA 中的二进制文件,使得压缩效率降低。(可以查看 iOS App Store Specific ConsiderationsQA1795 关于加密的部分)

当然,你的实际情况可能跟我们所说的有所不同,我们建议你测量自己的应用的体积。想要测量应用体积,请查看 测量你的应用体积

How does Flutter define a pixel?

Flutter uses logical pixels, and often refers to them merely as “pixels”. Flutter’s devicePixelRatio expresses the ratio between physical pixels and logical CSS pixels.

赋能

Flutter 应用会拥有怎样的性能表现?

Flutter 应用会有很出色的性能。 Flutter 设计的目标就是帮助开发者轻松实现 60fps 的稳定帧率。 Flutter 应用通过本地编译的代码运行——不涉及解释过程。这也意味着 Flutter 应用启动会非常快捷。

开发 Flutter 时的操作周期有多长?修改代码和看到界面内容更新之间会隔多久?

Flutter 使用的是热重载式的开发操作周期。你在实机或者模拟器上都能实现亚秒级的修改和更新速度。

另外,Flutter 的热重载是有状态的 (stateful),这意味着重新加载后 app 的状态会被保留。这样即使你修改的界面在应用很深的位置,重载后你也能直接看到修改后的该界面,而无需从应用首页开始重新操作。

热重载 hot reload 相比较热重启 hot restart 的区别在哪里?

通过将更新的源代码文件注入到正在运行的 Dart VM(虚拟机)中来进行热重载。这不仅会添加新的类,还会向现有的类中添加方法和字段,并更改现有的函数。热重启后会将状态重置为应用程序的初始状态。

更多关于热重载的详细信息,请查看文档:使用热重载

我能把 Flutter 应用部署到哪里?

你可以将 Flutter 应用编译并部署到 iOS 和 Android 平台,亦可部署到 web 平台以及 桌面端

Flutter 可以运行在哪些设备,哪些操作系统版本上?

  • 我们会为各种从低端到高端的平台进行支持并且加入测试。你可以查看 已支持的平台 以了解已测试的平台列表。

  • Flutter 支持在 x86_64armeabi-v7aarm64-v8a 架构下构建为 ahead-of-time (AOT) 库。

  • 为 ARMv7 或 ARM64 构建的应用在很多 x86 Android 设备上运行良好 (使用 ARM 模拟器)。

  • 我们支持在不同的平台上开发 Flutter 应用,请参阅 不同操作系统下安装 Flutter 的方法文档 了解更多。

Flutter 能在 Web 上运行吗?

可以的,目前 stable channel 已经支持 web 平台了。你可以将已有的 Flutter 代码编译在 web 运行。更多详细信息,请参阅 Web 介绍

我能使用 Flutter 构建桌面应用吗?

可以,Flutter 的桌面端稳定版支持已经适用于 Windows、macOS 和 Linux 啦。

我能在我现有的原生应用里使用 Flutter 吗?

是的,你可以在我们网上内的 混合应用 章节中学习。

我能访问传感器、本地存储之类的平台服务和 API 吗?

可以。Flutter 默认即为开发者提供了操作系统中 一些 平台专属服务和 API 的操作入口。但是,我们希望避免大多数跨平台 API 的“最小公约数”问题,因此我们不打算为所有本地服务和 API 构建跨平台的操作 API。

很多平台服务和 API 都在 Pub 站点中提供了 现成的代码包,我们可以根据 说明 使用它们,非常方便。

最后,我们鼓励开发者使用 Flutter 的异步消息传递系统来创建出 自己的平台 与第三方 API 的整合方案。开发者可以根据需要公开尽可能多 (或者尽可能少) 的平台 API,并构建最适合其项目的抽象层。

我能对自带的 widget 进行扩展和定制吗?

当然可以。Flutter widget 系统的设计思路就是让开发者可以轻松定制。

Flutter 没有让每个 widget 都提供大量参数,而是采用了组合的方式。较大的 widget 是用较小的 widget 组合构建出来的,你可以重复使用它们,并以新颖的方式对其加以组合,从而生成自定义的 widget。例如,RaisedButton 没有继承自一个通用按钮 widget,而是将 Material widget 与 GestureDetector widget 组合在一起。 Material widget 负责视觉呈现,GestureDetector widget 则实现其交互。

如果你想要创建自定义设计的按钮,可以将负责视觉呈现的 widget 与提供交互的 GestureDetector 组合起来使用。例如,CupertinoButton 就采用了这种方法,将 GestureDetector 与其他几个负责表现视觉的 widget 进行组合。

这种组合策略使你可以最大限度地控制 widget 的可视化和交互逻辑,同时重复利用大量代码。在框架中,我们将复杂的 widget 分解为实现视觉、交互和动效的各部分。你可以按照自己喜欢的方式重新组合这些 widget,从而制作出自定义 widget 来完整传达出你的设计意图。

我为什么要在 iOS 和 Android 应用间共享布局代码?

你可以选择为 iOS 和 Android 应用实现不同的布局。开发者可以在运行时检查移动操作系统的种类,并根据操作系统呈现不同的布局,但我们发现这种做法比较少见。

我们发现移动应用布局和设计正在不断发展,更趋于品牌设计的诉求,而且跨平台之间的呈现逐渐趋同。这意味着不少开发者会有很强的动力在 iOS 和 Android 上共享布局和 UI 代码。

如今,在应用美学设计中,品牌表达和定制比严格遵循平台自己的美学更为重要。例如,应用设计通常需要自定义字体、颜色、形状、动效等,以便清楚地传达出其品牌独有的特性。

我们还发现,很多应用都在 iOS 和 Android 上采用了通用的布局模式。例如,你现在可以在 iOS 和 Android 上很方便地找到“底部导航”设计模式。移动平台上的设计理念似乎正在趋于一致。

我能与移动平台上的默认编程语言进行互操作吗?

可以,Flutter 支持调用 (包括集成) Android 上的 Java 或者 Kotlin 代码,或者 iOS 上的 ObjectiveC 或 Swift 代码。这是通过灵活的消息传递方式实现的, Flutter 应用可以使用 BasicMessageChannel 向移动平台收发消息。

如果你想了解有关平台通道的更多信息,可以查阅 platform channels 相关文档。

你也可以通过这个 示例项目,学习如何使用平台通道访问 iOS 和 Android 上的电池状态信息。

Flutter 包含反射 / 镜像系统吗?

不支持,Dart 的确是含有 dart:mirrors 库,能够提供类型反射。但是由于 Flutter 应用已经针对最终产物进行了预编译,并且控制二进制内容体积始终是现代移动应用需要面对的一个问题,所以我们禁用了 dart:mirrors。

使用静态类型分析系统,我们可以移除任何不会用到的东西(”得益于 tree shaking 机制”)。如果你导入了一个巨大的 Dart 库,但仅仅用到了一个其中实现的一个两行的函数,那么你只需要付出这两行函数的代价,即便是这个 Dart 库中导入了非常多非常多的库。此保证仅 Dart 可以在编译期安全识别代码路径的情况下。目前,我们已找到其他满足特定需求的方法以提供更好的平衡,如代码生成。

我应该如何在 Flutter 实现国际化 (internationalization, i18n)、本地化 (localization, l10n) 和可访问性 (accessibility, a11y) ?

关于国际化和本地化,请查看教程: Flutter 应用里的国际化

关于可访问性 / 无障碍使用,请查看文档:无障碍

我如何为 Flutter 开发并行 (parallel) 和/或并发 (concurrent) 应用?

Flutter 支持 isolate,一个个的 isolate 是 Flutter VM 里彼此独立的堆 (heap),可以并行运行 (通常以独立线程的形式实现)。 Isolate 之间通过异步收发消息来进行通信。

你可以点击链接查看 在 Flutter 中使用 isolate 的示例

我能在 Flutter 应用后台运行 Dart 代码吗?

可以,你可以在 iOS 和 Android 后台进程中运行 Dart 代码。有关更多信息,你可以查看在 Medium 上的文章: 使用 Flutter 插件和 Geofencing 在后台运行 Dart 代码

我在 Flutter 里能使用 JSON/XML/protobuffers 等内容吗?

当然可以。Pub 站点 提供了很多这样的代码库,包括 JSON, XML, protobufs 以及很多其他内容格式。

有关在 Flutter 中使用 JSON 的详细介绍,你可以查看 使用 JSON 的教程

我能用 Flutter 构建 3D (OpenGL) 应用吗?

我们暂不支持通过 OpenGL ES 或类似的机制实现 3D。在 3D API 方面我们有一个长期的计划,但目前我们专注于呈现 2D。

我的 APK 或 IPA 为什么这么大?

通常,图像、声音文件、字体等资源在 APK 或 IPA 里占据了相当的比重。 Android 和 iOS 生态系统中有很多工具可以帮助你了解 APK 或 IPA 中的各种内容的比重情况。

此外,请务必使用 Flutter 工具创建 APK 或 IPA 的_发布版本_。发布版本的体积通常_远_小于_调试_版本。

如果你想学习更多有关如何发布版本的教程,可以查看 打包和发布到 Android 平台 以及 打包和发布到 iOS 平台。同时,查看 测量你的应用体积

Flutter 应用能在 Chromebook 上运行吗?

我们注意到已经有 Flutter 应用运行在某些 Chromebook 上了。针对在 Chromebook 上运行 Flutter 的情况,我们有进行持续的跟踪,你可以查看 Flutter 运行在 Chromebook 上的问题追踪 来获得相关信息。

Flutter 是否提供 ABI 支持?

Flutter 和 Dart 尚未提供且目前不会提供应用二进制接口 (ABI) 的支持。

框架

为什么 build() 方法被放在 State 上,而不是 StatefulWidget 上?

将 Widget 的 build(BuildContext context) 方法放在 State 上,而不是将 Widget build(BuildContext context, State state) 方法放在 StatefulWidget 上,这个策略能让开发者在继承 StatefulWidget 时提供更多的灵活性,你可以在 API 文档中查看 关于 State.build 的讨论

Flutter 怎么没有标记语言 (markup language) 和语法?

Flutter 的 UI 由指令式的面向对象语言构建,也就是 Dart。它也是 Flutter 框架的编写语言。Flutter 本身并不包含声明式的标记语言。

我们发现将 UI 交给代码来动态构建会带来更多的灵活性。比如,我们发现固化的标记语言系统很难表达一个从视觉到行为都完全定制的 widget。

另外,“代码优先”的开发也使得热重载以及动态环境适配等特性能更好地得以实现。

从根本上来讲,创造出一种能动态转化成 widget 的语言是可能的,毕竟构建方法说到底也还是代码,他们能做的事情很多,自然也包括将标记语言转化成 widget。

我的应用运行时在右上角有一个 Debug 的标识,为什么?

默认情况下,flutter run 指令会使用 debug 编译配置。

Debug 编译配置会在一个 VM (Virtual Machine) 里运行你的 Dart 代码,从而提供更快速的开发操作周期,如 热重载。(如果是编译发布版本的话,则会使用 AndroidiOS 标准的工具链。)

Debug 编译配置也会检查所有的断言 (assert),这会帮助你在开发时更早地发现错误,但这也会加大运行时的开销。你看到的 Debug 标识是告诉你这些检查目前是打开的状态。你可以通过在运行 flutter run 时附加 --profile 或者 --release 来跳过这些检查。

如果你在使用 Flutter 的 IDE 插件,你就可以在 profile 或者 release 模式下启动应用,对于 VS Code 而言,你可以使用 Run > Start debugging 或者 Run > Run without debugging 菜单选项。对于 IntelliJ 而言,你可以使用 Run > Flutter run in Profile Mode 或者 Release Mode 菜单选项。

Flutter 框架采用了哪些编程范式?

Flutter 是一个多范式的编程环境。过去几十年中许多编程技术都有在 Flutter 中使用。我们在选择范式时会考虑其适用性进行综合性的决策。以下列出的范式不分先后:

组合 (composition)
这也是 Flutter 的主要开发范式,将简单的、行为有限的小对象进行组合,从而实现更复杂的效果。绝大多数 Flutter widget 都是用这种方法构建的。比如 Material TextButton 类是基于 IconThemeInkWellPaddingCenterMaterialAnimatedDefaultTextStyle 以及 ConstrainedBox 组合而成的。而 InkWell 则是由 GestureDetector 组成, Material 则是由 AnimatedDefaultTextStyleNotificationListenerAnimatedPhysicalModel 组成。如此等等。

函数式编程 (functional programming)
整个应用都可以只用 StatelessWidget 来构建,它本质上就是一些方法,用来描述如何将参数传送给其他方法,以及在布局区域内计算布局以及绘制图像。当然这样的应用一般也不会包含状态,所以通常也无法进行交互。比如,Icon widget 就只是一个将其元素(颜色图标尺寸)罗列在布局区域内的方法。另外,当这个范式被重度使用时,则会使用不可变的数据结构,如整个 Widget 类及其派生,以及一些辅助类,如 RectTextStyle。另外,从一个较小的尺度来看的话, Dart 的 Iterable API 也重度使用了这个范式 (如 map, reduce, where 等方法),它在框架中经常被用来处理一系列的值。

事件驱动编程 (event-driven programming)
用户的交互操作被包装成事件对象,这些对象发送给被各个 event handler 注册的回调方法。屏幕内容的更新使用的也是类似的回调机制。比如,做为动画系统构建基础的 Listenable 类,就采用了包含多个事件监听者的订阅模型。

面向类编程 (class-based programming,是面向对象编程的一种方式)
框架内绝大多数的 API 是由包含各种继承关系的类来组成的。我们在基本类中定义较高级别的 API,然后在其子类中对这些 API 进行特化处理。比如,我们的渲染对象就有一个基本类 RenderObject),它对坐标系的细节并不关心,但它的子类 RenderBox) 就引入了笛卡尔坐标系的概念(x/y坐标值,以及宽度高度的概念)。

原型编程 (prototype-based programming,同样是面向对象编程的一种方式)
ScrollPhysics 类在运行时动态链接那些会组成滚动逻辑的实例。这就使得系统无需在编译时提前选择平台的情况下,也能组合出符合平台特性的页面滚动效果。

指令式编程 (imperative programming)
简单直白的指令式编程,通常和对象内封装的状态 (state) 搭配使用,这种范式能提供最符合直觉的解法。比如,测试就是使用指令式编程实现的,首先描述出测试的环境,然后给出测试需要满足的定量,最后开始步进,或者根据测试需要插入事件。

响应式编程 (reactive programming)
Widget 和元素树有时候被描述为响应式的,因为随 widget 构造方法引入的新输入会随着其 build 方法传播给更低等级的 widget;而底层 widget 中出现的修改 (如响应用户的输入) 也会沿着结构树通过 event handler 向上传播。在整个框架中,函数-响应式以及指令-响应式的实现都有出现,具体取决于 widget 的功能需求。 Widget 的 build 方法如果只是包含其针对变化如何响应的表达式的话,就是函数-响应式 widget (如 Material Divider 类)。如果 widget 的 build 方法包含一系列构造子元素的表达式,用于描述该 widget 如何响应变化的话,那它就是指令响应式 widget (如 Chip 类)。

声明式编程 (declarative programming)
Widget 的 build 方法通常都是一个单一表达式,它包含多级嵌套的构造函数,且使用 Dart 严格的声明式子集编写。这些嵌套的表达式可以与合适的标记语言互相转换。比如,UserAccountsDrawerHeader 这个 widget 就有一个很长的 build 方法 (20 多行),由一个嵌套的表达式构成。这种范式也可以和指令式混合使用,以实现某些很难用纯声明式的方法实现的 UI。

泛型程序设计 (generic programming)
类型可以帮助开发者更早地抓到错误,基于这一点,Flutter 框架也采用了泛型开发。比如,State 类就是如此,其关联的 widget 就是类型参数,如此一来 Dart 分析器就能捕获到 state 和 widget 不匹配的情况。类似的,GlobalKey 类就接受一个类型参数,从而类型安全地访问一个 widget 的 state (会使用运行时检查)。 Route 接口也在被 popped 时接受类型参数,另外 List, Map, Set 这些集合也都如此,这样就可以在分析或者运行时尽早发现类型不匹配的错误。

并发 (concurrent programming)
Flutter 大量使用诸如 Future 等异步 API。比如,动画系统就会在动画执行完 future 时进行事件告知。同样的,图片加载系统也会使用 future 在加载完毕时进行告知。

约束编程 (constraint programming)
Flutter 的布局系统使用了约束编程的简化形态来描述一个场景的几何性质。约束值 (比如一个笛卡尔矩形允许的最大 / 最小宽高值) 会从父元素传递给子元素,子元素最终选择一个能满足上面所有约束条件的最终尺寸。这种做法也使得 Flutter 能不依赖太多输入的情况下快速完成一个全新的布局。

工程管理

我该如何获得技术支持?

If you think you’ve encountered a bug, file it in our issue tracker. You might also use Stack Overflow for “HOWTO” type questions. For discussions, join our mailing list at cfug-dev@googlegroups.com or seek us out on Discord.

如果你觉得遇到 bug 了,请提交至我们的 问题追踪入口。我们也鼓励你在 Stack Overflow 中多多使用 “如何 (how to) …“来搜索解答。如果你希望直接与我们沟通,请使用我们的官方邮件地址 cfug-dev@googlegroups.com 或在 Discord 上向我们提问。

我如何投入到 Flutter 开发社区?

Flutter 是开源的,我们鼓励你为此做出自己的贡献。你可以通过 问题追踪入口 来提交功能需求或者 bug 报告。

我们也希望你加入我们的邮件讨论 cfug-dev@googlegroups.com,告诉我们你是如何使用 Flutter 的,以及打算用 Flutter 开发什么。

如果你打算为 Flutter 贡献代码,请先阅读 代码贡献指南,然后从 简单待修复问题 列表中寻找力所能及的问题开始入手。

最后,你可以与各个 Flutter 社区保持联系,更多相关信息,请查阅我们的 社区 页面。

Flutter 是开源的吗?

是的,Flutter 是开源的。你可以在 GitHub 上获取到它。

Flutter 以及其依存项目使用的是哪种软件许可协议?

Flutter 包含两个部分:一个使用动态链接二进制文件发行的引擎,以及引擎加载的 Dart 框架二进制文件。引擎使用了很多软件组件,且包含许多依存内容。完整的说明和依存清单请查看引擎的 许可协议

框架部分则自成一体,且 只有一份简单的许可协议

另外,你使用的其他 Dart 代码包可能有其独有的许可协议。

我如何确定我的 Flutter 应用该显示哪些许可协议?

你可以使用 API 来确定需要显示的许可协议。

目前有哪些人在开发 Flutter?

我们都在参与 Flutter 开发!我们都知道 Flutter 是一个开源项目。目前 Flutter 中的大部分都是由 Google 的工程师来开发。如果你喜欢 Flutter 的话,我们希望你加入开发者社区并 做出贡献

Flutter 有哪些指导原则?

我们相信:

  • 为了触达每一位潜在用户,开发者需要针对多个移动平台发布自己的应用。

  • 目前常用的 HTML 和 WebView 由于一些默认的交互响应(滚动、布局等)以及向后兼容等问题,很难获得稳定的高帧率和精确的设计体验。

  • 目前,开发同一个应用的不同平台版本成本很高:这意味着不同的团队、不同的代码库、不同的工作流程以及不同的工具,等等。

  • 开发者需要一个简单的、更好的方法来使用同一套代码库开发应用的不同平台版本。而且他们不希望在质量、细节和功能控制以及性能上有任何妥协。

我们目前集中于以下三件事:

功能控制
开发者应该能访问到系统所有层级的功能,且能获得全面的控制权。这也意味着:

性能表现
用户应该获得流畅、响应迅捷且没有卡顿的应用。这也意味着:

精确实现
每一个人都应该获得精确、优美且富有表现力的移动应用体验。

Apple 会拒绝我的 Flutter 应用吗?

我们无法代 Apple 发言,但已经有很多使用类似 Flutter 的其他技术开发的应用。实际上,Flutter 与 Unity 使用了近乎一致的底层架构模型, Apple store 中最著名的游戏也是使用它的引擎开发的。

Apple 最近评选的最佳设计应用也是使用 Flutter 开发的,其中包括 HamiltonReflectly

任何提交到 Apple store 的 Flutter 应用都应该遵守 Apple 的 规范