如需转载,请注明出处:Flutter学习笔记(30)--Android原生与Flutter混编

这篇文章旨在学习如何在现有的Android原生项目上集成Flutter,实现Android与Flutter的混编,文章主体内容分为5部分,如下:

  • Android项目如何集成FlutterModule

  • Flutter视图是如何展示到前台界面的

  • Flutter与Weex对比

  • 如何进行原生页面跳转到Flutter页面

  • 原生如何与Flutter进行传值通信(以EventChannel为例说明)

接下来我会按照上面列出来的5点,逐一的进行实例讲解说明

1.Android项目如何集成FlutterModule

Android原生项目集成Flutter有两种方式,一种是在原生项目内集成FlutterModule,还有一种是将FLutter项目打包成arr文件,然后以组件的形式被原生项目依赖。这里我们就只说一下在原生项目内集成FlutterModule。

第一步:在主工程下创建FlutterModule,File->New->New Flutter Project,然后选择Flutter Module点击Next。

设置完成之后点击Finish,创建完module后我们来看一下工程的目录结构

第二步:在app下的build.gradle添加依赖

    //在android下添加jdk1.8支持
compileOptions {
sourceCompatibility 1.8
targetCompatibility 1.8
} //在dependencies下添加flutter依赖
implementation project(':flutter')
implementation 'android.arch.lifecycle:runtime:1.1.0'
implementation 'android.arch.lifecycle:extensions:1.1.0'

第三步:在根目录下的settings.gradle添加配置

setBinding(new Binding([gradle: this]))
evaluate(new File(
settingsDir.parentFile,
'AndroidProject/flutter_module/.android/include_flutter.groovy'
))

最后同步一下,将相关的依赖下载下来,至此就成功集成了FlutterModule了。

2.Flutter视图是如何展示到前台界面的

其实Flutter视图是以View的形式添加到原生页面中的,这个和weex很像,简单的来说就是我们首先要通过某一个方法来创建一个Flutter的视图,然后在原生的Activity中创建一个容器,这个容器的作用就是来装载我们Flutter的视图,最后我们将Flutter的View添加到容器里面就可以了。接下来我们看一下实现的代码。

package com.example.flutterdemo;

import android.os.Bundle;
import android.view.View;
import android.widget.FrameLayout; import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity; import io.flutter.facade.Flutter;
import io.flutter.view.FlutterView; public class MyFlutterActivity extends AppCompatActivity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_flutter);
//创建一个FlutterView
final FlutterView flutterView = Flutter.createView(this, getLifecycle(), "route1");
//实例化容器
final FrameLayout layout = findViewById(R.id.flutter_container);
//将FlutterView添加到容器中去
layout.addView(flutterView);
//解决原生页面跳转Flutter页面黑屏的问题(原理就是先让界面隐藏,等第一帧绘制完成后,再让他显示出来)
final FlutterView.FirstFrameListener[] listeners = new FlutterView.FirstFrameListener[];
listeners[] = new FlutterView.FirstFrameListener() {
@Override
public void onFirstFrame() {
layout.setVisibility(View.VISIBLE);
}
};
flutterView.addFirstFrameListener(listeners[]);
}
}

xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent"> <FrameLayout
android:id="@+id/flutter_container"
android:layout_width="match_parent"
android:layout_height="match_parent"></FrameLayout>
</LinearLayout>

特别说一下创建Flutter视图这一块Flutter.createView(this, getLifecycle(), "route1");,createView中传了3个参数,前两个就不说了,重点说一下最后一个参数,最后一个参数大家可以理解为原生跳转到第一个Flutter页面的路由,可能有的人还是不理解是什么意思,我举一个例子来说明一下就会理解了。

通常我们的Flutter页面肯定不止一个,也许有很多情况下,原生要跳转到不同的Flutter页面,但是我们Flutter的入口只有这一个,那么我们要如何跳转到指定的Flutter页面呢?这时候createView的最后一个参数就发挥作用,因为我们在Flutter工程的main入口,可以获取到这个参数,进而我们就可以根据这个参数来跳转到不同的Flutter页面了。看一下Flutter的代码感受一下。

void main() => runApp(_MainEntrance(window.defaultRouteName));

Widget _MainEntrance(String defaultRouteName) {
print(defaultRouteName);
switch (defaultRouteName){
case 'flutter_main':
return new Center(
child: SettingPage(),
);
case 'other':
return new Center(
child: defaultPage(),
);
}
}
window.defaultRouteName这个方法会获取到原生中createView传递过来的第三个参数,我们可以通过一个switch语句来控制不同的路由来跳转到不同的页面。即:第三个参数为flutter_main跳转到设置页面。第三个参数为other跳转到默认页面。

3.Flutter与Weex对比

在上面第2条我们说到了原生加载Flutter视图和Weex很像,那么weex又是怎样的呢?

在weex中,也是需要我们来创建一个原生的容器用来装载weex的view视图,如我们新建一个WeexActivity实现IWXRenderListener,重写onViewCreated,在onViewCreated中系统会返回给我们一个创建好的weex的view,我们需要做的只需要将这个view添加到原生的容器中即可。

总的来说很像是因为Flutter和Weex对于Android或者iOS来说都是透明的,平台只会认为整个Flutter展示的内容是一个view,所以,Flutter视图都是以view的形式来添加到我们的原生项目中。

4.如何进行原生页面跳转到Flutter页面

这块就很简单了,前面我们已经说了,Flutter页面是以view的形式添加到我们的原生项目中的,那么我想要跳转到Flutter页面就只需要跳转到这个容器就好了

package com.example.flutterdemo;

import androidx.appcompat.app.AppCompatActivity;

import android.content.Intent;
import android.os.Bundle;
import android.view.View; public class MainActivity extends AppCompatActivity { @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
findViewById(R.id.mButton).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent();
intent.setClass(MainActivity.this, MyFlutterActivity.class);
startActivity(intent);
}
});
}
}

xml:

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity"> <Button
android:id="@+id/mButton"
android:layout_width="200dp"
android:layout_height="50dp"
tools:ignore="MissingConstraints" />
</androidx.constraintlayout.widget.ConstraintLayout>

5.原生如何与Flutter进行传值通信(以EventChannel为例说明)

在上一篇博客中我们有讲过原生与Flutter通信的三种方式,这里我再说一下EventChannel通信。

EventChannel是单向的通信方式,即只能通过原生向Flutter发起通信。

(1)原生发起通信

new EventChannel(flutterView,"NATIVE/HMLT/Channel/Setting").setStreamHandler(new EventChannel.StreamHandler() {
@Override
public void onListen(Object o, EventChannel.EventSink eventSink) {
eventSink.success( SharedPreferenceUtil.getToken(context));
} @Override
public void onCancel(Object o) { }
});

其中onCancel代表对面不再接收,这里我们应该做一些clean up的事情。而 onListen则代表通道已经建好,Native可以发送数据了。注意onListen里带的EventSink这个参数,后续Native发送数据都是经过EventSink的。

(2)在Flutter中注册监听

//注册监听原生通道
EventChannel eventChannel = EventChannel('NATIVE/HMLT/Channel/Setting');

(3)在Flutter中重写initState并发起通信请求

void initState() {
//实现通道的监听,并传入两个带有参数的函数用于监听到数据后 对数据进行处理
eventChannel.receiveBroadcastStream().listen(_receiveFromeNative, onError: _fromNativeError);
super.initState();
}

(4)监听到通信数据后进行成功或失败的处理

void _receiveFromeNative(Object para){
print(para);
setState(() {
_nativeToFlutterHMToken = para.toString();
print("原生界面数据" + _nativeToFlutterHMToken);
});
} //原生返回错误信息
void _fromNativeError(Object error){
print(error);
}

总结:以上就是Android与Flutter混编的全部内容了,整体就分为4部分,1.创建FlutterModule,2.创建Flutter视图容器,3.原生跳转到Flutter页面,4.原生与FLutter进行通信。以arr组件的形式集成到项目中我还没有尝试过,还在学习的过程中,如果有写的不对的地方欢迎大佬们留言指证。

Flutter学习笔记(30)--Android原生与Flutter混编的更多相关文章

  1. Flutter学习笔记(36)--常用内置动画

    如需转载,请注明出处:Flutter学习笔记(36)--常用内置动画 Flutter给我们提供了很多而且很好用的内置动画,这些动画仅仅需要简单的几行代码就可以实现一些不错的效果,Flutter的动画分 ...

  2. Flutter学习笔记(10)--容器组件、图片组件

    如需转载,请注明出处:Flutter学习笔记(10)--容器组件.图片组件 上一篇Flutter学习笔记(9)--组件Widget我们说到了在Flutter中一个非常重要的理念"一切皆为组件 ...

  3. Flutter学习笔记(29)--Flutter如何与native进行通信

    如需转载,请注明出处:Flutter学习笔记(29)--Flutter如何与native进行通信 前言:在我们开发Flutter项目的时候,难免会遇到需要调用native api或者是其他的情况,这时 ...

  4. Flutter学习笔记(8)--Dart面向对象

    如需转载,请注明出处:Flutter学习笔记(7)--Dart异常处理 Dart作为高级语言,支持面向对象的很多特性,并且支持基于mixin的继承方式,基于mixin的继承方式是指:一个类可以继承自多 ...

  5. Flutter学习笔记(11)--文本组件、图标及按钮组件

    如需转载,请注明出处:Flutter学习笔记(10)--容器组件.图片组件 文本组件 文本组件(text)负责显示文本和定义显示样式,下表为text常见属性 Text组件属性及描述 属性名 类型 默认 ...

  6. Flutter学习笔记(12)--列表组件

    如需转载,请注明出处:Flutter学习笔记(12)--列表组件 在日常的产品项目需求中,经常会有列表展示类的需求,在Android中常用的做法是收集数据源,然后创建列表适配器Adapter,将数据源 ...

  7. Flutter学习笔记(13)--表单组件

    如需转载,请注明出处:Flutter学习笔记(13)--表单组件 表单组件是个包含表单元素的区域,表单元素允许用户输入内容,比如:文本区域,下拉表单,单选框.复选框等,常见的应用场景有:登陆.注册.输 ...

  8. Flutter学习笔记(14)--StatefulWidget简单使用

    如需转载,请注明出处:Flutter学习笔记(14)--StatefulWidget简单使用 今天上班没那么忙,突然想起来我好像没StatefulWidget(有状态组件)的demo,闲来无事,写一个 ...

  9. Flutter学习笔记(15)--MaterialApp应用组件及routes路由详解

    如需转载,请注明出处:Flutter学习笔记(15)--MaterialApp应用组件及routes路由详解 最近一段时间生病了,整天往医院跑,也没状态学东西了,现在是好了不少了,也该继续学习啦!!! ...

随机推荐

  1. todoList.html

    待做的事情 {{item}} 完成 <!DOCTYPE html> <html> <head> <meta charset="UTF-8" ...

  2. ThreadPoolExecutor源码中的适配器模式

    什么是适配器模式 网上已有很多的教程,不细讲了.可以参考:五分钟了解设计模式(3)---适配器模式 在适配器模式中,一定要识别清楚,Target Adaptee Adapter分别是哪些类或接口,这样 ...

  3. SpringCloud之Zuul过滤器实现登录鉴权实战(十一)

    自定义zuul过滤器实现登录鉴权实战 1.新建filter包 2.新建类继承ZuulFilter,重写方法 3.在类顶部加注解@Comment让spring扫描 /** * @author WGR * ...

  4. podman初试-和docker对比

    podman初试-和docker对比 1,什么是docker? Docker 是一个开源的应用容器引擎,属于 Linux 容器的一种封装,Docker 提供简单易用的容器使用接口,让开发者可以打包他们 ...

  5. Docker安装ElasticSearch 以及使用LogStash实现索引库和数据库同步

    1:下载 ElasticSearch 镜像 docker pull docker.io/elasticsearch:5.6.8 2:创建 ElasticSearch 容器: 注意:5.0默认分配jvm ...

  6. python基础-集合set及内置方法

    数据类型之集合-set 用途:多用于去重,关系运算 定义方式:通过大括号存储,集合中的每个元素通过逗号分隔.集合内存储的元素必须是不可变的,因此,列表-List 和字典dict 不能存储在集合中 注意 ...

  7. 在VMware15中安装虚拟机并使用Xshell连接到此虚拟机(超详细哦)

    首先点击创建新的虚拟机. 此处默认, 点击下一步 默认, 点击下一步 此处可以设置你的虚拟机名称和安装位置(强烈建议不要将安装位置放在系统盘). 此处可根据自己的电脑配置来设置(建议2,4),后续可以 ...

  8. Project Euler 53: Combinatoric selections

    从12345这个数字中挑选出三个数共有十种方式: \[ 123, 124, 125, 134, 135, 145, 234, 235, 245,345 \] 在组合学中,我们将其记为\(C(5,3)= ...

  9. canvas线条实践之运动的正方形

    原理说明: 1.通过rect实现正方形的绘制: 2.save保存canvas面板的保存,restore回复保存的canvas面板到初始状态: 3.translate用于改变canvas坐标的起始位置: ...

  10. Spring源码解析之@Configuration

    @Configuration简介 用于标识一个类为配置类,与xml配置效果类似 用法简介 public class TestApplication { public static void main( ...