英文地址:Separating build environments in Flutter apps
在开发专业的移动应用程度的时候,我们至少需要两个不同的环境:开发环境和生产环境,通过这种方式, 我们可以在开发环境中进行开发及测试新的特性,而不会意外地破坏用户生产环境的任何东西。
样本代码地址:separating_build_environments
最初的应用程序
lib/main.dart是flutter在新建一个项目的时候,为我们生成默认程序的入口文件,生成的模版代码如下:
1 | import 'package:flutter/material.dart'; |
lib/my_home_page.dart:
1 | import 'package:flutter/material.dart'; |
该my_home_page.dart
文件是对默认地模版代码文件稍微做了一些修改。
将应用程序分为两个环境
我们当前的应用配置仅是生产环境的,没有方法为生产环境提供环境配置,让我们做些修改,使我们拥有两套不同的环境:development
和producation
。
这里我们有几个地方想要根据当前的环境来拥有不同的行为:
- 标题栏,生产环境标题是
Build flavors DEV
,开发环境是Build flavors
。 - 第一个文本控件,开发环境显示文本是
This is the development app
,生产环境是the production app
。 - 第二个文本控件,开发环境显示文本:
Backend API url is https://dev-api.example.com/
,生产环境是Backend API url is https://api.example.com/
我们需要创建一个用于包含所有特定于环境的配置信息的配置类,这是有意义的。
创建配置对象
新建app_config.dart
文件,该文件将包含我们所有环境依赖的信息。
在我们这个例子中,将得到这样的结果,如下:
1 | import 'package:meta/meta.dart'; |
你可能正在询问该如何为我们的app提供这些配置信息?你们中的一些人可能早已知晓答案。InheritedWidget使从任务地方获取配置对象变得异常简单。
将AppConfig对象转变为Inherited Widget
为了能够使我们的AppConfig
类能够成为Inherited Widget
,我们将扩展InheritedWidget
类,提供一个静态的of
方法来获取该实例,最后重写updateShouldNotify
方法。
1 | import 'package:flutter/material.dart'; |
这里有几点需要注意:
- 这个
child
参数将会是我们整个MaterialApp
实例,我们将包裹我们整个应用在AppConfig
对象中。 - 我们创建了一个
of
静态方法,这个是InheritedWidget
的一般约定,这个方法允许我们无论在哪需要,通过调用AppConfig.of(context)
来获取特定环境的配置。 - 在
updateShouldNotify
方法中,我只返回false
。这个是因为AppConfig
在我们创建之后将会不会变化。
接下,让我们为我们的两个环境创建这些文件。
为不同的环境创建启动文件
我们将会为每个环境创建所谓的启动文件,在我们这个例子中,我们仅有两个环境development
和producation
,这样 我将会新建两个文件main_dev.dart
和main_prod.dart
。
在每个文件中,我将会用正确的配置数据来创建一个AppConfig
类的实例,我们将传入MyApp
新的实例到AppConfig
控件中,这样我们应用中任何控件能够轻松地获取到这个配置的实例,然后调用runApp
,这个我们整个应用程序的入口点。
lib/main_dev.dart:
1 | import 'package:build_flavors/app_config.dart'; |
lib/main_prod.dart:
1 | import 'package:build_flavors/app_config.dart'; |
生产和开发环境的启动文件不同的仅是配置选项的值不同。
lib/main.dart:
1 | import 'package:build_flavors/app_config.dart'; |
在这里,我们仅仅是获取应用的配置实例,并根据当前的环境正确地设置我们的MaterialApp
的标题,移除main
,因为在对应的启动文件已经包括这个入口函数。
因为我们的整个应用被包裹在了AppConfig
控件中(扩展了InheritedWidget
),通过调用AppConfig.of(context)
就可以从任何地方来获取这个配置信息,这个在控件树更深地节点也是能有效的。
lib/my_home_page.dart:
1 | import 'package:build_flavors/app_config.dart'; |
在不同的环境中运行应用程序
我们可以flutter run
命令配合--target
或-t
(缩写)参数来指定。
在我们这个例子中:
- 运行开发环境的构建,调用
flutter run -t lib/main_dev.dart
- 运行生产环境的构建,调用
flutter run -t lib/main_prod.dart
为了创建基于Andriod的发布构建,我可以运行flutter build apk -t lib/main_<environment>.dart
,并将根据我们环境得到正确的apk,若是iOS上的发布构建,只需将apk
替换成ios
。