第1节:用于测试与原生项目交互的Flutter项目

第1节:用于测试与原生项目交互的Flutter项目

本节学习内容:通过Flutter的平台通道在Flutter工程中建立提供给原生项目的方法及接收从原生项目返回的值。

本节学习用时:30分钟

本节学习方式:动手实践


本节目录:

一、本节内容介绍

二、本节代码解释


一、本节内容介绍

1、主要介绍的知识点有:

  • 在iOS界面中点击一个按钮跳转到Flutter页面,该Flutter页面有需要传参Main页面

2、要实现的效果如下图所示:

OC跳到Flutter有需要传参的Main页面

3、实现本节效果的代码

本节所有代码文件为:main.dartStatelessMainPage.dartStatefulMainPage.dartNewRouteNoneParam.dartNewRouteWithParam

您可自己通过flutter create materialappproject创建materialappproject项目后,将其lib文件夹下的代码文件替换为如下即可。

3.1、其中完整的main.dart代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
import 'package:flutter/material.dart';
import 'StatelessMainPage.dart';
import 'StatefulMainPage.dart';
import 'NewRouteNoneParam.dart';
import 'NewRouteWithParam.dart';



void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Platform Channel Demo',
home: StatelessMainPage(), //不需传参数的Flutter页面
//home: StatefulMainPage(), //需传参数的Flutter页面
routes: {
'StatelessMainPage':(context) => StatelessMainPage(),
'StatefulMainPage':(context) => StatefulMainPage(),
'NewRouteNoneParam':(context) => NewRouteNoneParam(),
'NewRouteWithParam':(context) => NewRouteWithParam()
}
);
}
}
3.2、其中完整的StatelessMainPage.dart代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
import 'package:flutter/material.dart';
import 'StatefulMainPage.dart';
import 'NewRouteNoneParam.dart';
import 'NewRouteWithParam.dart';

import 'package:flutter/services.dart';
import 'dart:async';

// 已写在main.dart中
//void main() => runApp(MyApp());
//
//class MyApp extends StatelessWidget {
// @override
// Widget build(BuildContext context) {
// return MaterialApp(
// title: 'Platform Channel Demo',
// home: StatelessMainPage(),
// routes: {
// 'newRoute':(context) => NewRoute(),
// 'newRouteWithParam':(context) => NewRouteWithParam(),
// 'StatefulMainPage':(context) => StatefulMainPage()
// }
// );
// }
//}

class StatelessMainPage extends StatelessWidget {
// 创建一个给native的channel (类似iOS的通知)
static const methodChannel = const MethodChannel('com.dvlproad.ciyouzen/platform_channel');

// 给客户端发送一些东东, 这里先不用去拿回什么
Future<Null> _showToast() async {
try {
await methodChannel.invokeMethod('showToast','这是我在Flutter中写的文字');
} on PlatformException {

}
}

Future<Null> _goBack() async {
try {
await methodChannel.invokeMethod('goBack');
} on PlatformException {

}
}

Future<Null> _goiosPage() async {
try {
Map<String, dynamic> map = { "content": "flutter传给iOS的内容","data":[1,2,3,4,5]};
await methodChannel.invokeMethod('goiosPage', map);
} on PlatformException {

}
}

@override
Widget build(BuildContext context) {
//Scaffold是Material中主要的布局组件.
return new Scaffold(
appBar: new AppBar(
leading: new IconButton(
icon: new Icon(Icons.menu),
tooltip: 'Navigation menu',
onPressed: null,
),
title: new Text('platform channel Example title'),
actions: <Widget>[
// new IconButton(
// icon: new Icon(Icons.search),
// tooltip: 'Search',
// //onPressed: null,
// onPressed: () {
// goStatefulMainPage(context);
// },
// ),
new FlatButton(
child: Image.asset('lib/Resources/nav_right_gray_normal.png'),
onPressed: (){
goStatefulMainPage(context);
}),
],
),
//body占屏幕的大部分
body: new Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
new Text('Hello, platform channel!'),
new RaisedButton(
child: Text('showToast'),
onPressed: (){
_showToast();
}
),
new RaisedButton(
child: Text('goBack'),
onPressed: (){
_goBack();
}
),
new RaisedButton(
child: Text('goiosPage'),
onPressed: (){
_goiosPage();
}
),

],
),
),
floatingActionButton: new FloatingActionButton(
tooltip: 'Add', // used by assistive technologies
child: new Icon(Icons.add),
onPressed: () {
goNextPageNoneParam(context);
},
)
);
}
}

void goNextPageNoneParam(context) {
Navigator.push(context, new MaterialPageRoute(builder: (context) {
return new NewRouteNoneParam();
}));
}


void goNextPageWithParams(context) {
Navigator.push(context, new MaterialPageRoute(builder: (context) {
return new NewRouteWithParam();
}));
}

void goStatefulMainPage(context) {
Navigator.push(context, new MaterialPageRoute(builder: (context) {
return new StatefulMainPage();
}));
}
3.3、其中完整的StatefulMainPage.dart代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
import 'package:flutter/material.dart';
import 'NewRouteNoneParam.dart';

import 'package:flutter/services.dart';
import 'dart:async';


// 已写在main.dart中
//void main() => runApp(MyApp());
//
//class MyApp extends StatelessWidget {
// @override
// Widget build(BuildContext context) {
// return MaterialApp(
// title: 'Platform Channel Demo',
//
// home: StatefulMainPage(),
// );
// }
//}

class StatefulMainPage extends StatefulWidget {

@override
State<StatefulWidget> createState() {
// TODO: implement createState
return StatefulMainPageState();
}
}

class StatefulMainPageState extends State<StatefulMainPage> {
// 创建一个给native的channel (类似iOS的通知)
static const methodChannel = const MethodChannel(
'com.dvlproad.ciyouzen/platform_channel');

// 给客户端发送一些东东, 这里先不用去拿回什么
Future<Null> _showToast() async {
try {
await methodChannel.invokeMethod('showToast','这是我在Flutter中写的文字');
} on PlatformException {

}
}

Future<Null> _goBack() async {
try {
await methodChannel.invokeMethod('goBack');
} on PlatformException {

}
}

Future<Null> _goiosPage() async {
try {
Map<String, dynamic> map = { "content": "flutter传给iOS的内容","data":[1,2,3,4,5]};
await methodChannel.invokeMethod('goiosPage', map);
} on PlatformException {

}
}

String imageName = "lib/Resources/message_arrow.png";
Future<Null> _changeLeftBarButtonAction() async {
try {
Map<String, dynamic> map = { "content": "flutter传给iOS的内容","data":[1,2,3,4,5]};
final Map dict = await methodChannel.invokeMethod('changeLeftBarButtonAction', map);

setState(() {
imageName = dict["imageName"];
print(imageName);
});
} on PlatformException {

}
}

@override
void initState() {
// TODO: implement initState
super.initState();
_changeLeftBarButtonAction();
}

@override
Widget build(BuildContext context) {
//Scaffold是Material中主要的布局组件.
return new Scaffold(
appBar: new AppBar(
leading: new FlatButton(
// child: Image.asset('lib/Resources/nav_back_white_normal.png'),
child: Image.asset(imageName),
onPressed: (){
_goBack();
}),

// new IconButton(
// icon: new Icon(Icons.menu),
//// icon: Image.asset('lib/Resources/message_arrow.png'),
// tooltip: 'Navigation menu',
// onPressed: null,
// ),
title: new Text('StatefulMainPage'),
actions: <Widget>[
// new IconButton(
// icon: new Icon(Icons.search),
// tooltip: 'Search',
// onPressed: null,
// ),
new FlatButton(
child: Image.asset('lib/Resources/nav_right_gray_normal.png'),
onPressed: null
),
],
),
//body占屏幕的大部分
body: new Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Image.asset('lib/Resources/message_arrow.png'),
new Text('Hello, StatefulMainPage!'),
new RaisedButton(
child: Text('showToast'),
onPressed: (){
_showToast();
}
),
new RaisedButton(
child: Text('goBack'),
onPressed: (){
_goBack();
}
),
new RaisedButton(
child: Text('goiosPage'),
onPressed: (){
_goiosPage();
}
),

],
),
),
floatingActionButton: new FloatingActionButton(
tooltip: 'Add', // used by assistive technologies
child: new Icon(Icons.add),
onPressed: () {
goNextPageNoneParam(context);
},
)
);
}
}

void goNextPageNoneParam(context) {
Navigator.push(context, new MaterialPageRoute(builder: (context) {
return new NewRouteNoneParam();
}));
}
3.4、其中完整的NewRouteNoneParam.dart代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'dart:async';

class NewRouteNoneParam extends StatelessWidget {
static const methodChannel = const MethodChannel('com.dvlproad.ciyouzen/platform_channel');
Future<Null> _goBack() async {
try {
await methodChannel.invokeMethod('goBack');
} on PlatformException {

}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("New route none Param"),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text("This is new route"),
RaisedButton(
child: Text('goback'),
onPressed: _goBack
)
],
)

),
);
}
}
3.5、其中完整的NewRouteWithParam.dart代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'dart:async';

class NewRouteWithParam extends StatelessWidget {
static const methodChannel = const MethodChannel('com.dvlproad.ciyouzen/platform_channel');
Future<Null> _goBack() async {
try {
await methodChannel.invokeMethod('goBack');
} on PlatformException {

}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("New route with params"),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text("This is new route with params"),
RaisedButton(
child: Text('goback'),
onPressed: _goBack
)
],
)

),
);
}
}

第2节:Android项目集成Flutter

第2节:Android项目集成Flutter

本节学习内容:在已有的Android项目中集成Flutter,以使得您的Android项目中的部分界面/功能可以通过Flutter来实现。

本节学习用时:3分钟

本节学习方式:动手实践


本节目录:

一、集成方式介绍

二、集成方法介绍

三、集成后调用Flutter界面的代码编写


一、集成方式介绍

本节将介绍两种在已有的Android项目中集成Flutter的方法。

待补充。。。。。。。

第1节:iOS项目集成Flutter

第1节:iOS项目集成Flutter

本节学习内容:在已有的iOS项目中集成Flutter,以使得您的iOS项目中的部分界面/功能可以通过Flutter来实现。

本节学习用时:30分钟

本节学习方式:动手实践


本节目录:

一、集成方式介绍

二、集成方法一:手动配置iOS与Flutter的混编环境

三、集成方法二:Pod集成Flutter方式

四、集成后调用Flutter界面的代码编写


一、集成方式介绍

本节将介绍两种在已有的iOS项目中集成Flutter的方法,分别为①手动配置iOS与Flutter的混编环境、②Pod集成Flutter方式。

下面表格是两种集成Flutter的方法比较:

手动集成Flutter Pod集成Flutter
集成速度 需要自己建立文件、进行相应配置,并替换 执行Pod及Run Script即可
Flutter项目更新时 每次都需要替换 不用替换
Flutter项目与iOS同时路径变更时 不影响iOS工程 Flutter工程需要重新编译执行;
然后iOS工程需再重新执行Pod

二、集成方法一:手动配置iOS与Flutter的混编环境

1.1 集成后的最后项目结构如图:

myiosproject project structure

1.2 集成后的最后文件结构如图:

myiosproject file structure

1.3 详细的集成实现步骤如下:
  • ①、通过终端命令在指定目录(这里我们选择iOS项目的同级目录)创建myfluttermodule。flutter create -t module myfluttermodule

  • ②、Xcode:创建iOS项目,设为myiosproject;

  • ③、Xcode:创建配置衔接文件

    • 在②中建立的iOS项目中新建Config目录,用于存放/管理接下来Xcode工程需要创建的的配置衔接文件;

    • 选择创建Configuration Settings File文件,分别创建名为 Flutter.xcconfigDebug.xcconfigRelease.xcconfig的三个配置文件;

      New Configuration Settings File

    • 完善Flutter.xcconfigDebug.xcconfigRelease.xcconfig三个配置文件的内容为分别如下:

      Flutter.xcconfig 配置文件内容如下:

      1
      2
      3
      4
      5
      6
      > //Flutter.xconfig,用于指向外目录flutter module的`Generated.xcconfig`文件路径引用文件
      >
      > //这里填写前面建立的 myfluttermodule 的Generated.xcconfig的路径
      > #include "../../myfluttermodule/.ios/Flutter/Generated.xcconfig"
      > ENABLE_BITCODE=NO
      >

      Debug.xcconfig 配置文件内容如下:

      1
      2
      3
      4
      5
      6
      7
      > //Debug.xconfig,Xcode的环境配置文件
      >
      > #include "Flutter.xcconfig"
      > //#include "../Pods/Target Support Files/******.debug.xcconfig"//pod路径
      > #include "../Pods/Target Support Files/Pods-myiosproject/Pods-myiosproject.debug.xcconfig"//pod路径
      > FLUTTER_BUILD_MODE=debug
      >

      Release.xcconfig 配置文件内容如下:

      1
      2
      3
      4
      5
      6
      7
      > //Release.xconfig,Xcode的环境配置文件
      >
      > #include "Flutter.xcconfig"
      > //#include "../Pods/Target Support Files/******.release.xcconfig"//pod路径
      > #include "../Pods/Target Support Files/Pods-myiosproject/Pods-myiosproject.release.xcconfig"//pod路径
      > FLUTTER_BUILD_MODE=release
      >
    • 修改Xcode Project的环境配置选择

      myiosproject Project Info Configurations

  • ④、Xcode -> Target -> Build Phases -> New Run Script Phase,添加要执行的脚本内容引入xcode-backend.sh,此步很重要。

    1
    2
    "$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh" build
    "$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh" embed

    myiosproject New Script xcode-backend.sh

  • ⑤、添加/替换flutter编译产物,如果之前已添加,则这里每次有有新的时候,注意要替换掉,否则界面还是旧的。

    即复制 myfluttermodule/.ios/Flutter下的App.frameworkengineflutter_assets进行替换。

    然后Xcode重新编译即可。

    注意:flutter_assets 并不能使用Create groups 的方式添加,只能使用Creat folder references 的方式添加进Xcode项目内,否则跳转flutter会页面渲染失败(页面空白)。

  • ⑥、至此,恭喜你,到这里您可向往常一样直接执行已集成Flutter的Xcode项目了。

三、集成方法二:Pod集成Flutter方式

2.1 最后的项目结构如图:

myiosproject2 project structure

2.2 实现步骤如下:
  • ①、通过终端命令在指定目录(这里我们选择iOS项目的同级目录)创建myfluttermodule。flutter create -t module myfluttermodule。这里因为我们已经在1中实现,所以不再重复创建。

  • ②、Xcode:创建myiosproject2;添加如Podfile,及在Podfile中如结构图中所示,补充

    1
    2
    flutter_application_path = './../myfluttermodule/'
    eval(File.read(File.join(flutter_application_path, '.ios', 'Flutter', 'podhelper.rb')), binding)

    后,执行pod install

    myiosproject2 pod install

  • ③、Xcode -> Target -> Build Phases -> New Run Script Phase,添加要执行的脚本内容引入xcode-backend.sh,此步很重要。同1中一样的做法。

  • ④、至此,混编环境配置成功!

四、集成后调用Flutter界面的代码编写

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#import "AppDelegate.h"
#import <Flutter/Flutter.h>

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
// ViewController *viewController = [[ViewController alloc] init];
// UIViewController *rootViewController = [[UINavigationController alloc] initWithRootViewController:viewController];
UIViewController *rootViewController = [[FlutterViewController alloc] initWithProject:nil nibName:nil bundle:nil];
self.window.rootViewController = rootViewController;
[self.window makeKeyAndVisible];

return YES;
}

而后,正常执行Xcode项目即可。

三、更多混编

更多混编知识,请查看官网:使用平台通道编写平台特定的代码

platform channel

附:

目录

目录

前言

前言

为更好的学习Flutter,特地将Flutter的学习从零整理及总结成本书,方便大家的快速学习!

其他权威网站:Flutter中文网Flutter实战书籍

主流跨平台语言对比

一个推uniapp的flutter、rn、uni-app比较的好文

主流跨平台语言(Flutter和RN、Weex)之间的对比:

主流跨平台语言对比

  • 渲染性能

和RN和Weex将javascript转化为原生控件渲染不同,Flutter完全挣脱了原生控件的“束缚”,如下图所示,Flutter使用了分层架构,分为Framework和Engine两个部分,其中Framework层提供各种基础组件库,包括各种Widget,动画等,Engine层则完全由C和C++实现,使用Skia进行渲染(对!就是chrome用的那个图形渲染框架),官方宣称可以达到原生app的渲染性能。

Flutter结构

  • Google新操作系统Fuchsia(被认为是Android的继任者)也使用Flutter作为其UI框架,今后的发展不可限量。

第1节:Flutter与Dart的升级

[TOC]

一、查看当前Flutter与Dart版本

升级dart sdk和升级flutter sdk是不一样的,两者千万不要搞混了。

废话不多说,其实我就想说一句,dart sdk不建议升级。

为什么这么说呢,原因很简单,因为flutter sdk中自带了匹配flutter sdk版本的dart sdk(flutter sdk和dart sdk的版本要匹配,不是任意的dart sdk版本都能匹配任意的flutter sdk版本,这一点官方已经帮我们做了。在你下载的flutter sdk中就自带了匹配版本的dart sdk)。如果强行手动去升级dart sdk会报错,flutter项目都会出问题的。

flutter与Dart的匹配:https://flutter.cn/docs/development/tools/sdk/releases?tab=macos

1
2
3
4
5
6
7
8
9
qian@qiandeMacBook-Pro ~ % dart --version
Dart SDK version: 2.14.4 (stable) (Wed Oct 13 11:11:32 2021 +0200) on "macos_x64"
qian@qiandeMacBook-Pro ~ %
qian@qiandeMacBook-Pro ~ % flutter --version
Flutter 2.5.3 • channel stable • https://github.com/flutter/flutter.git
Framework • revision 18116933e7 (6 months ago) • 2021-10-15 10:46:35 -0700
Engine • revision d3ea636dc5
Tools • Dart 2.14.4
qian@qiandeMacBook-Pro ~ %

二、升级到3.0.0

Flutter 3.0 升级涉及的主要三方库整理如下:

三方库 功能简述 当前版本 最新版本 官方开始支持 flutter3.0的版本 备注
pull_to_refresh 下拉刷新上拉加载 2.0.0 2.0.0
flutter_easyrefresh 下拉刷新上拉加载 2.2.1 2.2.1
marquee 跑马灯 2.2.0 2.2.2 2.2.2(5.19)
fading_edge_scrollview 构建具有淡入淡出边缘的可滚动视图 marquee中依赖 2.0.1 2.0.1
photo_manager 相册相关插件 2.0.8 2.1.1 2.1.0+2(5.13)
wechat_assets_picker 相册选择照片 7.2.0 7.3.0 7.3.0(5.13)
wechat_camera_picker 相机拍摄照片 3.1.0 3.2.0+1 3.2.0+1(5.13)
extended_image 图片浏览 6.0.3 6.2.1 6.2.0(5.12)
extended_image_library 图片浏览 3.1.4 3.3.0 3.3.0(5.12)
reorderables 拖曳排序 0.4.4 0.5.0 0.5.0(5.12)
cached_network_image 图片缓存底层库 3.2.0 3.2.1 3.2.1(5.16)
flutter_easyloading loading 3.0.1 3.0.5 3.0.5(5.23)
tim_ui_kit_lbs_plugin 地图位置插件 1.1.2 1.1.2
bruno 贝壳UI库 2.0.0 2.2.0
scroll_to_index 固定/可变行高的滚动 2.1.1 3.0.1 3.0.0
scrollable_positioned_list
scroll_to_index](https://pub.dev/packages/)
scroll_to_index](https://pub.dev/packages/)

上述控件计划处理方案:

1、已支持的,直接升级到,并升级其依赖到的相关库

2、不支持且需要的,进行手动支持,如tim_ui_kit_lbs_plugin

3、不支持但冗余的,合并减少,如pull_to_refreshflutter_easyrefresh

4、不支持但冗余且被其他app使用率不高的,从项目中逐步移除,如bruno

第1节:Flutter开发环境搭建与运行

[TOC]

本节学习内容:Flutter的环境搭建及创建运行您的第一个Flutter项目。

本节学习用时:30分钟

本节学习方式:动手实践


本节目录:

一、检测您是否具备了Flutter的开发环境

二、创建并运行第一个Flutter项目


一、检测您是否具备了Flutter的开发环境

因为您可能之前已经有配置过Flutter的开发环境了,所以为了避免重复安装,我们通过在终端运行flutter doctor命令,来进行检测,查看是否缺少。

新电脑未安装,请点击查看在macOS上搭建Flutter开发环境

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 在终端打开该文件
open ~/.bash_profile

# 终端编辑该文件(没有则会新建)
vim .bash_profile # 不存在.bash_profile,可以该终端输入来创建该文件

# 在打开的文件中,插入如下内容
export PATH=`pwd`/flutter/bin:$PATH

# 输入 :wq 来保存


# 在终端执行如下命令,保证设置的环境变量,本次就能够使用
source .bash_profile

1、环境已完善时

如果您的环境之前已经配置过且已完全配置好的话,您的命令执行结果可能会如图所示:

flutter doctor 检测出无问题

2、环境未完善时

  • 如果有提示错误的(如果你是第一次,那肯定有很多问题),请参照本节最后的【附1】、flutter doctor问题解决中的内容进行解决。

分割图1

二、创建第一个Flutter项目

1、最简单的创建Flutter项目的方法

在终端执行flutter create originflutterproject即可在指定目录建立Flutter项目。

flutter create originflutterproject

三、运行Flutter项目

1、运行方法

1.1、查找本地及指定运行设备

1
flutter devices

1.2、常见的在终端运行方法

在指定设备上运行Flutter项目

1
flutter run -d xxxxxxxx

flutter run -d deviceid

1.3、在WebStorm中运行

本质还在flutter run -d xxxxxxxx

如果,你想在WebStorm中运行的话,操作如下:

webstorm flutter run -d deviceid

上述 External Tool的添加过程如下:

1
2


webstorm flutter run -d deviceid

运行效果如下:

webstorm flutter run -d deviceid

热更新问题:

image-20200817102953555

直接在终端下,输入对应的如r就行。

image-20200817103401865

1.4、在VS Code中运行

选择设备有如下两个地方。当然你也可以直接在终端上执行。

image-20211209225632484

2、运行项目的常见问题

2.1 问题一、缺少第三方库

如果缺少依赖的第三方库,在pubspec.yaml 文件中找到 dependencies 在里面填写 第三方库。

并请在终端执行flutter packages get,以拉取声明的第三方库到本地工程即可。

flutter第三方库官网:https://pub.dartlang.org/

如要了解更多请查看:官网Flutter起步: 体验

分割图1

【附1】、flutter doctor问题解决

flutter doctor该命令的作用:查看是否需要安装其它依赖项来完成安装。

下面涵盖的错误介绍及解决有:

  • 1.1、-bash: flutter: command not found
  • 1.2、缺少依赖项
  • 其他问题,请查看【附2】、flutter 安装过程中的其他问题解决

1.1、flutter doctor执行问题-bash: flutter: command not found

原因:Flutter相关命令无效(此时flutter -h肯定也是一样的问题)

附:完好的flutter -h结果应为如图所示:

 flutter -h 检测flutter

解决:下载Flutter SDK,并配置Flutter环境变量到PATH中即可。

步骤:

  • ①下载Flutter SDK。

    Flutter SDK官网地址。(如果您觉得速度慢,这里提供一个已经下载好的地址:Flutter SDK 1.0.0 网盘下载地址 密码:nm09)

  • ②配置Flutter环境变量方法:即在~/.bash_profile文件里添加需要配置的内容即可。

    下面是我的~/.bash_profile文件内容:

我的~/.bash_profile

但在这里目前我们只需要上图中我圈出来的那行export PATH=/Applications/flutter/bin:$PATH #配置Flutter环境变量即可。这里我们先满足目前认知Flutter所需的即可,没必要把如下其他行是暂时不需要的所有的都加上去,当然你加上去可以以后更省事。

1
2
3
4
5
6
7
8
9
10
11
# Flutter
export PATH=/Applications/flutter/bin:$PATH #配置Flutter环境变量

# 设置pub源,才能让你在国内愉快的使用别人写的库
export PUB_HOSTED_URL=https://pub.flutter-io.cn
export FLUTTER_STORAGE_BASE_URL=https://storage.flutter-io.cn

# ANDROID
export ANDROID_HOME=/Users/lichaoqian/Library/Android/sdk #android sdk目录,替换为你自己的即可
export PATH=${PATH}:${ANDROID_HOME}/tools
export PATH=${PATH}:${ANDROID_HOME}/platform-tools

1.2、flutter doctor执行结果问题:缺少依赖项

如果您不缺依赖项,那您命令的执行结果会为

如果flutter doctor 检测出问题,此时的命令执行结果一般如下:

flutter doctor 检测出问题

原因:缺少依赖项

解决:遇到什么错误,根据提示操作即可。

1.2.1、iOS toolchain

image-20220321005147057

①、解决iOS toolchain - develop for iOS devices (Xcode 10.1),根据提示终端执行命令后iOS toolchain即变为正常如下

iOS toolchain问题解决后

1.2.2、Android toolchain

②、解决Android toolchain - develop for iOS devices

image-20220321005213102

在遇到这个问题,首先要确保自己的Android studio的下图中的几个项勾选上:

image-20220321010157585

安装 Android SDK Command-line Tools(latest)

image-20220321010247340

根据提示下载Android SDK,并放置ANDROD_HOME指定的目录下后,问题解决,结果如下:

Android SDK安装后

其他参考:入门: 在macOS上搭建Flutter开发环境

修改环境变量:

1
2
3
4
# ANDROID
export ANDROID_HOME=/Users/qian/Library/Android/sdk #android sdk目录,替换为你自己的即可
export PATH=${PATH}:${ANDROID_HOME}/tools
export PATH=${PATH}:${ANDROID_HOME}/platform-tools

非M1芯片的Mac:

image-20220321011753288

1.2.3、Android Studio

③、解决Android Studio

image-20220321005253299

为Android Studio安装Flutter Plugins后

Android Studio安装Flutter Plugins后

安装过程中,如遇Plugins搜索不到时候,如

Android Plugins搜索不到的示例截图

请确保如下图中的路径Perferences -> Appearance & Behavior -> System Settings -> Updates -> Use secure connection中的勾是取消的,如果不是请取消掉,并重启Android Studio后,重新搜索即可。

Android Plugins搜索不到的处理1

或者可以直接从http://plugins.jetbrains.com/上下载插件后,通过选择插件安装方式为Install plugin from disk来进行安装,如下图:

插件安装方式选择为Install plugin from disk

附:这是已经下载好后存在网盘上的Flutter插件

1.2.4、解决Intelij IDEA,为Intelij IDEA安装Flutter Plugins后

④为Intelij IDEA安装Flutter Plugins后的结果,即为不缺依赖的情况了。

其他资料:官网中的入门: 在macOS上搭建Flutter开发环境

如果还没解决安装问题,请查看【附2】、flutter 安装过程中的其他问题解决

四、升级 Flutter

官网升级 Flutter的标准步骤

1.2.5、解决Flutter

有时候,你还会有这种错误,原因为你的flutter sdk太旧了。

flutter doctor 检测出问题2

官网下载最新sdk,并替换掉你之前的flutter sdk。(附:你之前的Flutter的sdk的路径,请通过你写在open ~/.bash_profile中的PATH找到。

image-20200717193444530

【附2】、flutter 安装过程中的其他问题解决

flutter doctor其他问题1

原因:您的Flutter SDK 要求你Android Studio中的Flutter plugin版本至少到16.0.0。但你当前的Android Studio版本却只允许你最高只能装到Flutter plugin version 12.1。

解决:升级你的Android Studio后,重新安装其Flutter plugin。

【附3】、flutter 运行的过程中的其他问题解决

image-20200718010926592

可以看出是路径出错了。

根据路径出错这个方向,进行工程配置错误的查看,发现出错的位置在如下图位置。

image-20200718011513227

假设我们的工程目录结构如下,

image-20200718012410466

则cj_nativeflutter_fluttermodule的路径表示为${SRCROOT}/../cj_nativeflutter_fluttermodule

修改完后,重新编译即可解决问题。

Command PhaseScriptExecution failed with a nonzero exit code

image-20200718014117212

pubspec.yaml文件所在的目录下执行flutter packages get

flutter packages get获取pubspec.yaml文件中列出的所有依赖包

image-20200718014656554

接着再执行flutter packages upgrade,会发现刚才的Compiler message错误少了很多

flutter packages upgrade 获取pubspec.yaml文件中列出的所有依赖包的最新版本

更新库之后还有错误。

image-20200718015310060

进入工程查看,确实各个地方都提示着我们工程代码有问题。那么我们所需要做的就是修复这个问题。

image-20200718015625741

我们对这些编译不通过的代码进行修复或者临时注释掉,即可通过。

第3节:Flutter的最基础知识

[toc]

第3节:Flutter的最基础知识

一、最基础知识

1、颜色

1
2
Colors.transparent,  //透明色
Colors.black.withOpacity(0.4)

2、图片

1
new Image.asset('images/goods_image.png', width: 30.0, height: 30.0,),

三、按钮Button

1、按钮形式

1
2
3
4
5
6
7
8
9
floatingActionButton: new FloatingActionButton(
tooltip: 'Add', // used by assistive technologies
child: new Icon(Icons.add),
// 点击进行页面跳转
onPressed:() {
goNextPage(context);
}
),
);

2、按钮的事件写法

2.1、无方法
1
2
3
4
5
6
7
8
9
// 写法①
onPressed: null,

// 写法②:推荐
onPressed: () {}

// 写法③:不推荐
onPressed: () => {}
// 缺点:只能直接retrun返回值,不能写多行
2.2、有方法,但该方法无参数
1
2
3
4
5
6
7
8
9
10
11
12
// 设方法为:
void printLog() {
print("This is printLog Method");
}

// 则按钮点击事件有两种写法:
// 写法①:常见的写法
onPressed: () {
printLog();
},
// 写法②:简写
onPressed: printLog,
2.3、有方法,且该方法有参数
1
2
3
4
5
6
7
8
//设方法为:
void printText($text) {
print("The text is " + $text);
}
//则按钮点击事件为:
onPressed:() {
printText("Hello world");
}

五、页面的跳转 & 路由的管理

5.1 直接跳转

以跳转到上述建立的NewRoute.dart为例,则跳转方法:

方式①:

1
2
3
4
5
6
7
8
import 'NewRoute.dart';

// 按钮处的写法
onPressed: () {
Navigator.push(context, new MaterialPageRoute(builder: (context) {
return new NewRoute();
}));
},

方式②:

1
2
3
4
5
6
7
8
9
10
11
12
13
import 'NewRoute.dart';

// 定义导航到新路由的方法
void goNextPage(context) {
Navigator.push(context, new MaterialPageRoute(builder: (context) {
return new NewRoute();
}));
}

// 则按钮处的写法,自然如下:
onPressed:() {
goNextPage(context);
}

5.2 使用路由管理

1
2
3
4
5
6
7
8
9
10
11
import 'NewRoute.dart';

// 在MaterialApp中注册路由表
routes: {
"new_page": (context) => NewRoute(),
},

// 按钮位置写法
onPressed: () {
Navigator.pushNamed(context, "new_page");
},

第3节:Flutter的最基础知识

[toc]

第3节:Flutter的最基础知识

本节学习内容:通过最基础的Flutter控件等实现一个app ,让您对Flutter构建的app有一个初步的认识!

本节学习用时:30分钟

本节学习方式:推荐直接看懂代码即可


本节目录:

一、本节内容介绍

二、本节代码解释


一、本节内容介绍

本节通过实现以下界面/功能效果,为您介绍一些最基础的Flutter知识点。

1、主要介绍的知识点有:

  • MaterialApp的应用
  • Scaffold的应用
  • 文本的应用:Text
  • 按钮的应用:FloatingActionButton
  • 页面的跳转

2、要实现的效果如下图所示:

materialappproject效果图

3、实现本节效果的代码

本节所有代码文件为:main.dartNewRoute.dart

您可自己通过flutter create materialappproject创建materialappproject项目后,将其lib文件夹下的代码文件替换为如下即可。

3.1、其中完整的main.dart代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
import 'package:flutter/material.dart';
import 'NewRoute.dart';

// 写法①
// >>>>>>>>>>>>> runApp写法① >>>>>>>>>>>>>
// void main() {
// runApp(new MaterialApp(
// title: '1.MaterialApp in main',
// home: new HelloWorldPage(),
// ));
// }
// <<<<<<<<<<<<< runApp写法① <<<<<<<<<<<<<


// 写法②
// >>>>>>>>>>>>> runApp写法② >>>>>>>>>>>>>
void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: '2.MaterialApp in MyApp',

// 页面跳转的方式②:注册路由表
// 详情查看[官网路由管理](https://book.flutterchina.club/chapter2/flutter_router.html)
// 缺点:路由传递的参数无法动态修改(如果路由有参数)
routes: {
"new_page": (context) => NewRoute(),
},

home: HelloWorldPage(),
);
}
}
// <<<<<<<<<<<<< runApp写法② <<<<<<<<<<<<<


class HelloWorldPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
//Scaffold是Material中主要的布局组件.
return new Scaffold(
appBar: new AppBar(
leading: new IconButton(
icon: new Icon(Icons.menu),
tooltip: 'Navigation menu',
onPressed: null,
),
title: new Text('MaterialApp Example title'),
actions: <Widget>[
new IconButton(
icon: new Icon(Icons.search),
tooltip: 'Search',
onPressed: null,
),
],
),
//body占屏幕的大部分
body: new Center(
child: new Text('Hello, world2!'),
),
floatingActionButton: new FloatingActionButton(
tooltip: 'Add', // used by assistive technologies
child: new Icon(Icons.add),
// 1、无方法
// 写法①
// onPressed: null,
// 写法②
// onPressed: () {}
// 写法③
// onPressed: () => {}

// 2、有方法,但该方法无参数
// 写法①
// onPressed: printLog,
// 写法②
// onPressed: () {
// printLog();
// },

// 3、有方法,且该方法有参数
// onPressed:() {
// printText("Hello world");
// }

// 4.页面跳转方式
// 写法①
// onPressed: () {
// goNextPage(context);
// },
// 写法②
// onPressed: () {
// Navigator.pushNamed(context, "new_page");
// },
// 写法③
onPressed: () {
Navigator.push(context, new MaterialPageRoute(builder: (context) {
return new NewRoute();
}));
},
)
);
}
}

void printLog() {
print("This is printLog Method");
}

void printText($text) {
print("The text is " + $text);
}

void goNextPage(context) {
// 导航到新路由
Navigator.push(context, new MaterialPageRoute(builder: (context) {
return new NewRoute();
}));
}
3.2、其中完整的NewRoute.dart代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import 'package:flutter/material.dart';

class NewRoute extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("New route"),
),
body: Center(
child: Text("This is new route"),
),
);
}
}

二、本节代码解释

1、MaterialApp的使用方式介绍

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// 写法①
import 'package:flutter/material.dart';

void main() {
runApp(new MaterialApp(
title: '1.MaterialApp in main',
home: new HelloWorldPage(),
));
}


// ------------------- 我是分割线,下面介绍的是另一种写法 ------------------- //
// 写法②
import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: '2.MaterialApp in MyApp',
home: HelloWorldPage(),
);
}
}

2、Scaffold的使用方式介绍

以创建一个新页面NewRoute.dart为例,该文件代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import 'package:flutter/material.dart';

class NewRoute extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("New route"),
),
body: Center(
child: Text("This is new route"),
),
);
}
}

3、文本Text以及按钮Button的使用介绍

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
class HelloWorldPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
//Scaffold是Material中主要的布局组件.
return new Scaffold(
appBar: new AppBar(
leading: new IconButton(
icon: new Icon(Icons.menu),
tooltip: 'Navigation menu',
onPressed: null,
),
title: new Text('MaterialApp Example title'),
actions: <Widget>[
new IconButton(
icon: new Icon(Icons.search),
tooltip: 'Search',
onPressed: null,
),
],
),
//body占屏幕的大部分
body: new Center(
child: new Text('Hello, world2!'),
),
floatingActionButton: new FloatingActionButton(
tooltip: 'Add', // used by assistive technologies
child: new Icon(Icons.add),
onPressed: null,
),
);
}
}

三、按钮Button

按钮的点击:略,请看前文

四、新页面的创建

以创建一个新页面NewRoute.dart为例,该文件代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import 'package:flutter/material.dart';

class NewRoute extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("New route"),
),
body: Center(
child: Text("This is new route"),
),
);
}
}

五、页面的跳转 & 路由的管理

页面的跳转,略。请看前文