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布局文件修改如下:

<LinearLayout
        android:orientation="vertical"
        android:gravity="center"
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent" >

    <Button
            android:id="@+id/btn_jump_f1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="跳转到到flutter界面 1 "
            android:textAllCaps="false"/>

    <Button
            android:id="@+id/btn_jump_f2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="跳转到到flutter界面 2 "
            android:textAllCaps="false"/>

</LinearLayout>

在MainActivity中为两个按钮添加点击跳转事件:

btn_jump_f1.setOnClickListener {
    startActivity<FlutterActivity>("pager" to 1)
}

btn_jump_f2.setOnClickListener {
    startActivity<FlutterActivity>("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<FlutterActivity>("pager" to 2) 需要在build.gradle中添加依赖

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<PagerOne> {
  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: <Widget>[
            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<PagerTwo> {

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("pager 2"),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            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<String>("android")
}

在flutter端设置发送的方法:

class _PagerTwoState extends State<PagerTwo> {

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("pager 2"),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            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<Object> _stream ,此用法与Android 的广播类似,在使用结束的时候需要在 dispose() 方法中调用 _stream?.cancel();来释放StreamSubscription

class _PagerThreeState extends State<PagerThree> {
  
  String content="this is pager 3";

  StreamSubscription<Object> _stream;
  
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("pager 3"),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text("EventChannel 接收来自 Android的消息"),
            Text( content, ),
          ],
        ),
      ),
    );
  }
  
  @override
  void initState() {
    // TODO: implement initState
    super.initState();
    //除了 _onData 后面的三个参数可不传
    _stream = EventChannel("send_to_flutter").receiveBroadcastStream().listen(_onData,onError: _onError,onDone: _onDown,cancelOnError: true);

  }

  void _onData(Object object){
    setState(() {
      content=object.toString();
    });
  }

  void _onError(Object object){

  }

  void _onDown(){

  }

  @override
  void dispose() {
    // TODO: implement dispose
    super.dispose();
    if(_stream!=null){
      _stream?.cancel();
    }
  }
}

运行示例:

需要注意的地方是 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<PagerFour> {

  String content="this is pager 4";

  BasicMessageChannel<String> _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: <Widget>[
            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

 

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值