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'

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

复制代码
dependencies {
	//...
	implementation project(':flutter')
}

添加完毕,我们切回 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()
  }
}

另外在项目的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()
  }
}

然后运行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>

点击跳转:

复制代码
   binding.fab.setOnClickListener { view ->
      //跳转flutter
      startActivity(
        FlutterActivity.createDefaultIntent(this)
      )
    }

你会发现跳转很慢,所以,我们用带有缓存引擎的初始路由来启动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);
  }

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

复制代码
 binding.fab.setOnClickListener { view ->
      //跳转flutter
      startActivity(
        FlutterActivity
          .withCachedEngine("my_engine_id")
          .build(this)
      );
    }

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

2、如何跳转不同的flutter页面?

在applation 的onCreate 初始化需要跳转的页面, 到我们的Application 中的onCreate添加:

复制代码
flutterEngine.getNavigationChannel().setInitialRoute("/test2");

然后修改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();
}
}

Test1是Test1.dart,代表不同的页面。当我们要跳转不同的页面,只要修改

flutterEngine.getNavigationChannel().setInitialRoute("/test2");就可以了,比如我们要跳转到Test3页面改成 flutterEngine.getNavigationChannel().setInitialRoute("/test3");

这个很简单,根据不同的标识,跳转对应的页面就行了。

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

BasicMsgChannel

EventChannel

MethodChannel

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发回给原生的消息
    }

flutter 接收:

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

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

原生接收:

复制代码
    basicMessageChannel.setMessageHandler { message, reply ->
      Log.d("ssz", "接收:$message")
    }

flutter 发送:

复制代码
      _basicMessageChannel.send("我是flutter的消息");

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调用")
        }
      }
    }

flutter 发送

复制代码
 const _methodChannel = MethodChannel('test2');
    _methodChannel.invokeListMethod("open");

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?) {
        }
      })

    }
  }

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);
    });

  }

最后呢,关于路由方面,有的业务可能需要跳转很多不同的页面,原生的方式不太友好,可以选择闲鱼开源的库 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

相关推荐
千里马学框架2 天前
一起学 Android 14:ShellTransition 屏幕旋转过程深度剖析
android·智能手机·性能优化·framework·性能·屏幕旋转·rotation
美狐美颜SDK开放平台2 天前
开发直播APP时如何接入视频美颜SDK?开发流程与注意事项
android·人工智能·计算机视觉·音视频·直播美颜sdk
AFinalStone2 天前
Android7 SystemUI源码解析(七)Keyguard锁屏模块深度解析
android·systemui
致远ccc2 天前
Google Play 上架前如何测试 App?多国家 Android 环境测试
android·app测试·googleplay·多国家应用测试
ttyyttemo2 天前
Kotlin 协程中的 Job 结构化并发与取消
android
sun0077002 天前
tbox 4g/5g切换,导致wan ip 改变,导致车机旧网络不可用。需要重启车机才行
android
其实防守也摸鱼2 天前
内网穿透与反向代理:原理、工具与实战指南
android·大数据·运维·安全·网络安全·自动化·渗透
AFinalStone2 天前
Android7 SystemUI 源码解析(四)NavigationBar 导航栏与 SystemBars
android·systemui
JMchen2 天前
属性动画原理与高级动画实现
android·kotlin·canvas
AFinalStone2 天前
Android7 SystemUI 源码解析(二)启动流程深度解析
android·systemui