欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

Flutter学习笔记(30)--Android原生与Flutter混编

程序员文章站 2023-08-31 00:03:10
这篇文章旨在学习如何在现有的Android原生项目上集成Flutter,实现Android与Flutter的混编,文章主体内容分为5部分,如下: Android项目如何集成FlutterModule Flutter视图是如何展示到前台界面的 Flutter与Weex... ......

如需转载,请注明出处: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。

Flutter学习笔记(30)--Android原生与Flutter混编

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

Flutter学习笔记(30)--Android原生与Flutter混编

 第二步:在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'
)) 

Flutter学习笔记(30)--Android原生与Flutter混编

 最后同步一下,将相关的依赖下载下来,至此就成功集成了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[1];
        listeners[0] = new flutterview.firstframelistener() {
            @override
            public void onfirstframe() {
                layout.setvisibility(view.visible);
            }
        };
        flutterview.addfirstframelistener(listeners[0]);
    }
}

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组件的形式集成到项目中我还没有尝试过,还在学习的过程中,如果有写的不对的地方欢迎大佬们留言指证。