第2节:Android项目集成Flutter

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

本节学习用时:3分钟

本节学习方式:动手实践


本节目录:

一、集成方式介绍

二、集成方法介绍

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


项目 CQInitProject

一、集成方式介绍

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

待补充。。。。。。。

第1节:ReactNative的Demo实践

ReactNative的Demo实践

一、工程创建

创建APP(iOS & Android)项目

1
react-native init TSDemoDemo

1、iOS工程

1
2
cd iOS项目
pod install

2、Android工程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
终端运行cd myProject切换到项目根目录中,
运行adb devices来确保有设备连接到了电脑上

运行react-native run-android打包编译安卓项目,并部署到模拟器或开发机中

运行上一条命令之前,要确保有设备连接到了电脑上,可以运行adb devices查看当前接入的设备列表;如果无法检查到设备列表,请先确保手机开启了开发者模式,同时要电脑上要安装手机的驱动程序;

注意:首次打包时候,会联网下载gradle相关的文件,需要等待很长时间,大家可以直接从http://www.androiddevtools.cn/手动下载对应版本的gradle文件,并手动拷贝解压到C:\Users\自己的用户名\.gradle\wrapper\dists目录下;

注意:接下来,如果是第一次打包,会从https://jcenter.bintray.com下载好多的依赖项,此时需要耐心等待,如果中间出现了长时间卡顿,大家需要Ctrl+C停止打包,并重新运行react-native run-android

作者:白小白大白白
链接:https://www.jianshu.com/p/ab8bf4128b0e
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

二、添加路由

参考文档

1
2
3
4
5
6
7
8
9
10
11

yarn add @react-navigation/native


yarn add react-native-reanimated react-native-gesture-handler react-native-screens react-native-safe-area-context @react-native-community/masked-view

③在iOS工程中,重新 pod install


④接下来,因为从React Navigation4.x版本开始,堆栈导航库就已经被分离出来,作为单独的依赖文件,所以要想添加StackNavigator的依赖
yarn add @react-navigation/stack

三、

参考文章:

四、发布

1
2
3
4
5
npm config get registry

npm login

npm publish --access=public

详情查看:代码管理/库管理/npmjs/npmjs的发布

第四章:Flutter登录页实战

前言

本章介绍

  • ①通过Flutter构建适用于多平台的登录页,并在Flutter工程中建立提供给原生项目的方法及接收从原生项目返回的值。
  • ②原生iOS项目使用Flutter实现的登录页时候的交互代码编写
  • ③原生Android使用Flutter实现的登录页时候的交互代码编写

点击此处,进入本章第1节的正式学习 >

第2节:交互时iOS端的代码编写

本节学习内容:原生iOS项目在交互时的代码编写。

本节学习用时:30分钟

本节学习方式:动手实践


本节目录:

一、本节内容介绍

二、本节代码解释


一、本节内容介绍

略!

二、本节代码解释

1、本节代码

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
- (void)showMainFlutterViewControllerWithoutParam {
self.navigationController.navigationBarHidden = YES;

FlutterViewController *flutterViewController = [[FlutterViewController alloc] initWithProject:nil nibName:nil bundle:nil];

NSString *channelName = @"com.dvlproad.ciyouzen/platform_channel";// 要与.dart中一致
FlutterMethodChannel *messageChannel = [FlutterMethodChannel methodChannelWithName:channelName binaryMessenger:flutterViewController];

[messageChannel setMethodCallHandler:^(FlutterMethodCall * _Nonnull call, FlutterResult _Nonnull result) {
// call.method获取flutter给回到的方法名,要匹配到channelName对应的多个 发送方法名,一般需要判断区分
// call.arguments获取到flutter给到的参数,(比如跳转到另一个页面所需要参数)
// result是给flutter的回调,只能回调一次
NSString *message = [NSString stringWithFormat:@"flutter回调:\n nmethod = %@\n arguments = %@", call.method, call.arguments];
NSLog(@"%@", message);

if ([call.method isEqualToString:@"showToast"]) {
[CJToast shortShowMessage:message];
return;

} else if ([call.method isEqualToString:@"goBack"]) {
[self.navigationController popViewControllerAnimated:YES];
return;

} else if ([call.method isEqualToString:@"goiosPage"]) {
OCCallFlutterViewController *viewController = [[OCCallFlutterViewController alloc] init];
viewController.parames = call.arguments;
[self.navigationController pushViewController:viewController animated:YES];
return;

} else if ([call.method isEqualToString:@"changeLeftBarButtonAction"]) {
NSDictionary *params = @{@"imageName":@"lib/Resources/message_arrow.png"};
result(params);
return;
}

result(FlutterMethodNotImplemented);
}];

[self.navigationController pushViewController:flutterViewController animated:YES];
}

第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
)
],
)

),
);
}
}