Flutter学习记录——2.Flutter项目架构
  Xa7AsmJIfSXT 2023年11月02日 105 0


文章目录


对于一门新语言或新技术的学习来说,在新建了项目之后,了解其项目结构及含义、配置文件的编写,这些对后续的开发和深入学习起到很重要的作用。俗话说磨刀不误砍柴工,Flutter 的学习也同理,我们在新建了 Flutter 项目后,需要进一步了解和学习 Flutter 的项目结构、文件的配置。而 Flutter 由于是跨平台应用,所以一般都会包括 Android 和 iOS 两个项目的目录以及 Flutter 框架相关的 dart 类源码等。

Flutter 的项目开发比较简单,项目结构也不算太复杂,所以大家应该有信心去掌握和学习 Flutter 相关知识。接下来,就开始我们认识 Flutter 项目结构及配置文件的学习之旅吧。

1.Flutter的项目架构

Flutter 包括 Android 和 iOS 两个项目的目录以及相关的 dart 类源码。

前面讲到过 Flutter 的新建项目,这里就不再赘述了。我们新建项目后,会看到如下图所示的 Flutter 默认项目结构:

Flutter学习记录——2.Flutter项目架构_Flutter


Flutter学习记录——2.Flutter项目架构_android_02


我们可以看到主要包含了:android、ios、lib、test 几个目录以及 pubspec.yaml 配置文件等。接下来我们先看这几个目录的作用。

1.1 android目录

android 目录主要是存放一个完整的 Android 项目的目录。编译后,我们的 Flutter 代码会加入整合到这个 Android 项目中,形成一个 Flutter Android 应用。所以 android 目录存放的 Android 项目结构都是完整的,可以通过 Android Studio 打开进行编译、运行、开发、调试等等操作。这里把 android 目录的项目用 Android Studio 打开进行一下预览:

Flutter学习记录——2.Flutter项目架构_Flutter_03


可以看到它就是一个完整的 Android 项目,代码最终编译为对应的 Android 平台的应用。这里的启动 Activity 就是 MainActivity,看下里面的内容:

package com.example.flutter_samples;

import android.os.Bundle;
import io.flutter.app.FlutterActivity;
import io.flutter.plugins.GeneratedPluginRegistrant;

public class MainActivity extends FlutterActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
GeneratedPluginRegistrant.registerWith(this);
}
}

可以看到,里面几乎没有什么代码逻辑,只是继承了 FlutterActivity,然后将 Flutter 相关插件注册进来。当然后续如果我们需要编写插件、编写原生交互的时候(一般不用这种,除非一定要写代码逻辑的时候,否则就脱离了 Flutter 插件化跨平台的特性),需要在这里写一些回调插件逻辑。不过这种情况一般是:Flutter 插件库里没有可以实现你的复杂功能的插件库,Flutter SDK 里无法实现你要的功能,这种情况就可能要与原生交互了。推荐是编写插件库形式进行与原生交互,更加规范和方便,也有利于后续组件化维护与共享。

如果需要更改 Android 应用包名、版本号、签名文件,修改方式和修改 Android 项目一样的,都是在 app 目录下的 build.gradle 里进行修改:

android {
compileSdkVersion 28
...
defaultConfig {
//应用包名
applicationId "com.example.flutter_samples"
minSdkVersion 16
targetSdkVersion 28
//版本号
versionCode 1
//版本名称
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
...

1.2 ios目录

ios 目录和 android 目录一样,存放的是 iOS 项目文件,里面的 iOS 项目结构就是一个完整的 iOS 目录结构。可以使用 XCode 打开进行编译、修改、开发、调试等等操作。例如 iOS 平台的图标的修改、版本号的修改等等操作都是在这里,就不再重复说明。

1.3 lib目录

lib 目录就是我们存放核心的 Flutter 代码逻辑的地方了,里面放置了 dart 语言的类源码文件(例如 main.dart)。我们的项目核心逻辑源码文件都是放在这里的,lib 下的源码最终会编译到 Android 和 iOS 平台进行渲染。

默认有一个 main.dart 类,这个 main.dart 类名字不可以修改,必须放置在 lib 根目录,它是我们项目的入口文件,入口类。

test 目录里主要用于编写我们的测试用例,如测试 Widget UI、数据等等。默认里面有一个 widget_test.dart 文件。我们看下它的内容:

//这个一个测试用例的小例子
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';

import 'package:flutter_samples/main.dart';

void main() {
testWidgets('Counter increments smoke test', (WidgetTester tester) async {
// 编译APP
await tester.pumpWidget(MyApp());

// 验证初始状态下ui是否有显示为0的Widget和1的Widget
expect(find.text('0'), findsOneWidget);
expect(find.text('1'), findsNothing);

// 点击"+"号图标,触发事件
await tester.tap(find.byIcon(Icons.add));
await tester.pump();

//验证点击后是否实现加一功能,寻找ui上是否有显示为0的Widget和1的Widget
expect(find.text('0'), findsNothing);
expect(find.text('1'), findsOneWidget);
});

// test(description, body);
}

如果在 Visual Studio Code 里看这段,默认是有 Run 和 Debug 按钮的,我们可以点击 Run 进行运行测试用例:

Flutter学习记录——2.Flutter项目架构_Flutter_04

2.Flutter配置文件讲解

2.1 pubspec.yaml

这个是我们的 Flutter 项目的配置文件,也比较重要,我们在这里可以配置引用第三方插件库、添加 assets 图片资源、font 字体资源、音视频资源路径等等。整个文件是参照 YAML(YAML Ain’t a Markup Language)语法规范进行定义的格式,其实就是通过缩进来形成结构目录,非常简单,因此就不过多描述语法了。我们看下 pubspec.yaml 配置文件的内容和结构:

//项目名称:要用英文,类似于Android中的包名,如果它修改了整个项目的引入的路径都要修改
//所以一般确定了就不要修改
name: flutter_samples
//项目描述
description: A new Flutter project.

//版本号,这个会覆盖对应Android和IOS的应用版本号
//+号前对应Android的versionCode,+号后对应Android的versionName
//+号前对应IOS的CFBundleVersion,+号后对应IOS的CFBundleShortVersionString
version: 1.0.0+1

//表示项目的编译环境要求为dart sdk版本号在2.1.0和3.0.0之间
environment:
sdk: ">=2.1.0 <3.0.0"


//项目的依赖插件库
//Flutter插件库在这里查找引用:https://pub.dartlang.org/flutter
dependencies:
flutter:
sdk: flutter
//我们可以在这里引入插件库
cupertino_icons: ^0.1.2
flutter_webview_plugin: ^0.3.1

dev_dependencies:
flutter_test:
sdk: flutter

//flutter相关配置
flutter:
//是否使用material图标,建议为true
uses-material-design: true

//配置项目文件里的图片路径
//如果需要使用项目目录内附带的图片、音视频等资源,必须在这里配置定义
assets:
- images/a_dot_burr.jpeg
- images/a_dot_ham.jpeg

//字体文件资源相关配置
fonts:
- family: Schyler
fonts:
- asset: fonts/Schyler-Regular.ttf
- asset: fonts/Schyler-Italic.ttf
style: italic
- family: Trajan Pro
fonts:
- asset: fonts/TrajanPro.ttf
- asset: fonts/TrajanPro_Bold.ttf
weight: 700

//下面这几项一般只有在编写插件库发布到Dart Pub时才写,一般不用写
//作者
authors:
- Natalie Weizenbaum <nweiz@google.com>
- Bob Nystrom <rnystrom@google.com>
//主页
homepage: https://example-pet-store.com/newtify
//文档地址
documentation: https://example-pet-store.com/newtify/docs
//发布到
publish_to:

这里再多说一句,如果我们在配置文件里引入了一个插件库后,比如 sharedpreferences,我们再用 Android Studio 打开 Android 项目后,可以看到目录的依赖项里增加了 sharedpreferences:

Flutter学习记录——2.Flutter项目架构_android_05

然后 Android 项目主工程 GeneratedPluginRegistrant 类里增加了如下内容:

package io.flutter.plugins;

import io.flutter.plugin.common.PluginRegistry;
import io.flutter.plugins.sharedpreferences.SharedPreferencesPlugin;

/**
* 增加了注册shared_preferences插件库方法
*/
public final class GeneratedPluginRegistrant {
public static void registerWith(PluginRegistry registry) {
if (alreadyRegisteredWith(registry)) {
return;
}
SharedPreferencesPlugin.registerWith(registry.registrarFor("io.flutter.plugins.sharedpreferences.SharedPreferencesPlugin"));
}

private static boolean alreadyRegisteredWith(PluginRegistry registry) {
final String key = GeneratedPluginRegistrant.class.getCanonicalName();
if (registry.hasPlugin(key)) {
return true;
}
registry.registrarFor(key);
return false;
}
}

2.2 其余几个文件

  • pubspec.lock

里面指明了我们的 pubspec.yaml 等依赖包和项目依赖的库的具体版本号,我们可以在这里查看我们项目引用的依赖的具体版本号等信息,如果某个配置文件丢失,可以通过这个文件重新下载和恢复依赖库。为自动生成文件。

  • .packages

里面放置了项目依赖的库的具体在本机电脑上的绝对路径。为自动生成文件,如果项目出错或者无法找到某个库,可以把这个文件删除,重新自动配置即可。

  • .metadata

里面记录了我们项目的属性信息,如使用 Flutter SDK 哪个分支开发的,项目属性等,用于切换分支、升级 SDK 使用。自动生成,无需修改删除。

3.Flutter代码架构

前面介绍了 Flutter 的项目基本结构,我们来着重看下 lib 里的代码结构。

默认 lib 下有一个 main.dart 类,这个 main.dart 类名字不可以修改,必须放置在 lib 根目录,它是我们项目的入口文件,入口类。当然我们在实际开发中,还是根据需要进行源码类的包划分,这里给出一个示例:

Flutter学习记录——2.Flutter项目架构_android_06


Flutter学习记录——2.Flutter项目架构_ios_07

我们可以根据实际需要在 lib 里建立相关的文件夹,可以按照项目功能分、类的类型和功能分等等。

我们再看下 main.dart 入口文件内容结构:

import 'package:flutter/material.dart';

//void main()为入口方法,main.dart文件独有
void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
//应用的最顶层入口
@override
Widget build(BuildContext context) {
//这里使用了MaterialApp脚手架,当然也可以使用WidgetApp,建议入口使用MaterialApp。
//直接定义一个容器布局也可以
return MaterialApp(
//标题
title: 'Flutter Demo',
theme: ThemeData(
//可以自定义配置主题色调
primarySwatch: Colors.blue,
),
//页面
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}

//使用StatefulWidget有状态Widget
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);

final String title;

//创建State状态
@override
_MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;

void _incrementCounter() {
//每次执行这个方法_counter加一,然后用setState方法进行UI刷新
setState(() {
_counter++;
});
}

@override
Widget build(BuildContext context) {
//Scaffold布局脚手架组件
return Scaffold(
//标题栏Widget组件
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'You have pushed the button this many times:',
),
Text(
'$_counter',
style: Theme.of(context).textTheme.display1,
),
],
),
),
floatingActionButton: FloatingActionButton(
//定义了一个Button,点击执行_incrementCounter()方法
onPressed: _incrementCounter,
tooltip: 'Increment',
child: Icon(Icons.add),
),
);
}
}

这个代码例子是官方默认新建后的内容,运行效果如下图:

Flutter学习记录——2.Flutter项目架构_android_08


实现的功能就是每点击+号浮动按钮一次,显示 0 的 Widget 组件就加一。

代码整体风格就是 React 组件化响应式风格,类似于 DOM 树结构,通过小的 Widget 来组成一个大的页面。部分代码类似于 Java 的写法,其实还是比较简单。刚开始看的时候可能会觉得有点迷惑,不过不要担心,接触 Widget的学习后,大家就会对 Flutter 的编写风格有更直观的了解。

再给大家一个简化版的 main.dart:

import 'package:flutter/material.dart';

//void main()为入口方法,main.dart文件独有
void main() => runApp(MyMainApp());

class MyMainApp extends StatefulWidget {
//这里可以简写为:State<StatefulWidget> createState() => _MyMainPageState();
@override
State<StatefulWidget> createState() {
return _MyMainPageState();
}
}

class _MyMainPageState extends State<MyMainApp> {
@override
void initState() {
super.initState();
}

@override
Widget build(BuildContext context) {
return MaterialApp(
//页面
home: Scaffold(
appBar: AppBar(
title: Text('标题'),
),
body: Center(
child: Text("我是内容"),
),
),
);
}
}

这样看着是不是更简单清晰了,效果如下图:

Flutter学习记录——2.Flutter项目架构_ios_09

大家可以按照这个效果图倒推看代码逻辑结构。

4.总结

本节课主要是给大家讲解 Flutter 项目结构及配置文件相关知识,为后面的 Flutter 学习打下基础。注意点和建议如下:

  • 可以尝试新建一个项目,查看和熟悉下项目相关目录文件信息和结构。
  • 在项目配置文件里添加和修改一下配置信息,看看有什么变化。
  • 多试多实践。


【版权声明】本文内容来自摩杜云社区用户原创、第三方投稿、转载,内容版权归原作者所有。本网站的目的在于传递更多信息,不拥有版权,亦不承担相应法律责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@moduyun.com

  1. 分享:
最后一次编辑于 2023年11月08日 0

暂无评论

推荐阅读
  iD7FikcuyaVi   2023年11月30日   26   0   0 MacWindowsandroid
  b1UHV4WKBb2S   2023年11月13日   37   0   0 裁剪ideflutter
  b1UHV4WKBb2S   2023年11月13日   29   0   0 flutterDart
Xa7AsmJIfSXT