flutter 与 android 混合开发 以及 Android与flutter之间的通信
之前我们分享过flutter的app开发,不过那是单纯的flutter开发,实际使用中因为flutter通用与Android与IOS所以一般采用的应该是Android与flutter的混合的开发。
今天作此笔记,记录 Android 与 flutter 混合开发的 的记录,以及测试Android与flutter之间的通信方式。
目录
一、Android与flutter混合开发
二、Android 与 flutter 之间的消息通信
2.1、MethodChannel 方式传递信息(单向)
2.2 EventChannel 方式传递信息(单项)
2.3 BasicMeaageChannel 方式传递消息(双向的)
一、Android与flutter混合开发
首先我们在Android studio 中新建一个Android项目(此处使用的 kotlin)。
Android 项目新建完成之后,我们新建一个flutter项目,new->new flutter project,选中 flutter module
当flutter项目构建好了之后,我们在Android项目中以module导入flutter项目。new->new module,选中 import flutter module,点击next选则我们刚才新建的flutter module
然后等待项目构建完成。
完成之后我们看以下项目中的一些变化 ,首先是 app下面的build.gradle增加了依赖
settings.gradle增加了setBinding
在项目的目录中也有flutter的依赖,与Android的module相同。
module已经导入了,接下来我们需要从Android中集成flutter的页面了。为了便于观察我们新建一个 FlutterActivity 来加载flutter部分,MainActivity 作为原生的界面跳转入口。
在MainActivity中添加两个按钮用来跳转,xml布局文件修改如下:
在MainActivity中为两个按钮添加点击跳转事件:
btn_jump_f1.setOnClickListener { startActivity("pager" to 1)}btn_jump_f2.setOnClickListener { startActivity("pager" to 2)}
FlutterActivity 的代码如下
class FlutterActivity :AppCompatActivity(){ @SuppressLint("SetTextI18n") override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_flutter) //创建flutter view val flutterView=Flutter.createView(this,lifecycle,"addflutter") val params = LinearLayout.LayoutParams( LinearLayout.LayoutParams.MATCH_PARENT , LinearLayout.LayoutParams.MATCH_PARENT ) linear_flutter.addView(flutterView,params) }
注意:使用 startActivity
implementation 'org.jetbrains.anko:anko:0.10.4'
还需要修改 build.gradle 中的 minSdkVersion 修改为 26否则运行程序的时候会报错
Error: Invoke-customs are only supported starting with Android O (--min-api 26)
运行之后的界面:
‘
上右图可以看到典型的flutter新项目的界面图:
我们实现了flutter的页面的加载。在创建flutterview的时候我们给出了3个参数 activity , lifecycle ,name 。其中 name 是作为一个标识参数在传递到flutter页面之后,我们可以根据这个值来区分我们加载的页面。flutter端获取此值的代码为:window.defaultRouteName
首先我们在跳转到FlutterActivity页面时 携带的参数 pager 是不同的,可以根据这个值来区分flutter加载不同的页面,修改flutter端的代码:
void main() => runApp(MyApp(route: window.defaultRouteName,));class MyApp extends StatelessWidget { // This widget is the root of your application. String route; MyApp({this.route}); @override Widget build(BuildContext context) { return MaterialApp( title: "flutter_pager", home: _getHomeByRoute(), ); } Widget _getHomeByRoute(){ switch(route){ case "pager1": return PagerOne(title: route,); default: return PagerTwo(title: route,); } }}class PagerOne extends StatefulWidget { PagerOne({Key key, this.title}) : super(key: key); final String title; @override _PagerOneState createState() => _PagerOneState();}class _PagerOneState extends State { int _counter = 0; void _incrementCounter() { setState(() { _counter++; }); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text("this is pager 1"), ), body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Text( 'this is pager 1', ), Text( '$_counter', style: Theme.of(context).textTheme.display1, ), ], ), ), floatingActionButton: FloatingActionButton( onPressed: _incrementCounter, tooltip: 'Increment', child: Icon(Icons.add), ), // This trailing comma makes auto-formatting nicer for build methods. ); }}class PagerTwo extends StatefulWidget { PagerTwo({Key key, this.title}) : super(key: key); final String title; @override _PagerTwoState createState() => _PagerTwoState();}class _PagerTwoState extends State { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text("pager 2"), ), body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Text( 'this is pager 2', ), ], ), ), ); }}
flutter端将根据 window.defaultRouteName 获取的字符串来决定加载 PagerOne 或者 PagerTwo.修改Android端FlutterActivity的代码为:
class FlutterActivity :AppCompatActivity(){ @SuppressLint("SetTextI18n") override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_flutter) val index=intent.getIntExtra("pager",1); tv_mark.text="${tv_mark.text} pager=$index" val pager= if(index==1){ "pager1" }else{ "pager2" } //创建flutter view val flutterView=Flutter.createView(this,lifecycle,pager) val params= LinearLayout.LayoutParams( LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.MATCH_PARENT) linear_flutter.addView(flutterView,params) }}
运行代码的示例:
页面没做美化看起来可能比较丑,不过我们现在只是为了实现根据参数加载不同页面的效果而已,功能已经实现了,接下来我们开始实现 Android与flutter的消息互发。
二、Android 与 flutter 之间的消息通信
2.1、MethodChannel 方式传递信息(单向)
此方式是 把 Android 作为接受方,flutter 作为发送方。首先我们需要在Android 端注册 MethodChannel
MethodChannel(flutterView,"accept_from_flutter") .setMethodCallHandler { methodCall, result -> Log.d("+++++++++++",methodCall.method) tv_accept_from_flutter.text=methodCall.argument("android")}
在flutter端设置发送的方法:
class _PagerTwoState extends State { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text("pager 2"), ), body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Text( 'this is pager 2', ), RaisedButton( child: Text("MethodChannel 给Android发送消息"), onPressed: (){ _methodChannelSendMessageToAndroid(); }, ), ], ), ), ); } //消息发送 void _methodChannelSendMessageToAndroid() async { var result=await MethodChannel("accept_from_flutter").invokeMapMethod("option",{"android":"我是MethodChanner flutter给android发送的消息"}); }}
运行示例
需要注意的地方是 Android端的 MethodChannel(flutterview,name)与flutter端MethodChannel(name),两个方法中的name必须相同,下面涉及到的其他消息发送方式也需要注意此项
2.2 EventChannel 方式传递信息(单项)
此方式是把Android 作为信息发送方,首先需要在Android 端设置EventChannel 的异步发送方法,并且需要把EventChannel.StreamHandler中的onListen方法中的 eventSink 参数传递到外界,因为我们需要使用 eventSink.success来发送消息。
class FlutterSendActivity :AppCompatActivity(){ var eventSink:EventChannel.EventSink?=null @SuppressLint("SetTextI18n") override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_flutter_send) //创建flutter view val flutterView=Flutter.createView(this,lifecycle,"pager3") val params= LinearLayout.LayoutParams( LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.MATCH_PARENT) linear_flutter.addView(flutterView,params) EventChannel(flutterView,"send_to_flutter") .setStreamHandler(object:EventChannel.StreamHandler{ override fun onListen(p0: Any?, event: EventChannel.EventSink?) { eventSink=event } override fun onCancel(p0: Any?) { print("++++++++++++++++") } }) btn_send_to_flutter.setOnClickListener { eventSink!!.success("这是Android发送给flutter的消息") } }}
在flutter 端我们需要设置同样的EventChannel 用来接受消息。接收信息的方法为EventChannel("send_to_flutter").receiveBroadcastStream().listen()来接受消息,此用法的返回值是StreamSubscription
class _PagerThreeState extends State { String content="this is pager 3"; StreamSubscription
运行示例:
需要注意的地方是 Android端的 EventChannel(flutterview,name)与flutter端EventChannel(name),两个方法中的name必须相同,下面涉及到的其他消息发送方式也需要注意此项
2.3 BasicMeaageChannel 方式传递消息(双向的)
Android端同样需要注册接收方法
class FlutterBasicMessageChannelActivity :AppCompatActivity(){ @SuppressLint("SetTextI18n") override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_flutter_basic) //创建flutter view val flutterView=Flutter.createView(this,lifecycle,"pager4") val params= LinearLayout.LayoutParams( LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.MATCH_PARENT) linear_flutter.addView(flutterView,params) val basicChannel=BasicMessageChannel(flutterView,"basicChannel", StringCodec.INSTANCE) //BasicMessageChannel 接受消息方法 basicChannel.setMessageHandler { string, reply -> tv_info_from_flutter.text=string } btn_send_to_flutter.setOnClickListener { //BasicMessageChannel 发送消息方法 basicChannel.send("我是BasicMessageChannel Android 发给 flutter的消息") } }}
flutter端同样需要注册
class PagerFour extends StatefulWidget { PagerFour({Key key, this.title}) : super(key: key); final String title; @override _PagerFourState createState() => _PagerFourState();}class _PagerFourState extends State { String content="this is pager 4"; BasicMessageChannel _basicMessageChannel=BasicMessageChannel("basicChannel", StringCodec()); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text("pager 4"), ), body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Text("BasicMessageChannel 接收来自 Android的消息"), Text( content, ), RaisedButton( child: Text("BasicMessageChannel 给 Android发送消息"), onPressed: (){ _sendMessageToAndroid(); }, ) ], ), ), ); } @override void initState() { // TODO: implement initState super.initState(); //BasicMessageChannel的消息接受方法 _basicMessageChannel.setMessageHandler((str){ setState(() { content=str; }); }); } //发送方法 void _sendMessageToAndroid(){ _basicMessageChannel.send("我是 BasicMessageChannel 给Android的发送消息"); }}
运行示例:
需要注意的地方是 Android端的 BasicMessageChannel(flutterview,name)与flutter端BasicMessageChannel(name),两个方法中的name必须相同.
现在Android与flutter的通信实现了,我们可以使用各种参数的传递来实现我们所需要功能了。
CSDN源码下载
示例程序百度网盘下载
链接:https://pan.baidu.com/s/1HYdJGPOexN-2RubpCdtN_g
提取码:0r2n
更多相关文章
- Android跨进程通信IPC之9——Binder之Framework层C++篇2
- Android跨进程通信IPC之9——Binder之Framework层C++篇1
- Android Studio导入第三方类库的方法
- Android消息循环
- android 的常标签和方法 android 初学者
- Android给TextView添加点击事件的实现方法
- 赢得争论的方法只有一个,那就是避免争论
- Android 高级进阶之深入剖析消息机制
- 详细介绍MvcPager分页控件使用的实例方法