Flutter 学习之旅 之 flutter 作为 module ,在 Android 的界面中嵌入Flutter界面功能的简单整理
目录
Flutter 学习之旅 之 flutter 作为 module ,在 Android 的界面中嵌入Flutter界面功能的简单整理
一、简单介绍
二、在同一个布局中同时显示 Android 和 Flutter 界面 的实现原理
1. Flutter 的嵌入机制
2. FlutterEngine 的作用
3. FlutterView 的工作原理
4. FlutterFragment 的工作原理
三、简单效果预览
四、案例简单实现步骤
五、关键代码
一、简单介绍
Flutter 是一款开源的 UI 软件开发工具包,由 Google 开发和维护。它允许开发者使用一套代码同时构建跨平台的应用程序,包括移动设备(iOS 和 Android)、Web 和桌面平台(Windows、macOS 和 Linux)。
Flutter 使用 Dart 编程语言,它可以将代码编译为 ARM 或 Intel 机器代码以及 JavaScript,从而实现快速的性能。Flutter 提供了一个丰富的预置小部件库,开发者可以根据自己的需求灵活地控制每个像素,从而创建自定义的、适应性强的设计,这些设计在任何屏幕上都能呈现出色的外观和感觉。
二、在同一个布局中同时显示 Android 和 Flutter 界面 的实现原理
在同一个布局中同时显示 Android 和 Flutter 界面的实现原理主要基于 Flutter 提供的嵌入机制,允许 Flutter 内容以视图的形式嵌入到原生 Android 布局中。以下是其实现原理的详细解释:
1. Flutter 的嵌入机制
Flutter 提供了两种主要方式将 Flutter 内容嵌入到原生 Android 应用中:
-
FlutterView:这是一个原生的 Android 视图,用于显示 Flutter 内容。
-
FlutterFragment:这是一个 Android Fragment,用于将 Flutter 内容嵌入到 Android 的 Fragment 管理系统中。
这两种方式的核心是通过 FlutterEngine
来运行 Flutter 的 Dart 代码,并将渲染结果绘制到一个原生的 Android 视图中。
2. FlutterEngine 的作用
FlutterEngine
是 Flutter 提供的一个核心组件,用于初始化和运行 Flutter 的 Dart 代码。它负责以下任务:
-
加载 Dart 代码:从 APK 或其他资源中加载 Dart 文件,并执行 Dart 入口点(通常是
main()
函数)。 -
管理渲染线程:负责将 Flutter 的渲染内容绘制到原生视图中。
-
处理平台通道通信:通过
MethodChannel
和EventChannel
实现 Flutter 和原生代码之间的通信。 -
管理生命周期:与 Android 的生命周期(如
onPause
、onResume
)同步,确保 Flutter 内容在合适的时机进行渲染和暂停。
3. FlutterView 的工作原理
FlutterView
是一个原生的 Android 视图,用于显示 Flutter 内容。它的实现原理如下:
-
创建 FlutterEngine:在 Android 代码中创建一个
FlutterEngine
实例,并将其与FlutterView
关联。 -
绑定 Dart 代码:通过
FlutterEngine
加载 Dart 代码,并指定 Dart 的入口点(通常是main()
函数)。 -
渲染 Flutter 内容:
FlutterView
会接收来自 Flutter 引擎的渲染指令,并将其绘制到视图中。Flutter 引擎会将渲染内容转换为 OpenGL 或 Skia 的绘图命令,并通过FlutterView
的Surface
或TextureView
进行渲染。
4. FlutterFragment 的工作原理
FlutterFragment
是一个 Android Fragment,用于将 Flutter 内容嵌入到 Android 的 Fragment 管理系统中。它的实现原理如下:
-
创建 FlutterEngine:与
FlutterView
类似,FlutterFragment
也需要一个FlutterEngine
实例来运行 Dart 代码。 -
生命周期管理:
FlutterFragment
会根据 Android 的 Fragment 生命周期(如onCreate
、onResume
)管理 Flutter 引擎的生命周期,确保 Flutter 内容在合适的时机进行初始化和销毁。 -
视图嵌入:
FlutterFragment
内部会创建一个FlutterView
,并将 Flutter 内容渲染到该视图中。通过 Fragment 的onCreateView
方法,将FlutterView
返回给 Android 系统,从而实现 Flutter 内容的嵌入。
三、简单效果预览
四、案例简单实现步骤
1、在 Android Studio 中创建一个 Flutter 工程
2、选择创建 一个 Flutter Module
3、编写一个简单的 Flutter 界面
4、先再创建一个 Android 工程
5、回到 Flutter 工程,进行 Flutter - Build AAR 编译
6、编译完成后, 会有提示如何在 Android 工程中引用
7、在 Android 工程中,根据提示,在 settings.gradle 和 build.gradle 添加如下的提示内容
8、在 activity_main.xml 中添加一个 按钮,用来调起 Flutter 界面
9、在 MainActivity 中 引入 Flutter 相关,并实现点击 按钮 唤起 Flutter 界面的代码
10、在 AndroidManifest.xml 中,添加 FlutterActivity 相关属性
11、打包运行,简单效果如下
五、关键代码
1、main.dart
import 'package:flutter/material.dart';void main() {runApp(MyApp());
}class MyApp extends StatelessWidget {@overrideWidget build(BuildContext context) {return MaterialApp(title: 'Flutter Demo', // 设置应用的标题,显示在系统任务栏或窗口标题中theme: ThemeData(primarySwatch: Colors.blue, // 设置应用的主题颜色,这里使用蓝色作为主色调),home: MyHomePage(), // 设置应用的初始页面为 MyHomePage);}
}class MyHomePage extends StatelessWidget {@overrideWidget build(BuildContext context) {return Scaffold( // 使用 Scaffold 提供一个基本的页面布局结构appBar: AppBar( // 添加一个应用栏(AppBar)作为页面的顶部导航title: Text('Flutter Module in Android'), // 设置应用栏的标题),body: Center( // 设置页面的主体内容child: Text('Hello from Flutter!'), // 在页面中心显示一条文本消息),);}
}
2、MainActivity.java
package com.example.test_android_embedding_flutter_0428;import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.FragmentTransaction;import io.flutter.embedding.android.FlutterFragment;
import io.flutter.embedding.engine.FlutterEngine;
import io.flutter.embedding.engine.FlutterEngineCache;
import io.flutter.embedding.engine.dart.DartExecutor;public class MainActivity extends AppCompatActivity {private FlutterEngine flutterEngine; // 用于运行 Flutter Dart 代码的核心引擎@Overrideprotected void onCreate(@Nullable Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main); // 设置当前 Activity 的布局文件// 初始化 FlutterEngine// 创建一个 FlutterEngine 实例,用于运行 Flutter 的 Dart 代码flutterEngine = new FlutterEngine(this);// 执行 Dart 入口点,默认是 main() 函数flutterEngine.getDartExecutor().executeDartEntrypoint(DartExecutor.DartEntrypoint.createDefault());// 将 FlutterEngine 实例缓存到 FlutterEngineCache 中// 这样可以在需要时快速复用,避免重复初始化FlutterEngineCache.getInstance().put("my_flutter_engine", flutterEngine);// 获取按钮并设置点击事件findViewById(R.id.button).setOnClickListener(v -> {// 创建 FlutterFragment 实例// FlutterFragment 是一个 Android Fragment,用于嵌入 Flutter 界面FlutterFragment flutterFragment = FlutterFragment.createDefault();// 开始一个 Fragment 事务FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();// 将 FlutterFragment 替换到布局中的 FrameLayout 容器中// R.id.fl_container 是布局文件中定义的 FrameLayout 的 IDtransaction.replace(R.id.fl_container, flutterFragment);// 提交事务,使 Flutter 界面显示出来transaction.commit();});}
}
代码注释说明
FlutterEngine 的初始化
new FlutterEngine(this)
:创建一个FlutterEngine
实例,用于运行 Flutter 的 Dart 代码。
executeDartEntrypoint
:指定 Dart 的入口点,默认是main()
函数。这是 Flutter 应用的起点。
FlutterEngineCache.getInstance().put("my_flutter_engine", flutterEngine)
:将初始化好的FlutterEngine
缓存起来,以便后续复用。这可以避免重复初始化 Flutter 引擎,提高性能。按钮点击事件
findViewById(R.id.button)
:通过 ID 获取布局中的按钮。
setOnClickListener
:为按钮设置点击事件监听器。
FlutterFragment.createDefault()
:创建一个默认的FlutterFragment
实例。FlutterFragment
是一个 Android Fragment,用于嵌入 Flutter 界面。
getSupportFragmentManager().beginTransaction()
:开始一个 Fragment 事务,用于管理 Fragment 的添加、替换等操作。
transaction.replace(R.id.fl_container, flutterFragment)
:将FlutterFragment
替换到布局中的FrameLayout
容器中。R.id.fl_container
是布局文件中定义的容器 ID。
transaction.commit()
:提交事务,使 Flutter 界面显示出来。
3、activity_main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"><!-- 定义一个按钮,点击后会显示 Flutter 界面 --><Buttonandroid:id="@+id/button"android:layout_width="match_parent"android:layout_height="wrap_content"android:text="打开 Flutter 界面" /><!-- 定义一个 FrameLayout 作为容器,用于嵌入 Flutter 界面 --><FrameLayoutandroid:id="@+id/fl_container"android:layout_width="match_parent"android:layout_height="0dp"android:layout_weight="1" />
</LinearLayout>
4、AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"><applicationandroid:allowBackup="true"android:dataExtractionRules="@xml/data_extraction_rules"android:fullBackupContent="@xml/backup_rules"android:icon="@mipmap/ic_launcher"android:label="@string/app_name"android:roundIcon="@mipmap/ic_launcher_round"android:supportsRtl="true"android:theme="@style/Theme.Test_Android_Embedding_Flutter_0428"tools:targetApi="31"><activityandroid:name=".MainActivity"android:exported="true"android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"android:hardwareAccelerated="true"android:windowSoftInputMode="adjustResize"><intent-filter><action android:name="android.intent.action.MAIN" /><category android:name="android.intent.category.LAUNCHER" /></intent-filter></activity></application>
</manifest>
5、settings.gradle
pluginManagement {// 配置插件管理相关的设置repositories {// 定义插件管理的仓库来源google {// 使用 Google 的 Maven 仓库content {// 定义需要包含的组(group)正则表达式includeGroupByRegex("com\\.android.*") // 包含以 "com.android" 开头的组includeGroupByRegex("com\\.google.*") // 包含以 "com.google" 开头的组includeGroupByRegex("androidx.*") // 包含以 "androidx" 开头的组}}mavenCentral() // 使用 Maven Central 仓库gradlePluginPortal() // 使用 Gradle 插件门户}
}dependencyResolutionManagement {// 配置依赖解析相关的设置repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) // 设置仓库模式,如果项目中有仓库配置错误则失败repositories {google() // 使用 Google 的 Maven 仓库mavenCentral() // 使用 Maven Central 仓库}// 定义 Flutter 模块的存储 URLString storageUrl = System.env.FLUTTER_STORAGE_BASE_URL ?: "https://storage.googleapis.com"// 如果环境变量 FLUTTER_STORAGE_BASE_URL 未设置,则使用默认的 Flutter 存储 URL// 注意:该 URL 是 Flutter 依赖项的默认存储位置,但由于网络原因,可能无法直接访问// 如果您遇到问题,请检查链接的合法性或在网络正常的情况下重试repositories {maven {// 定义本地 Maven 仓库路径url 'D:/UsingForXAN/Projects/AndroidStudioProjects/FlutterProject/test_flutter_module_0418/build/host/outputs/repo'}maven {// 定义远程 Maven 仓库路径url "$storageUrl/download.flutter.io"}}
}// 设置项目的根项目名称
rootProject.name = "Test_Android_Embedding_Flutter_0428"
// 包含子项目 'app',这是 Android 项目的主模块
include ':app'
6、build.gradle
plugins {alias(libs.plugins.android.application)
}
// 定义项目使用的插件
// 这里使用了 alias 来引用预定义的插件,通常是定义在 buildSrc 或其他地方的插件别名
// 这里引用的是 Android 应用插件,用于构建 Android 应用android {namespace 'com.example.test_android_embedding_flutter_0428'// 设置项目的命名空间,用于区分不同的应用compileSdk 35// 设置编译 SDK 的版本,这里是 API 级别 35defaultConfig {applicationId "com.example.test_android_embedding_flutter_0428"// 设置应用的唯一标识符minSdk 28// 设置应用支持的最低 SDK 版本targetSdk 34// 设置应用的目标 SDK 版本versionCode 1// 设置应用的版本代码,用于内部版本管理versionName "1.0"// 设置应用的版本名称,显示给用户testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"// 设置用于运行 Android 测试的测试运行器}buildTypes {release {minifyEnabled false// 是否启用代码混淆,这里设置为 false 表示不启用proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'// 指定 ProGuard 配置文件,用于代码混淆规则}profile {initWith debug// 将 profile 构建类型初始化为 debug 构建类型的配置}}compileOptions {sourceCompatibility JavaVersion.VERSION_1_8// 设置源代码的 Java 版本兼容性targetCompatibility JavaVersion.VERSION_1_8// 设置目标字节码的 Java 版本兼容性}
}dependencies {// 定义项目的依赖项implementation libs.appcompat// 添加 AndroidX AppCompat 库的依赖,用于支持旧版本 Android 的兼容性implementation libs.material// 添加 Material Design 组件库的依赖,用于构建 Material Design 风格的界面implementation libs.activity// 添加 Activity 组件库的依赖,用于支持新的 Activity APIimplementation libs.constraintlayout// 添加 ConstraintLayout 布局库的依赖,用于构建复杂的布局testImplementation libs.junit// 添加 JUnit 测试框架的依赖,用于编写单元测试androidTestImplementation libs.ext.junit// 添加扩展的 JUnit 测试框架的依赖,用于 Android 测试androidTestImplementation libs.espresso.core// 添加 Espresso 测试框架的依赖,用于编写 UI 测试debugImplementation 'com.example.test_flutter_module_0418:flutter_debug:1.0'// 在 debug 构建类型中添加 Flutter 模块的 debug 版本依赖profileImplementation 'com.example.test_flutter_module_0418:flutter_profile:1.0'// 在 profile 构建类型中添加 Flutter 模块的 profile 版本依赖releaseImplementation 'com.example.test_flutter_module_0418:flutter_release:1.0'// 在 release 构建类型中添加 Flutter 模块的 release 版本依赖
}