先看一下效果图吧(图一):上面是android原生,下面是flutter页面

图一

好 让我们一步一步来

- 1.创建flutter module

在android项目同级的目录里按住shift+右键,然后选择在此处打开 Powershell窗口(s)。

//或者在dos里cd到指定目录也行

然后输入flutter create -t module my_flutter

创建好后目录如下(图二):

图二

- 2.配置android工程(将Flutter模块作为依赖添加到主项目)

settings.gradle文件里添加:

setBinding(new Binding([gradle: this]))

//我们的flutter目录

evaluate(new File(

settingsDir.parentFile,

'my_flutter/.android/include_flutter.groovy'

))

app目录的build.gradle下添加:

dependencies {

...

implementation project(':flutter')

}

添加之后同步下代码,然后我们就可以在android项目里调用flutter页面了

- 3.android添加flutter布局

改一下android:MainActivity.java里代码

class MainActivity : AppCompatActivity() {

override fun onCreate(savedInstanceState: Bundle?) {

super.onCreate(savedInstanceState)

// setContentView(R.layout.activity_main)

//获取flutterView

val flutterView = Flutter.createView(this, lifecycle, "route1")

setContentView(flutterView)

}

}

Flutter.createView方法里前两个参数是不变的,后面的"route1"可以获取指定的flutter页面,后面讲

现在我们先运行一下看一下效果。。。

运行的时候报了个错误(图三):

图三

需要在app目录的build.gradle下指定下jdk版本:

android {

...

compileOptions {

sourceCompatibility JavaVersion.VERSION_1_8

targetCompatibility JavaVersion.VERSION_1_8

}

}

再同步下,就可以运行了,运行效果(图四):

图四

获取flutterView还有一种方法:

//获取flutterView 第二种方法

val tx = supportFragmentManager.beginTransaction()

//第一个参数填入flutterView要存放的布局id

tx.replace(R.id.---, Flutter.createFragment("route1"))

tx.commit()

这两种方法都设置了"route1"这个参数,我们来看一下这个参数在flutter里怎么用吧:

修改flutter main.dart里代码:

import 'dart:ui';

import 'package:flutter/material.dart';

void main() => runApp(_widgetForRoute(window.defaultRouteName));

Widget _widgetForRoute(String route) {

switch (route) {

case 'route1':

return MyApp1();

break;

default:

return MyApp();

break;

}

}

class MyApp extends StatelessWidget {

@override

Widget build(BuildContext context) {

return MaterialApp(

home: Scaffold(

appBar: AppBar(

title: Text('MyApp'),

),

),

);

}

}

class MyApp1 extends StatelessWidget {

@override

Widget build(BuildContext context) {

return MaterialApp(

home: Scaffold(

appBar: AppBar(

title: Text('MyApp1'),

),

),

);

}

}

这里的window需要导包,现在知道那个参数的作用了吧,我们可以根据那个参数跳转不同的flutter页面

到这里android和flutter的基础配置就结束了,接下来我们进行数据传递

- 4.数据传递

写之前我们先修改下android activity_main.xml的布局(图五):

图五

MainActivity.java:

class MainActivity : AppCompatActivity() {

override fun onCreate(savedInstanceState: Bundle?) {

super.onCreate(savedInstanceState)

setContentView(R.layout.activity_main)

//获取flutterView

val flutterView = Flutter.createView(this, lifecycle, "route1")

llMainBottom.addView(flutterView)

}

}

flutter页面的布局也修改下:

import 'dart:ui';

import 'package:flutter/material.dart';

void main() => runApp(_widgetForRoute(window.defaultRouteName));

Widget _widgetForRoute(String route) {

switch (route) {

case 'route1':

return MyApp1();

break;

default:

return MyApp();

break;

}

}

//App

class MyApp extends StatelessWidget {

@override

Widget build(BuildContext context) {

return MaterialApp(

home: Scaffold(

appBar: AppBar(

title: Text('MyApp'),

),

),

);

}

}

//App1

class MyApp1 extends StatefulWidget {

@override

_MyApp1State createState() => _MyApp1State();

}

class _MyApp1State extends State {

String _text = '你好 世界!';

@override

Widget build(BuildContext context) {

return MaterialApp(

home: Scaffold(

body: Stack(

alignment: FractionalOffset(0.5, 0.95),

children: [

Center(

child: Text(_text),

),

RaisedButton(

child: Text('修改android'),

onPressed: () {

},

),

],

),

),

);

}

}

运行效果就和我们最上面的一样了,这里就不贴了,传输数据Flutter向我们提供了3个方法:

-MethodChannel

- EventChannel

- BasicMessageChannel

我这边示例一下MethodChannel的使用,其他两种方法有点类似

我们点击android按钮,然后传输数据到flutter那边

android发送:

//发送msg给flutters

MethodChannel(flutterView, "com.yang.test001").invokeMethod("android","Hello World!")

注:

"com.yang.test001"相当于唯一标识,flutter那边接受用

invokeMethod方法里传的是键值对,flutter接受时可根据key取值

flutter 接收:

@override

void initState() {

super.initState();

MethodChannel('com.yang.test001').setMethodCallHandler((handler) {

//根据key判断android传过来的值

switch (handler.method) {

case 'android':

setState(() {});

var msg = handler.arguments;

_text = msg.toString();

break;

}

});

}

在initState方法里进行监听,然后根据key进行判断,再setState(() {});改变下值就ok了

android接受flutter的值同理...

当我们android项目混合了flutter后,可以进行热重载(我这边测试只能更改flutter代码才有效果)

注:进入我们创建的my_flutter目录里,再shift+右键,然后选择在此处打开 Powershell窗口(s),然后输入:

flutter attach

会看到如下界面(图六):

图六

然后在android工程里启动我们的app(图七):

图七

启动后在shell窗口会看到如下信息(图八):

图八

之后修改flutter代码,在终端输入r就可以热重载了,R是热重启。没用的话先输入一遍R,再输入r,应该就可以看到效果了,再没用就反复多试试,感觉有点延迟,还有只能重载flutter代码,所以用处嘛,就一丢丢而已了。。

所有的代码也贴一下吧:

android:

class MainActivity : AppCompatActivity() {

private lateinit var mMethodChannel: MethodChannel //flutter连接

private val METHOD_CHANNER = "com.yang.test001" //与flutter连接的标识

private var mIsSendFlutter = false

override fun onCreate(savedInstanceState: Bundle?) {

super.onCreate(savedInstanceState)

setContentView(R.layout.activity_main)

initView()

initListener()

}

private fun initView() {

//绑定flutterView 第一种方法

val flutterView = Flutter.createView(this, lifecycle, "route1")

llMainBottom.addView(flutterView)

// //第二种方法

// val tx = supportFragmentManager.beginTransaction()

// tx.replace(R.id.llMainBottom, Flutter.createFragment("route1"))

// tx.commit()

//初始化MethodChannel

mMethodChannel = MethodChannel(flutterView, METHOD_CHANNER)

}

private fun initListener() {

//接受flutter消息监听

mMethodChannel.setMethodCallHandler(object : MethodChannel.MethodCallHandler {

override fun onMethodCall(p0: MethodCall, p1: MethodChannel.Result) {

//根据收到的消息key进行接收

when (p0.method) {

"flutter" -> {

val msg = p0.arguments

tvMain.text = msg.toString()

}

else -> {

}

}

}

})

btnMain.setOnClickListener {

//发送msg给flutter

mMethodChannel.invokeMethod("android", if (mIsSendFlutter) {

"你好 世界!"

} else {

"Hello World!"

})

mIsSendFlutter = !mIsSendFlutter

}

}

}

flutter:

import 'dart:ui';

import 'package:flutter/material.dart';

import 'package:flutter/services.dart';

void main() => runApp(_widgetForRoute(window.defaultRouteName));

Widget _widgetForRoute(String route) {

switch (route) {

case 'route1':

return MyApp1();

break;

default:

return MyApp();

break;

}

}

//App1

class MyApp1 extends StatefulWidget {

@override

_MyApp1State createState() => _MyApp1State();

}

class _MyApp1State extends State {

MethodChannel _methodChannel = MethodChannel('com.yang.test001'); //与android连接

String _text = '你好 世界!';

bool _isSendAndroid = false;

@override

void initState() {

super.initState();

_methodChannel.setMethodCallHandler(_handler);

}

//接收android监听

Future _handler(MethodCall call) {

switch (call.method) {

case 'android':

setState(() {});

var msg = call.arguments;

_text = msg.toString();

break;

}

}

//发送消息给android

void _sendMessage() {

//flutter 相当于key 后面是内容

_methodChannel.invokeListMethod(

'flutter', _isSendAndroid ? 'Hello World!' : '你好 世界!');

_isSendAndroid = !_isSendAndroid;

}

@override

Widget build(BuildContext context) {

return MaterialApp(

home: Scaffold(

body: Stack(

alignment: FractionalOffset(0.5, 0.95),

children: [

Center(

child: Text(_text),

),

RaisedButton(

child: Text('修改android'),

onPressed: () {

_sendMessage();

},

),

],

),

),

);

}

}

//默认App

class MyApp extends StatelessWidget {

@override

Widget build(BuildContext context) {

return MaterialApp(

home: Scaffold(

body: Center(

child: Text('myApp'),

),

),

);

}

}

Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐