常见问题与解答

简介

什么是 Flutter?

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

Flutter 是干什么的?

对于用户来说,Flutter 让漂亮的应用 UI 变得生动有趣。

对于开发者来说,Flutter 降低了创建移动应用的门槛。它加速了移动应用的开发,降低了兼顾 Android 和 iOS 应用开发的成本和复杂性。

对于设计师而言,Flutter 可以确保精确地实现设计意图,而无需降低保真度或被迫进行妥协。在设计师的手里,Flutter 还可以作为一种高效的原型设计工具。

哪些人会用到 Flutter?

Flutter 适用于希望快速构建精美的移动应用,或者希望用一套代码库覆盖更多用户的开发者。

Flutter 也适用于需要领导移动开发团队的开发管理人员。Flutter 可以让开发管理人员打造一个统一的移动应用开发团队,以便更快地开发更多功能,同时将相同的功能部署到 Android 和 iOS 版本的应用中,并降低维护成本。

虽然设计师群体不是 Flutter 最初的目标受众,但 Flutter 也适用于那些希望将原始设计意图高保真地传递给所有移动用户的设计师。

说到底,如果您想要漂亮的应用,令人愉悦的动效和动画,以及富有个性和身份感的 UI,那您就是 Flutter 的目标用户。

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

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

不过需要强调的是,学习和使用 Flutter 无需具备移动领域的开发经验。

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

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

Flutter 针对在 Android 和 iOS 上运行的 2D 移动应用进行了优化。

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

Flutter 可以构建功能齐全的应用,包括使用摄像头、地理位置、网络、存储、第三方 SDK 等。

谁创造了 Flutter?

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

谁在使用 Flutter?

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

Flutter 有哪些独到之处?

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

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

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

Flutter 1.0 已于 2018 年 12 月推出。成千上万使用了 Flutter 的应用已经被安装到了数亿台设备中。请通过成功 案例页面 了解知名开发者们的成果。

更多有关启动和后续版本的信息,你可以查看 Flutter 1.0: Google’s Portable UIToolkit

Flutter 能够为我们提供什么?

Flutter SDK 里有什么?

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

  • 现代化的 react 风格框架

  • 适用于 Android 和 iOS 的丰富 Widget

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

  • 用于连接系统和第三方 SDK 的互操作及插件 API

  • 无界面 (headless) 测试运行器,用于在 Windows、Linux 和 Mac 上运行测试

  • 命令行工具,用于创建、构建、测试和编译应用

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

可以通过插件的方式使用Android StudioIntelliJ IDEAVS Code 开发 Flutter 应用。

有关设置的详细信息,请参阅 编辑器配置文档,以及使用 Android Studio/IntelliJVS Code 插件的小提示。

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

Flutter 里存在开发框架吗?

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

Flutter 里存在 Widget 吗?

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

Flutter 支持 Material 主题定制 (Theming) 吗?

是的,Flutter 和 Material 团队密切合作,完全支持 Material Theming。你可以通过 codelab 了解 Material 组件 (MDC) 主题定制:MDC-103 Flutter: Material Theming

Flutter 带有测试框架吗?

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

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

Flutter 是否带有依赖注入 (dependency injection) 的框架或解决方案?

现在还没有。如果您有这方面的建议,请通过flutter-dev@googlegroups.com 邮箱与我们联系。

技术篇

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

Flutter 使用 C、C++、Dart 和 Skia (2D 渲染引擎) 构建。您可以参阅下面这张 架构图

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

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

调试模式时则使用虚拟机 (VM) 来运行 Dart 代码(因此这时会显示 “Debug” 字样,以提醒开发者速度会稍微变慢),这样便可以启用有状态热重载 (Stateful Hot Reload)。

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

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

调试模式时则使用虚拟机 (VM) 来运行 Dart 代码 (因此这时会显示 “Debug” 字样,以提醒开发者速度会稍微变慢),这样便可以启用有状态热重载 (Stateful Hot Reload)。

Flutter 是否会使用系统的 OEM widget?

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

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

In Android, for example, there’s a hard-coded set of gestures and fixed

例如,在 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 来编写框架和 widget。底层图形框架和 Dart 虚拟机在 C/C++ 中实现。

Flutter 为什么选择使用 Dart?

Flutter 使用四个主要维度进行评估,并综合考虑了框架开发者、应用开发者和最终用户的需求。我们发现某些语言的确在某些维度符合要求,但 Dart 在所有评估维度上都取得了高分,并且符合我们的所有要求和标准。

Dart 的运行时和编译器支持 Flutter 的两个关键特性: 基于 JIT 的快速开发周期,允许在带类型的语言中支持形变和有状态热重载,以及一个能产出高效率 ARM 代码的 AOT 编译器,从而确保快速启动的能力和可预期的生产版本运行性能。

此外,我们还有幸与 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:mirrors 或 dart:html (不论是直接还是间接引用) 的 Dart 代码。

Flutter 引擎有多大?

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

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

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

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

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

从 Flutter SDK 1.12 开始,release 模式下引擎二进制产物将包含 LLVM 的中间语言表示(bitcode)。Xcode 将使用 bitcode 为 App Store 生成最终包含了最新的编译器优化和功能的二进制文件。Profile 和 Debug 模式下的 Framework 中,bitcode 部分仅包含 bitcode marker,因此更能代表引擎的真实大小。无论你是否使用 bitcode,release 模式下增加的包大小都会在应用归档后并发布到应用商店后,在构建的最终步骤里被移除。

当然,您的实际情况可能跟我们所说的有所不同,我们建议您测量自己的应用的体积。想要测量 Android 应用体积,请运行 flutter build apk,(使用 1.7.8+hotfix.3 之后版本的 Flutter,请加入 —split-per-abi 参数)并将 APK (build/app/outputs/apk/release/app-release.apk) 加载到 Android Studio 中,以便获取详细的体积报告。想要测量 iOS 应用,请将发布 IPA 加载到 App Store Connect 并获取体积报告。你可以查看使用 Android Studio 加载 APK的相关说明,以及使用 App Store Connect 加载 IPA 的相关说明。

赋能

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

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

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

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

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

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

热重载是通过将更改过的源代码文件注入到正在运行的 Dart VM 中来实现的。这不仅包括添加新的类,还包括在既存的类里添加方法和字段,以及修改既有的方法。不过有少数代码修改是无法被热重载的:

  • 全局变量的初始化程序

  • 静态字段的初始化程序

  • 应用的 main() 方法

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

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

您可以将 Flutter 应用编译并部署到 iOS 和 Android 平台上。

如何吸引更多用户?

应用广告宣传将为你在合适的时机精准发掘目标用户。

  • 在谷歌搜索、商店、YouTube、Gmail 以及谷歌展示网络中推广你的应用以吸引更多用户。

  • 通过为效果最好的广告分配更多预算优化你的出价。您需要为其设置应用安装出价,也就是“目标每次安装费用”,同时设置每日推广支出预算(CPI),剩下的工作交给 Google 处理即可。

  • 从应用商店列表中获得即时广告预览,仅需10分钟即可完成设置。下面你可以设置自定义文本内容与投放区域。

获取 75 美元的赠金(当你消费 25 美金后)

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

移动操作系统:Android Jelly Bean, v16, 4.1.x 或更新版本,以及 iOS 8 或更高版本。

移动硬件:iOS 设备(iPhone 4S 或更新版本)和 ARM Android 设备。

请注意,Flutter 目前不支持直接为 x86 Android 进行构建(参考 issue #9253),但是针对 ARMv7 或 ARM64 构建的应用都在很多 x86 Android 设备上表现良好 (通过模拟 ARM 来实现)。

我们支持使用 Android 和 iOS 设备以及这两种 OS 的模拟器来开发 Flutter 应用。

我们会在各种从低端到高端的手机上进行测试,但我们还没有正式保证设备兼容性。

我们认为,Flutter 会在平板电脑上运行良好。我们目前没有覆盖到全部的 Material Design 平板电脑适配规则,但我们正计划在这个领域进一步加大投入。

Flutter 能在 Web 上运行吗?

Flutter web 目前处于 技术预览状态。你可以打包现有 Flutter 代码运行在预览版 web 上,但由于我们仍旧是预览版,所以会有一些警告。你可以在 web instructions 查看更多详细信息。

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

可以,但目前支持得并不完美。我们正在致力于为桌面应用打造最佳体验。这方面的进展在 我们的 wiki 上可以了解到。

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

可以,你可以在 Android 或 iOS 应用中嵌入一个全屏的 Flutter 实例。

请参考 这个文档,查看如何将 Flutter 加入现有的项目。

目前的两个演示项目是 platform_viewflutter_view。我们的 wiki 页面中也提供了一些初始文档:[将 Flutter 添加至现有应用][Add Flutter to existing apps]。

我能访问传感器、本地存储之类的平台服务和 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 包含反射 / 镜像系统吗?

现在暂时还不行。由于 Flutter 应用已经针对最终产物进行了预编译,并且控制二进制内容体积始终是现代移动应用需要面对的一个问题,所以我们禁用了 dart:mirrors。我们很想知道您需要反射 / 镜像系统的目的—请通过如下地址反馈给我们您的想法:flutter-dev@googlegroups.com

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

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

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

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

Flutter 支持 isolate。一个个的 isolate 是 Flutter VM 里彼此独立的堆 (heap),可以并行运行 (通常以独立线程的形式实现)。Isolate 之间通过异步收发消息来进行通信。Flutter 目前还没有共享内存的并行机制,不过我们正在评估这方面的解决方案。

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

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

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

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

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

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

我能用 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 上的问题追踪 来获得相关信息。

框架

为什么 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 的 IntelliJ 插件,您可以在 profile 或者 release 模式下启动应用,只需要在菜单里选择 Run > Flutter run in Profile Mode 或者 Release Mode 即可。

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

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

  • Composition
  • The primary paradigm used by Flutter is that of usingsmall objects with narrow scopes of behavior, composed together toobtain more complicated effects. Most widgets in the Flutter widgetlibrary are built in this way. For example, the Material[FlatButton][]class is built using a[MaterialButton][]class, which itself is built usingan [IconTheme][],an [InkWell][],a [Padding][],a [Center][],a [Material][],an [AnimatedDefaultTextStyle][],and a [ConstrainedBox][].The [InkWell][]is built using a [GestureDetector][].The [Material][]is built using an [AnimatedDefaultTextStyle][],a [NotificationListener][],and an [AnimatedPhysicalModel][].And so on. It’s widgets all the way down.

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

  • Functional programming
  • Entire applications can be built with only[StatelessWidget][]s,which are essentially functions that describe how arguments map to otherfunctions, bottoming out in primitives that compute layouts or paint graphics.(Such applications can’t easily have state, so are typically non-interactive.)For example, the [Icon][]widget is essentially a function that maps its arguments([color][],[icon][],[size][]) into layoutprimitives. Additionally, heavy use is made of immutable data structures,including the entire[Widget][] classhierarchy as well as numerous supporting classes such as[Rect][] and[TextStyle][]. On asmaller scale, Dart’s[Iterable][] API,which makes heavy use of the functional style (map, reduce, where, etc), isfrequently used to process lists of values in the framework.

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

  • Event-driven programming
  • User interactions are represented by event objectsthat are dispatched to callbacks registered with event handlers. Screen updatesare triggered by a similar callback mechanism. The[Listenable][]class, which is used as the basis of the animation system, formalizes asubscription model for events with multiple listeners.

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

  • Class-based object-oriented programming
  • Most of the APIs of the frameworkare built using classes with inheritance. We use an approach whereby we definevery high-level APIs in our base classes, then specialize them iteratively insubclasses. For example, our render objects have a base class([RenderObject][])that is agnostic regarding the coordinate system, and then we have a subclass([RenderBox][])that introduces the opinion that the geometry should be based on the Cartesiancoordinate system (x/width and y/height).

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

  • Prototype-based object-oriented programming
  • The[ScrollPhysics][]class chains instances to compose the physics that apply to scrollingdynamically at runtime. This lets the system compose, for example, pagingphysics with platform-specific physics, without the platform having to beselected at compile time.

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

  • Imperative programming
  • Straightforward imperative programming, usuallypaired with state encapsulated within an object, is used where it provides themost intuitive solution. For example, tests are written in an imperative style,first describing the situation under test, then listing the invariants that thetest must match, then advancing the clock or inserting events as necessary forthe test.

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

  • Reactive programming
  • The widget and element trees are sometimes described asreactive, because new inputs provided in a widget’s constructor are immediatelypropagated as changes to lower-level widgets by the widget’s build method, andchanges made in the lower widgets (e.g., in response to user input) propagateback up the tree via event handlers. Aspects of both functional-reactive andimperative-reactive are present in the framework, depending on the needs of thewidgets. Widgets with build methods that consist of just an expressiondescribing how the widget reacts to changes in its configuration are functionalreactive widgets (e.g., the Material[Divider][] class).Widgets whose build methods construct a list of children over severalstatements, describing how the widget reacts to changes in its configuration,are imperative reactive widgets (e.g., the[Chip][] class).

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

  • Declarative programming
  • The build methods of widgets are often a singleexpression with multiple levels of nested constructors, written using a strictlydeclarative subset of Dart. Such nested expressions could be mechanicallytransformed to or from any suitably expressive markup language. For example,the[UserAccountsDrawerHeader][]widget has a long build method (20+ lines), consisting of a single nestedexpression. This can also be combined with the imperative style to build UIsthat would be harder to describe in a pure-declarative approach.

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

  • Generic programming
  • Types can be used to help developers catch programmingerrors early. The Flutter framework uses generic programming to help in thisregard. For example, the[State][] class isparameterized in terms of the type of its associated widget, so that the Dartanalyzer can catch mismatches of states and widgets. Similarly, the[GlobalKey][] classtakes a type parameter so that it can access a remote widget’s state in atype-safe manner (using runtime checking), the[Route][] interface isparameterized with the type that it is expected to use whenpopped, andcollections such as[List][]s,[Map][]s, and[Set][]s are allparameterized so that mismatched elements can be caught early either duringanalysis or at runtime during debugging.

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

  • Concurrent programming
  • Flutter makes heavy use of[Future][]s andother asynchronous APIs. For example, the animation system reports when ananimation is finished by completing a future. The image loading system similarlyuses futures to report when a load is complete.

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

  • Constraint programming
  • The layout system in Flutter uses a weak form ofconstraint programming to determine the geometry of a scene. Constraints (e.g.,for cartesian boxes, a minimum and maximum width and a minimum and maximumheight) are passed from parent to child, and the child selects a resultinggeometry (e.g., for cartesian boxes, a size, specifically a width and a height)that fulfills those constraints. By using this technique, Flutter can usuallylay out an entire scene with a single pass.约束编程 (constraint programming):Flutter 的布局系统使用了约束编程的简化形态来描述一个场景的几何性质。约束值 (比如一个笛卡尔矩形允许的最大 / 最小宽高值) 会从父元素传递给子元素,子元素最终选择一个能满足上面所有约束条件的最终尺寸。这种做法也使得 Flutter 能不依赖太多输入的情况下快速完成一个全新的布局。

工程管理

我该如何获得技术支持?

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

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

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

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

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

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

Flutter 是开源的吗?

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

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

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

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

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

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

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

  • 如果您的应用使用了 [Drawer][],则添加一个 [AboutListTile][]。

  • 如果您的应用不包含 Drawer 但使用了 Material 组件库,请调用 [showAboutDialog][] 或者 [showLicensePage][]。

  • 对于更加定制的场合,您可以使用 [LicenseRegistry][] 获得原始的许可内容。

目前有哪些人在开发 Flutter?

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

Flutter 有哪些指导原则?

我们相信:

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

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

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

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

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

  • Control
  • Developers deserve access to, and control over, all layers of thesystem. Which leads to:

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

  • Performance
  • Users deserve perfectly fluid, responsive,jank-free apps. Which leads to:

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

  • Fidelity
  • Everyone deserves precise, beautiful,delightful mobile app experiences.

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

Apple 会拒绝我的 Flutter 应用吗?

我们无法代 Apple 发言,不过 Apple 的政策在过去几年有过不少变化,如今 App Store 里也有很多使用其他技术开发的应用,包括 Unity 和 Flutter。使用 Flutter 开发的应用还被 Apple 推荐过,例如 Hamilton.

当然,Apple 是其生态的最终管理者,但我们会尽我们所能来确保使用 Flutter 开发的应用不会被 Apple 拒绝。