• android 与 flutter 之间的通信


    文章目录

    • 前言
    • 集成 flutter 混合开发
    • android 与 flutter 之间的通信
    • 总结
    一、前言

    因为flutter 具有跨平台的属性,既可以在android上跑,也能在ios 上跑,所以为了节约开发的成本,减少人力,势必就会用到它。然而已有的项目部不太可能重新写,所以就需要进行混合开发。也就是在原生中集成flutter,进行混合开发。混合开发就会遇到原生和flutter的通信问题,今个就讲讲原生和flutter的通信。

    二、首先创建个flutter module,然后集成到app中

    1、在原生项目的父目录下,使用命令,创建flutter项目:
    flutter create -t module --org com.example flutter_demo
    在这里插入图片描述
    创建完毕,然后我们用as打开这个父目录,可以看到我们的flutter_demo 已经创建好了,如图:
    在这里插入图片描述
    2、在原生app里面的settings.gradle,include ‘:app’ 下面添加:

    setBinding(new Binding([gradle: this]))
    evaluate(new File(
        settingsDir.parentFile,
        'flutter_demo/.android/include_flutter.groovy'
    ))
    include ':flutter_demo'
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    3、在原生app下的build.gradle中添加依赖:

    dependencies {
    	//...
    	implementation project(':flutter')
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5

    添加完毕,我们切回 app的项目,运行会发现报错了。
    在这里插入图片描述
    报错是说flutterPlugin 没法用,这里在settings.gradle 将repositoriesMode改为:RepositoriesMode.PREFER_PROJECT。重新运行。
    如果还遇到第三方解析失败,添加maven:

    dependencyResolutionManagement {
      repositoriesMode.set(RepositoriesMode.PREFER_PROJECT)
      repositories {
        maven { url 'https://jitpack.io' }
        maven { url 'https://maven.aliyun.com/nexus/content/groups/public/' }
        maven { url 'https://maven.aliyun.com/repository/central' }
        maven { url 'https://maven.aliyun.com/nexus/content/repositories/google' }
        google()
        mavenCentral()
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    另外在项目的build.gradel 添加:

    allprojects {
      repositories {
        maven { url 'https://jitpack.io' }
        maven { url 'https://maven.aliyun.com/nexus/content/groups/public/' }
        maven { url 'https://maven.aliyun.com/repository/central' }
        maven { url 'https://maven.aliyun.com/nexus/content/repositories/google' }
        google()
        mavenCentral()
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    然后运行app,就可以了。如果你还有其他报错,切换到根目录,去检查下flutter_demo里头的这两个文件。打开main.dart,提示你Enable Dart support,点击它就可以。然后再打开 pubspec.yaml ,点击pub get 获取相应的依赖。确保flutter项目的环境和依赖库没问题。

    到这里,我们的flutter_demo 就集成到我们的app中了。接下来就是看android和flutter的通信

    三、android和flutter的通信

    上面的项目,每次要看flutter代码是不是每次都要切过来切过去的,所以呢,我们可以在setting.gradle 加上这么一行代码:
    project(‘:flutter_demo’).projectDir = new File(‘…/flutter_demo’)
    在这里插入图片描述
    这样,我们在app的项目中就能查看flutter的代码了。好了,我们最想知道的就是android 怎么打开 flutter页面。接这往下看。

    1、android 跳转 flutter:
    在清单AndroidManifest里面添加 FlutterActivity

        <activity android:name="io.flutter.embedding.android.FlutterActivity"
            android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
            android:hardwareAccelerated="true"
            android:windowSoftInputMode="adjustResize"
            >
        </activity>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    点击跳转:

       binding.fab.setOnClickListener { view ->
          //跳转flutter
          startActivity(
            FlutterActivity.createDefaultIntent(this)
          )
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    你会发现跳转很慢,所以,我们用带有缓存引擎的初始路由来启动FlutterActivity
    创建一个MyApplication 然后 在onCreate 中进行缓存引擎的初始化。

        // 创建一个Flutter引擎
        flutterEngine = new FlutterEngine(this);
    
        // 开始执行 Dart 代码来预热flutter引擎
        flutterEngine.getDartExecutor().executeDartEntrypoint(
          DartExecutor.DartEntrypoint.createDefault()
        );
    
        //缓存Flutter引擎用来开启FlutterActivity
        FlutterEngineCache
          .getInstance()
          .put("my_engine_id", flutterEngine);
      }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    这个我们就能使用缓存引擎跳转Flutter。

     binding.fab.setOnClickListener { view ->
          //跳转flutter
          startActivity(
            FlutterActivity
              .withCachedEngine("my_engine_id")
              .build(this)
          );
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    很明显立马就跳转过去了。

    2、如何跳转不同的flutter页面?
    在applation 的onCreate 初始化需要跳转的页面, 到我们的Application 中的onCreate添加:

    flutterEngine.getNavigationChannel().setInitialRoute("/test2");
    
    • 1

    然后修改main.dart 的代码:

    void main() => runApp(_widgetForRoute(window.defaultRouteName));
    
    Widget _widgetForRoute(String route) {
    switch (route) {
     case '/test1':
       return const Test1();
     case '/test2':
       return const Test2();
     case '/test3':
       return const Test3();
     default:
       return const Test1();
    }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    Test1是Test1.dart,代表不同的页面。当我们要跳转不同的页面,只要修改
    flutterEngine.getNavigationChannel().setInitialRoute(“/test2”);就可以了,比如我们要跳转到Test3页面改成 flutterEngine.getNavigationChannel().setInitialRoute(“/test3”);
    这个很简单,根据不同的标识,跳转对应的页面就行了。

    四、接下来,就是文章的主题,讲通信方式都有哪些?

    BasicMsgChannel
    MethodChannel
    EventChannel

    1、BasicMsgChannel 方式
    双向的,原生可以给flutter发送,然后flutter同时也可以返回信息给原生

    发送:

        val flutterEngine = MyApplication.flutterEngine
        val basicMessageChannel = BasicMessageChannel(
          flutterEngine.dartExecutor.binaryMessenger,
          "basicMessageChannel",
          StringCodec.INSTANCE
        )
        basicMessageChannel.send("通过basicMessageChannel发送消息"){
            message: String?->
          Log.d("ssz", "接收:$message") //message 是flutter发回给原生的消息
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    flutter 接收:

    _basicMessageChannel = const BasicMessageChannel('basicMessageChannel', StringCodec());
        _basicMessageChannel.setMessageHandler((String? message) => Future<String>((){
          setState(() {//刷新控件
            _basicMessage = "flutter接收了消息:${message!}";
          });
          return "flutter 收到了";//这里是返回信息给原生
        }));
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    我们也可以反过来,原生接收,flutter发送,如下:
    原生接收:

        basicMessageChannel.setMessageHandler { message, reply ->
          Log.d("ssz", "接收:$message")
        }
    
    • 1
    • 2
    • 3

    flutter 发送:

          _basicMessageChannel.send("我是flutter的消息");
    
    • 1

    2、MethodChannel 方法
    主要是flutter 调用原生

    原生接收:

    val methodChannel = MethodChannel(flutterEngine.dartExecutor.binaryMessenger, "test2")
        binding.btnTest2.setOnClickListener {
          toFlutter()
          methodChannel.setMethodCallHandler { call, result ->
            if (call.method.equals("open")){
              Log.d("ssz", "接收flutter调用")
            }
          }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    flutter 发送

     const _methodChannel = MethodChannel('test2');
        _methodChannel.invokeListMethod("open");
    
    • 1
    • 2

    3、EventChannel方法
    主要是原生发送给flutter,这个方法使用不当就会接受不到,谨慎使用。

    原生发送:

     val eventChannel = EventChannel(MyApplication.flutterEngine.dartExecutor.binaryMessenger, "test3")
        binding.btnTest3.setOnClickListener {
          toFlutter()
          eventChannel.setStreamHandler(object : StreamHandler{
            override fun onListen(arguments: Any?, events: EventSink?) {
              Log.d("ssz","执行了 onListen");
              events?.success("原生发送")
            }
            override fun onCancel(arguments: Any?) {
            }
          })
    
        }
      }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    flutter 接收

    void initState() {
        super.initState();
        Future.delayed(const Duration(milliseconds: 6000), () {//需要做个延迟,不然原生onListen会不执行,导致不能发送消息
          var eventChannel = const EventChannel("test3");
          eventChannel.receiveBroadcastStream().listen((dynamic event) {
            setState(() {
              _EventMessage = "flutter接收$event";
            });
          }, onError: (dynamic error){
            setState(() {
              _EventMessage = "flutter接收$error";
            });
          },cancelOnError: true);
        });
    
      }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    最后呢,关于路由方面,有的业务可能需要跳转很多不同的页面,原生的方式不太友好,可以选择闲鱼开源的库 https://github.com/alibaba/flutter_boost ,提高开发的效率。

    以上代码地址:https://github.com/shenshizhong/HybridFlutter

    总结

    总的来讲:
    1、android集成flutter,进行混合开发
    2、android 与 flutter 的通信
    3、使用第三方提高开发效率

    如果对你有一点点帮助,那是值得高兴的事情。:)
    我的csdn:http://blog.csdn.net/shenshizhong
    我的简书:http://www.jianshu.com/u/345daf0211ad

  • 相关阅读:
    深度优先搜索(DFS)和广度优先搜索(BFS)
    Android 插件化技术应运而生出的 Apk 动态加载技术的开源框架
    云计算时代改变了什么?
    Echarts图表中formatter的用法
    数据结构初相识
    JSP注释(多种注释详解)
    【Python学习笔记】超详细Python快速入门教程(上)
    ARFoundation系列讲解 - 89 适配华为机型
    Vue3:自定义图标选择器(包含 SVG 图标封装)
    [Unity]PostProcessing导入新场景报 NullReferenceException
  • 原文地址:https://blog.csdn.net/shenshizhong/article/details/133773820