当前位置: 首页 > news >正文

Flutter 学习之旅 之 flutter 作为 module ,在 Android 端主动唤起 Flutter 开发的界面 简单的整理

Flutter 学习之旅 之 flutter 作为 module ,在 Android 端主动唤起 Flutter 开发的界面 简单的整理

目录

Flutter 学习之旅 之 flutter 作为 module ,在 Android 端主动唤起 Flutter 开发的界面 简单的整理

一、简单介绍

二、Android 端唤起 Flutter 界面的功能实现原理

三、简单效果预览

四、案例简单实现步骤

五、关键代码


一、简单介绍

Flutter 是一款开源的 UI 软件开发工具包,由 Google 开发和维护。它允许开发者使用一套代码同时构建跨平台的应用程序,包括移动设备(iOS 和 Android)、Web 和桌面平台(Windows、macOS 和 Linux)。

Flutter 使用 Dart 编程语言,它可以将代码编译为 ARM 或 Intel 机器代码以及 JavaScript,从而实现快速的性能。Flutter 提供了一个丰富的预置小部件库,开发者可以根据自己的需求灵活地控制每个像素,从而创建自定义的、适应性强的设计,这些设计在任何屏幕上都能呈现出色的外观和感觉。

二、Android 端唤起 Flutter 界面的功能实现原理

  1. FlutterEngine 的初始化

    • 在 Android 端,FlutterEngine 是 Flutter 运行时的核心组件,负责加载和执行 Dart 代码。

    • 在代码中,通过 new FlutterEngine(this) 创建了一个新的 FlutterEngine 实例。

    • 使用 flutterEngine.getDartExecutor().executeDartEntrypoint(DartExecutor.DartEntrypoint.createDefault()) 来加载 Dart 入口点(通常是 main() 函数)。

    • 最后,将初始化好的 FlutterEngine 缓存到 FlutterEngineCache 中,以便后续使用。

  2. 缓存 FlutterEngine

    • FlutterEngineCache 是一个全局缓存,用于存储已经初始化的 FlutterEngine 实例。

    • 通过调用 FlutterEngineCache.getInstance().put(FLUTTER_ENGINE_ID, flutterEngine),将 FlutterEngine 实例与一个唯一的标识符(FLUTTER_ENGINE_ID)关联起来。

    • 这样做的好处是可以在后续启动 Flutter 界面时,直接使用缓存的 FlutterEngine,而无需重新初始化,从而提高性能。

  3. 启动 Flutter 界面

    • 使用 FlutterActivity.withCachedEngine(FLUTTER_ENGINE_ID).build(MainActivity.this) 创建一个 Intent,用于启动 Flutter 界面。

    • withCachedEngine(FLUTTER_ENGINE_ID) 方法会从 FlutterEngineCache 中获取之前缓存的 FlutterEngine 实例。

    • 调用 startActivity(intent) 启动 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.content.Intent;
import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import io.flutter.embedding.android.FlutterActivity;
import io.flutter.embedding.engine.FlutterEngine;
import io.flutter.embedding.engine.FlutterEngineCache;
import io.flutter.embedding.engine.dart.DartExecutor;public class MainActivity extends AppCompatActivity {// 定义一个常量,用于标识缓存的 FlutterEngine 实例private static final String FLUTTER_ENGINE_ID = "flutter_engine";@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);// 初始化 FlutterEngine// 创建一个新的 FlutterEngine 实例,用于加载和执行 Dart 代码FlutterEngine flutterEngine = new FlutterEngine(this);// 执行 Dart 入口点// 这里调用了 DartExecutor.DartEntrypoint.createDefault(),表示加载默认的 Dart 入口点(通常是 main() 函数)flutterEngine.getDartExecutor().executeDartEntrypoint(DartExecutor.DartEntrypoint.createDefault());// 缓存 FlutterEngine// 将初始化好的 FlutterEngine 实例缓存到 FlutterEngineCache 中,以便后续使用// 这样可以避免每次启动 Flutter 界面时重新初始化 FlutterEngine,从而提高性能FlutterEngineCache.getInstance().put(FLUTTER_ENGINE_ID, flutterEngine);// 启动 Flutter 界面// 设置一个点击事件监听器,当用户点击按钮时,启动 Flutter 界面findViewById(R.id.launch_flutter).setOnClickListener(v -> {// 使用 withCachedEngine 方法,从 FlutterEngineCache 中获取之前缓存的 FlutterEngine 实例// 并通过 build 方法创建一个 Intent,用于启动 FlutterActivityIntent intent = FlutterActivity.withCachedEngine(FLUTTER_ENGINE_ID).build(MainActivity.this);// 启动 FlutterActivity,展示 Flutter 界面startActivity(intent);});}@Overrideprotected void onDestroy() {super.onDestroy();// 在 Activity 销毁时,从 FlutterEngineCache 中移除缓存的 FlutterEngine 实例// 这是一个良好的资源管理实践,避免资源泄漏FlutterEngineCache.getInstance().remove(FLUTTER_ENGINE_ID);}
}

代码注释说明

  1. FlutterEngine 的初始化

    • FlutterEngine flutterEngine = new FlutterEngine(this);:创建一个新的 FlutterEngine 实例,它是 Flutter 运行时的核心组件,负责加载和执行 Dart 代码。

    • flutterEngine.getDartExecutor().executeDartEntrypoint(DartExecutor.DartEntrypoint.createDefault());:执行 Dart 入口点(通常是 main() 函数)。createDefault() 方法会加载默认的 Dart 入口点。

  2. 缓存 FlutterEngine

    • FlutterEngineCache.getInstance().put(FLUTTER_ENGINE_ID, flutterEngine);:将初始化好的 FlutterEngine 实例缓存到 FlutterEngineCache 中。缓存的目的是避免每次启动 Flutter 界面时重新初始化 FlutterEngine,从而提高性能。

  3. 启动 Flutter 界面

    • findViewById(R.id.launch_flutter).setOnClickListener(v -> { ... });:为按钮设置点击事件监听器。当用户点击按钮时,触发启动 Flutter 界面的操作。

    • FlutterActivity.withCachedEngine(FLUTTER_ENGINE_ID).build(MainActivity.this);:从 FlutterEngineCache 中获取之前缓存的 FlutterEngine 实例,并通过 build 方法创建一个 Intent,用于启动 FlutterActivity

    • startActivity(intent);:启动 FlutterActivity,展示 Flutter 界面。

  4. 资源管理

    • FlutterEngineCache.getInstance().remove(FLUTTER_ENGINE_ID);:在 onDestroy() 方法中,从 FlutterEngineCache 中移除缓存的 FlutterEngine 实例。这是为了避免资源泄漏,确保资源在 Activity 销毁时被正确释放。

3、activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<!-- 定义 XML 文件的版本和编码 -->
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"xmlns:tools="http://schemas.android.com/tools"android:id="@+id/main"android:layout_width="match_parent"android:layout_height="match_parent"tools:context=".MainActivity"><!--ConstraintLayout 是一个强大的布局容器,用于构建复杂的布局。- xmlns:android:声明标准的 Android 命名空间,用于访问 Android 的属性。- xmlns:app:声明自定义属性的命名空间,通常用于访问库(如 ConstraintLayout)的属性。- xmlns:tools:声明 tools 命名空间,用于在布局编辑器中提供工具属性。- android:id:设置布局的唯一标识符。- android:layout_width 和 android:layout_height:设置布局的宽度和高度,这里设置为 match_parent,表示填充父布局。- tools:context:指定与该布局关联的 Activity 类名,这里为 MainActivity。--><Buttonandroid:id="@+id/launch_flutter"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="Launch Flutter"tools:ignore="MissingConstraints" /><!--定义一个 Button,用于启动 Flutter 界面。- android:id:设置按钮的唯一标识符,用于在代码中引用。- android:layout_width 和 android:layout_height:设置按钮的宽度和高度,这里设置为 wrap_content,表示按钮的大小会根据内容自动调整。- android:text:设置按钮上显示的文本内容。- tools:ignore="MissingConstraints":这是一个工具属性,用于忽略布局编辑器中关于缺少约束的警告。在 ConstraintLayout 中,通常需要为子视图设置约束,但由于这里没有设置约束,因此使用该属性忽略警告。--></androidx.constraintlayout.widget.ConstraintLayout>

4、AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<!-- 声明 XML 文件的版本和编码格式 -->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"><!--xmlns:android:声明 Android 的命名空间,用于访问 Android SDK 的属性。xmlns:tools:声明 tools 命名空间,用于访问布局编辑器和构建工具的属性。注意:这些链接是固定的 URI,用于声明命名空间,而不是普通的网页链接。如果您尝试访问这些链接时遇到问题,请检查链接的合法性,或在网络正常的情况下重试。--><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"  <!-- 支持从右到左(RTL)的语言布局 -->android:theme="@style/Theme.Test_Android_Embedding_Flutter_0428"  <!-- 应用的主题 -->tools:targetApi="31">  <!-- 指定目标 API 级别 --><activityandroid:name=".MainActivity"  <!-- 主 Activity 的类名 -->android:exported="true">  <!-- 表示该 Activity 可以被外部应用启动 --><intent-filter><action android:name="android.intent.action.MAIN" />  <!-- 指定该 Activity 是应用的入口 --><category android:name="android.intent.category.LAUNCHER" />  <!-- 将该 Activity 添加到应用启动器 --></intent-filter></activity><activityandroid:name="io.flutter.embedding.android.FlutterActivity"  <!-- FlutterActivity 的类名 -->android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"  <!-- 指定配置变更时不需要重启 Activity -->android:exported="false"  <!-- 表示该 Activity 不允许被外部应用启动 -->android:hardwareAccelerated="true"  <!-- 启用硬件加速 -->android:windowSoftInputMode="adjustResize">  <!-- 指定软键盘弹出时窗口的调整方式 --></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 版本依赖
}

相关文章:

  • DBeaver CE 24.1.3 (Windows 64位) 详细安装教程
  • .net 常用
  • 基于C++实现人工智能—五子棋的目标识别
  • Google在架ab包分析-巴西
  • 阿里云服务器dns怎么修改服务器地址?服务器dns怎么设置??
  • MTK Android12-13 App卸载加锁
  • 基于 Java 的实现前端组装查询语句,后端直接执行查询方案,涵盖前端和后端的设计思路
  • 如何搭建spark yarn 模式的集群集群
  • java 和 C#操作数据库对比
  • Web基础和HTTP协议
  • kvm学习小结
  • 计算机视觉——通过 OWL-ViT 实现开放词汇对象检测
  • Java垃圾收集器与内存分配策略深度解析
  • php数据库连接
  • Linux常见基础命令
  • Leetcode - 双周赛155
  • 超级好用的​​参数化3D CAD 建模​​图形库 (CadQuery库介绍)
  • 数字孪生的浪潮:从虚拟镜像到现实世界的 IT 变革
  • Rust 学习笔记:编程练习(一)
  • 计算机基础—(九道题)
  • 企业取消“大小周”引热议,半月谈:不能将显性加班变为隐性加班
  • “上海-日喀则”直飞航线正式通航,将于5月1日开启首航
  • 坚守刑事检察一线13年,“在我心中每次庭审都是一次大考”
  • 广州一人均500元的日料店回收食材给下一桌?市场监管部门介入调查
  • 杨荫凯履新浙江省委常委、组织部部长,曾任中央财办副主任
  • 影子调查丨掉落的喷淋头:太原一7天酒店加盟店消防设施造假迷局