文章目录
因为flutter 具有跨平台的属性,既可以在android上跑,也能在ios 上跑,所以为了节约开发的成本,减少人力,势必就会用到它。然而已有的项目部不太可能重新写,所以就需要进行混合开发。也就是在原生中集成flutter,进行混合开发。混合开发就会遇到原生和flutter的通信问题,今个就讲讲原生和flutter的通信。
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的通信
上面的项目,每次要看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
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发回给原生的消息
}
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