-
先看一下效果圖吧(圖一):
上面是android原生攒读,下面是flutter頁面
圖一 好 讓我們一步一步來
- 1.創(chuàng)建flutter module
在android項(xiàng)目同級的目錄里按住shift+右鍵
遮斥,然后選擇在此處打開 Powershell窗口(s)
怠噪。
//或者在dos里cd到指定目錄也行
然后輸入flutter create -t module my_flutter
創(chuàng)建好后目錄如下(圖二):
- 2.配置android工程(將Flutter模塊作為依賴添加到主項(xiàng)目)
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項(xiàng)目里調(diào)用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方法里前兩個參數(shù)是不變的,后面的"route1"
可以獲取指定的flutter頁面鞠绰,后面講
現(xiàn)在我們先運(yùn)行一下看一下效果厢洞。。西饵。
-
運(yùn)行的時候報了個錯誤(圖三):
圖三
需要在app目錄的build.gradle
下指定下jdk版本:
android {
...
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
}
再同步下酝掩,就可以運(yùn)行了,運(yùn)行效果(圖四):
獲取flutterView還有一種方法:
//獲取flutterView 第二種方法
val tx = supportFragmentManager.beginTransaction()
//第一個參數(shù)填入flutterView要存放的布局id
tx.replace(R.id.---, Flutter.createFragment("route1"))
tx.commit()
這兩種方法都設(shè)置了"route1"
這個參數(shù)眷柔,我們來看一下這個參數(shù)在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需要導(dǎo)包期虾,現(xiàn)在知道那個參數(shù)的作用了吧,我們可以根據(jù)那個參數(shù)跳轉(zhuǎn)不同的flutter頁面
- 到這里android和flutter的基礎(chǔ)配置就結(jié)束了驯嘱,接下來我們進(jìn)行數(shù)據(jù)傳遞
- 4.數(shù)據(jù)傳遞
寫之前我們先修改下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<MyApp1> {
String _text = '你好 世界镶苞!';
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: Stack(
alignment: FractionalOffset(0.5, 0.95),
children: <Widget>[
Center(
child: Text(_text),
),
RaisedButton(
child: Text('修改android'),
onPressed: () {
},
),
],
),
),
);
}
}
運(yùn)行效果就和我們最上面的一樣了,這里就不貼了鞠评,傳輸數(shù)據(jù)Flutter向我們提供了3個方法:
-MethodChannel
-EventChannel
-BasicMessageChannel
我這邊示例一下MethodChannel
的使用茂蚓,其他兩種方法有點(diǎn)類似我們點(diǎn)擊android按鈕,然后傳輸數(shù)據(jù)到flutter那邊
android發(fā)送:
//發(fā)送msg給flutters
MethodChannel(flutterView, "com.yang.test001").invokeMethod("android","Hello World!")
注
:
-
"com.yang.test001"
相當(dāng)于唯一標(biāo)識剃幌,flutter那邊接受用 -
invokeMethod
方法里傳的是鍵值對聋涨,flutter接受時可根據(jù)key取值
flutter 接收:
@override
void initState() {
super.initState();
MethodChannel('com.yang.test001').setMethodCallHandler((handler) {
//根據(jù)key判斷android傳過來的值
switch (handler.method) {
case 'android':
setState(() {});
var msg = handler.arguments;
_text = msg.toString();
break;
}
});
}
在initState
方法里進(jìn)行監(jiān)聽,然后根據(jù)key進(jìn)行判斷负乡,再setState(() {});
改變下值就ok了
android接受flutter的值同理...
- 當(dāng)我們android項(xiàng)目混合了flutter后牍白,可以進(jìn)行熱重載(我這邊測試只能更改flutter代碼才有效果)
注
:進(jìn)入我們創(chuàng)建的my_flutter
目錄里,再shift+右鍵
抖棘,然后選擇在此處打開 Powershell窗口(s)
茂腥,然后輸入:
flutter attach
會看到如下界面(圖六):
然后在android工程里啟動我們的app(圖七):
啟動后在shell窗口會看到如下信息(圖八):
之后修改flutter代碼,在終端輸入r
就可以熱重載了切省,R
是熱重啟最岗。沒用的話先輸入一遍R
,再輸入r
朝捆,應(yīng)該就可以看到效果了仑性,再沒用就反復(fù)多試試,感覺有點(diǎn)延遲,還有只能重載flutter代碼诊杆,所以用處嘛,就一丟丟而已了歼捐。。
- 所有的代碼也貼一下吧:
android
:
class MainActivity : AppCompatActivity() {
private lateinit var mMethodChannel: MethodChannel //flutter連接
private val METHOD_CHANNER = "com.yang.test001" //與flutter連接的標(biāo)識
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消息監(jiān)聽
mMethodChannel.setMethodCallHandler(object : MethodChannel.MethodCallHandler {
override fun onMethodCall(p0: MethodCall, p1: MethodChannel.Result) {
//根據(jù)收到的消息key進(jìn)行接收
when (p0.method) {
"flutter" -> {
val msg = p0.arguments
tvMain.text = msg.toString()
}
else -> {
}
}
}
})
btnMain.setOnClickListener {
//發(fā)送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<MyApp1> {
MethodChannel _methodChannel = MethodChannel('com.yang.test001'); //與android連接
String _text = '你好 世界豹储!';
bool _isSendAndroid = false;
@override
void initState() {
super.initState();
_methodChannel.setMethodCallHandler(_handler);
}
//接收android監(jiān)聽
Future<dynamic> _handler(MethodCall call) {
switch (call.method) {
case 'android':
setState(() {});
var msg = call.arguments;
_text = msg.toString();
break;
}
}
//發(fā)送消息給android
void _sendMessage() {
//flutter 相當(dāng)于key 后面是內(nèi)容
_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: <Widget>[
Center(
child: Text(_text),
),
RaisedButton(
child: Text('修改android'),
onPressed: () {
_sendMessage();
},
),
],
),
),
);
}
}
//默認(rèn)App
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: Center(
child: Text('myApp'),
),
),
);
}
}