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


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

  • 相关阅读:
    notion笔记
    PHP性能分析工具xdebug+qcachegrind
    Homebrew1.5之后安装PHP和扩展
    Yii2 创建新项目目录
    MAC的一些实用
    Item2 + zsh
    YII2 RBAC Admin User权限相关
    ITEM 2 MAC OSX 功能略强大的终端
    MAC终端配色Solarized
    微服务 SpringCloud + docker
  • 原文地址:https://www.cnblogs.com/upwgh/p/11950392.html
Copyright © 2020-2023  润新知