flutter项目通用模板
这份说明将为你展示该项目结构、所用工具以及运行环境、代码规范等,请认真阅读
默认生产环境 flutter run
测试环境 flutter run -t lib/main_test.dart
开发环境 flutter run -t lib/main_dev.dart
建议运行前配置国内镜像
/// 配置全局环境变量
export PUB_HOSTED_URL=https://pub.flutter-io.cn
export FLUTTER_STORAGE_BASE_URL=https://storage.flutter-io.cn
开发环境 ./build.sh dev
测试环境 ./build.sh test
生产环境 ./build.sh
生产环境构建 flutter build ios --release
测试环境构建 flutter build ios -t lib/main_test.dart --release
开发环境构建 flutter build ios -t lib/main_dev.dart --release
生产环境构建 flutter build apk --target-platform=android-arm64
测试环境构建 flutter build apk -t lib/main_test.dart --target-platform=android-arm64
开发环境构建 flutter build apk -t lib/main_dev.dart --target-platform=android-arm64
master
开发分支, CI自动打包为开发版
staging/*
稳定测试分支, CI自动打包为测试版, 发布给测试和内部人员试用
release/*
发布分支, CI自动打包为版发布版, 对外正式发布
|-- flutter
|-- .gitignore # Git ignore 配置(禁止随意篡改配置!!!)
|-- pubspec.yaml # 依赖配置和图片配置
|-- android # 安卓文件
| |-- ...
|-- build # 打包文件
| |-- ...
| |-- ios
| |-- ...
|-- ios # ios文件
| |-- ...
|-- lib
| |-- app.dart # App 全局页面
| |-- env.dart # App 环境变量配置
| |-- main.dart # 入口文件(默认生产环境)
| |-- main_dev.dart # 入口文件(开发环境)
| |-- main_test.dart # 入口文件(测试环境)
| |-- routes.dart # APP 页面路由配置
| |-- store.dart
| |-- actions # 全局actions
| | |-- actions.dart # 暴露导出文件
| | |-- base_actions.dart
| | |-- ...
| |-- models # 全局models
| |-- models.dart # 暴露导出文件
| | |-- app_state.dart
| | |-- ...
| | |-- bean # 服务端返回数据model
| | |-- task_model.dart
| | |-- task_model.g.dart
| | |-- ...
| |-- pages # 页面模块
| | |-- pages.dart # 全局页面导出文件
| | |-- home # 单个页面模块
| | | |-- home.dart
| | | |-- home_page.dart
| | | |-- actions
| | | | |-- actions.dart
| | | | |-- home_actions.dart
| | | | |-- ...
| | | |-- models
| | | | |-- home_state.dart
| | | | |-- models.dart
| | | | |-- ...
| | | |-- view_models
| | | | |-- home_view_model.dart
| | | | |-- ...
| | | |-- widgets
| | | |-- drop_menu.dart
| | | |-- ...
| |-- services # API请求服务
| | |-- ...
| |-- utils # 全局工具函数
| | |-- ...
| |-- widgets # 全局公共组件
| |-- checkbox.dart
| |-- picker
| |-- ...
|-- test
|-- widget_test.dart
Flutter
Dart
Redux
Async Redux
我们使用Dart作为编码标准,开始之前请阅读。
Widgets 目录只能放全局的公共组件并保证该文件夹没有冗余的代码和文件, 该目录后期可以独立为一个组件库, 不断迭代完善这个组件库, 方便后期扩展使用
|-- widgets # 全局组件目录
| |-- checkbox.dart
| |-- ...
| |-- picker
| |-- picker.dart
| |-- picker_body.dart
| |-- picker_dialog.dart
| |-- picker_header.dart
| |-- ...
Actions 目录只能放全局的公共的actions, 比如全局的Loading Action, Alert Action, Dialog Action等。该目录下包含一个BaseAction
抽象类, 其他所有的Actions都需要继承该BaseAction类, 方便在Actions中获取State数据. 我们的业务逻辑统统都可以放到Action当中的reduce函数中, 该函数可以是同步函数, 也可以是异步函数, 同时需要返回AppState
.
/// Actions目录结构
|-- actions # 全局组件目录
| |-- actions.dart
| |-- base_actions.dart # Base Actions
| |-- ...
/// BaseAction基本内容
import 'package:async_redux/async_redux.dart';
import 'package:flutter_common_template/models/models.dart';
import 'package:flutter_common_template/pages/login/models/models.dart';
abstract class BaseAction extends ReduxAction<AppState> {
LoginState get loginState => state.loginState;
MainState get mainState => state.mainState;
}
ShowToastAction继承BaseAction类示例:
import 'package:flutter_common_template/actions/actions.dart';
class ShowToastAction extends BaseAction {
String msg;
BuildContext context;
ShowToastAction(this.msg, this.context);
@override
AppState reduce() {
Toast.show(msg, context, gravity: 1, duration: 2);
return null;
}
}
具体详情可以👉Action Subclassing
Models 目录包含全局的AppState和CommonState, AppState是全局的基础数据状态, 包含用户信息, 登录信息等基础信息, CommonState是全局通用数据状态, 例如路点数据, 定位数据, 对话框状态等通用数据可以放该文件. Model基本结构如下
class MainState {
bool isLoading;
MainState({this.isLoading});
static MainState initialState() => MainState(isLoading: false);
MainState copy({ bool isLoading }) =>
MainState(isLoading: isLoading ?? this.isLoading);
}
所有的 Model 基本包含两个要素,一个initialState
初始化状态的方法, 一个修改状态的copy
方法, 当Action当中需要修改状态时, 可以借助该类下面的copy方法来修改状态, 以便重新渲染UI界面.具体详情可以👉State Declaration
View Model主要用来连接Action 和 State, 页面的数据绑定和页面按钮等事件触发均需通过View Model来连接, 模块与模块之间的职责需划分清楚, 所有的View Model均需继承 BaseModel(async_redux库中的基类), 以便可以访问dispatch
方法和全局的state
数据状态, ViewModel的成员变量均需带上@required
字符, 表明该成员必需存在.
View Model示例
import 'package:flutter_common_template/pages/login/actions/actions.dart';
class ViewModel extends BaseModel<AppState> {
ViewModel();
bool isLoading;
Function sendCode;
ViewModel.build({
@required this.isLoading,
@required this.sendCode,
}) : super(equals: [isLoading]);
@override
ViewModel fromStore() {
return new _ViewModel.build(
isLoading: state.mainState.isLoading,
sendCode: () => dispatch(SendCodeAction()),
);
}
}
TODO: 待完善...
- 不要把业务逻辑放
Widgets
中 - 不要把业务逻辑放
Connectors
中 - 不要把业务逻辑放
ViewModels
中 - 不要把业务逻辑放
Reducers
中 - 不要把业务逻辑放
ViewModels
中 - 不要把业务逻辑放
State
中
-
图片资源需要在
pubspec.yaml
中引入才可以使用flutter: assets: - images/cat.png - images/2x/cat.png - images/3x/cat.png
/// 页面中引入使用图片 new Image.asset('images/cat.png');
TODO: 待完善...
git-flow 是目前流传最广的 Git 分支管理实践。git-flow 围绕的核心概念是版本发布(release)
git-flow 流程中包含 5 类分支,分别是 master、develop、新功能分支(feature)、发布分支(release)和 hotfix
分支类型 | 命名规范 | 创建自 | 合并到 | 说明 |
---|---|---|---|---|
master | master | 开发主分支 | ||
feature | feature/* | master | master | 新功能 |
staging | staging/* | develop | release 和 master | 稳定测试版本发布 |
release | release/* | staging | develop 和 master | 新版本发布 |
hotfix | hotfix/* | staging 或 release | release 和 staging | staging 或 release 中 bug 修复分支 |
bugfix | bugfix/* | master | master | master 中 bug 修复分支 |
master
为开发分支, 是一个进行代码集成的分支, 该分支会及时合并最新代码, 新需求的开发都从此分支上创建feature/my-awesome-feature
为新功能分支, 开发新需求时, 需从master
分支创建hotfix/fix-my-bug
为热修复 bug 分支, 主要是针对release
或staging
分支测试出现的 bug 进行修复release/0.0.1
分支为部署到持续集成服务器上进行测试的分支, 是一个相对稳定的可供测试的分支staging
是部署到测试环境中的代码, 一般不允许随意合并其他分支到此分支上bugfix/fix-my-bug
为主分支修复 bug 分支, 主要是针对master
或feature
分支测试出现的 bug 进行修复
- 从
master
分支创建一个新的feature
分支, 如feature/my-awesome-feature
- 在该
feature
分支上进行开发相关需求,完成后提交代码并 push 到远端仓库 - 当代码完成之后,提
pull request
, 代码审核通过后合并到master
分支, 之后可删除当前feature
分支
- 从
master
分支创建一个新的bugfix
分支,如bugfix/fix-my-bug
- 进行相关的 bug 修复并在本地测试通过
- 当 bug 修复之后,提
pull request
, 合并bugfix/fix-my-bug
分支到master
分支
- 从
master
分支创建一个新的staging
分支,如staging/0.0.1
- 把
staging
分支部署到持续集成服务器上, 并交给相关测试人员进行测试 - 对于测试中发现的问题,直接在
staging
分支上创建hotfix/fix-my-bug
分支, 进行相关的 bug 修复 - 当 bug 修复之后,提
pull request
, 合并hotfix/fix-bug
分支到staging
分支, 再次部署并交给测试人员进行测试
- 从
master
分支创建一个新的staging
分支,如staging/0.0.1
- 把
staging
分支部署到持续集成服务器上, 并交给相关测试人员进行测试
- 从
staging
分支创建一个新的release
分支, 如release/0.0.1
- 把
release
分支推到远端, 部署到持续集成服务器上线
严格规范 commit message,编写 message 时需要加上 type 前缀或者直接运行 git cz 来按步骤提交 type 用于说明 commit 的类别,只允许使用下面 7 个标识
1. feat:新功能(feature)
2. fix:修补 bug
3. docs:文档(documentation)
4. style: 格式(不影响代码运行的变动)
5. refactor:重构(即不是新增功能,也不是修改 bug 的代码变动)
6. test:增加测试
7. chore:构建过程或辅助工具的变动
-
安装 git_hooks 库
-
设置环境变量
# Pub export PATH="$PATH":"$HOME/flutter/.pub-cache/bin" # Dart export PATH=$HOME/flutter/bin/cache/dart-sdk/bin:$PATH
-
本地激活git_hooks命令
pub global activate git_hooks
-
移动到项目根目录运行
git_hooks create
https://flutter.dev/docs/development/ios-project-migration
-
使用flutter upgrade 或flutter pub get等命令时,提示waiting for another flutter command to release the startup lock
先打开任务管理器,结束掉所有dart进程。然后打开你的flutter安装文件夹, 找到\bin\cache中的lockfile文件删除。之后重启VS Code。
-
国内使用flutter指南 https://flutter.dev/community/china
-
遇到如下错误
* What went wrong: A problem occurred evaluating project ':app'. > Could not resolve all artifacts for configuration 'classpath'. > Could not resolve com.android.tools.build:gradle:3.5.0. Required by: unspecified:unspecified:unspecified > Could not resolve com.android.tools.build:gradle:3.5.0. > Could not get resource 'https://dl.google.com/dl/android/maven2/com/android/tools/build/gradle/3.5.0/gradle-3.5.0.pom'. > Could not GET 'https://dl.google.com/dl/android/maven2/com/android/tools/build/gradle/3.5.0/gradle-3.5.0.pom'.
尝试在
${rootProject}/android/build.gradle
下修改buildscript { repositories { // google() // jcenter() maven { url 'https://maven.aliyun.com/repository/google' } maven { url 'https://maven.aliyun.com/repository/jcenter' } maven { url 'http://maven.aliyun.com/nexus/content/groups/public' } } dependencies { classpath 'com.android.tools.build:gradle:3.2.1' } } allprojects { repositories { // google() // jcenter() maven { url 'https://maven.aliyun.com/repository/google' } maven { url 'https://maven.aliyun.com/repository/jcenter' } maven { url 'http://maven.aliyun.com/nexus/content/groups/public' } } }
-
每次切换分支,最好flutter upgrade一下,不然可能出现打包问题。
-
打包失败, 考虑./gradlew clean一下
-
打包出现OOM, 此时可以在gradle.properties配置一下内存大小。
-
不能hot reload, 那一定是姿势不对, flutter工程下flutter attach之后, native工程这边需要重新打一个调试包装到手机上, 然后进入flutter模块才可以的
-
我的机器打的调试包怎么跑不起来, 出现了JNI native之类的一些错误提示, 这类问题, 优先考虑你的flutter版本和大家一致吗? channel和大家一致吗?
-
2x,3x图似乎加载不了, 那是因为你使用了中文, flutter会把资源反倒一个mainifest中,它是一个map, 如果使用中文, map的key就和路径对不上了, 找不到的话, 就会找默认图啦, 也就是一倍图
入门资源:
For help getting started with Flutter, view our online documentation, which offers tutorials, samples, guidance on mobile development, and a full API reference.