Android 原生项目添加 Flutter Activity 示例及常见报错解决方案

本文档从 Android 原生项目集成 Flutter Activity 开始,逐步讲解实现步骤,并针对集成过程中常见的报错(如文件找不到、类找不到、序列化异常)提供完整解决方案,适配最新 Flutter 版本,可直接复制使用。

一、Android 原生项目添加 Flutter Activity 完整示例

1.1 环境准备

  1. 本地已安装 Flutter SDK(配置好环境变量);

  2. Android Studio 安装 Flutter、Dart 插件;

  3. 现有 Android 原生项目(Java/Kotlin 均可);

  4. Flutter 与 Android 项目同级目录存放(推荐)。

1.2 核心步骤

步骤1:创建 Flutter Module(关键)

Android 原生项目不能直接引入 Flutter,需先创建 Flutter Module(依赖库):

打开终端,进入 Android 项目的父目录,执行以下命令(模块名可自定义,本文以 gospot-flutter 为例):

bash 复制代码
# 创建 flutter module(名称自定义)

flutter create -t module gospot-flutter

注意不要使用android studio创建项目

最终目录结构如下:

复制代码
你的项目根目录/

├─ android_native_project/  # 你的现有 Android 原生项目

└─ gospot-flutter/          # 刚创建的 Flutter 模块
步骤2:配置 Android 项目依赖
(1)修改 settings.gradle(项目级配置)

添加 Flutter Module 依赖,确保路径与 Flutter 模块名一致:

gradle 复制代码
rootProject.name = "MyAndroidApp"

include ':app'

// 👇 新增:引入 Flutter Module(路径需与模块名一致)

setBinding(new Binding([gradle: this]))

evaluate(new File(

        settingsDir.parentFile,

        'gospot-flutter/.android/include_flutter.groovy'

))
(2)修改 app/build.gradle(模块级配置)
  1. 最低 SDK 版本要求:minSdk ≥ 16(Flutter 官方要求);

  2. 添加 Flutter 依赖:

gradle 复制代码
android {

    // 必须修改,确保 minSdk ≥ 16

    defaultConfig {

        minSdk 16

        // ... 其他配置(applicationId、versionCode 等)

    }

}

dependencies {

    // 👇 新增:依赖 Flutter 模块

    implementation project(':flutter')

    // ... 其他依赖

}
步骤3:编写 Flutter 页面代码

打开 gospot-flutter/lib/main.dart,替换为测试页面(可根据需求修改):

dart 复制代码
import 'package:flutter/material.dart';

void main() => runApp(const MyApp());

class MyApp extends StatelessWidget {

  const MyApp({super.key});

  @override

  Widget build(BuildContext context) {

    return MaterialApp(

      home: Scaffold(

        appBar: AppBar(

          title: const Text("Flutter 页面"),

          backgroundColor: Colors.blue,

        ),

        body: const Center(

          child: Column(

            mainAxisAlignment: MainAxisAlignment.center,

            children: [

              Text(

                "这是 Android 启动的 Flutter Activity",

                style: TextStyle(fontSize: 18),

              ),

              SizedBox(height: 20),

 Text(

                "Flutter 页面加载成功 ✅",

                style: TextStyle(color: Colors.green, fontSize: 16),

              ),

            ],

          ),

        ),

      ),

    );

  }

}
步骤4:Android 原生中创建并启动 Flutter Activity

提供两种方式,推荐方式2(自定义 Activity,可定制化),方式1最简用于快速测试。

方式1:使用 Flutter 官方提供的 FlutterActivity(最简单)

无需自定义 Activity,直接在 Android 代码中跳转:

Kotlin 代码
kotlin 复制代码
import io.flutter.embedding.android.FlutterActivity

// 点击按钮跳转(示例:按钮 id 为 btn_open_flutter)

btn_open_flutter.setOnClickListener {

    // 启动默认 Flutter 页面(对应 main.dart)

    startActivity(FlutterActivity.createDefaultIntent(this@MainActivity))

}
Java 代码
java 复制代码
import io.flutter.embedding.android.FlutterActivity;

import android.content.Intent;

// 点击按钮跳转(示例:按钮 id 为 btn_open_flutter)

findViewById(R.id.btn_open_flutter).setOnClickListener(v -> {

    Intent intent = FlutterActivity.createDefaultIntent(MainActivity.this);

    startActivity(intent);

});
方式2:自定义 Flutter Activity(推荐,可定制)
  1. 创建自定义 Activity(Java/Kotlin 均可,以 Java 为例):
java 复制代码
import io.flutter.embedding.android.FlutterActivity;

public class FlutterPageActivity extends FlutterActivity {

    // 可重写方法自定义 Flutter 初始化(如指定路由、传递参数)

}
  1. 在 AndroidManifest.xml 中注册 Activity(必须):
xml 复制代码
<activity

    android:name=".FlutterPageActivity"

    android:theme="@style/Theme.AppCompat" />
  1. 启动自定义 Flutter Activity(Java 代码):
java 复制代码
import android.content.Intent;

findViewById(R.id.btn_open_flutter).setOnClickListener(v -> {

    Intent intent = new Intent(MainActivity.this, FlutterPageActivity.class);

    startActivity(intent);

});
步骤5:测试运行
  1. 先执行 Flutter 模块初始化(进入 gospot-flutter 目录,执行 flutter pub get);

  2. 回到 Android 项目,点击 Android Studio 右上角「Sync Project with Gradle Files」(大象图标);

  3. 运行 Android 原生项目,点击按钮,即可跳转到 Flutter 页面;

  4. 支持热重载/热重启:修改 Flutter 代码,保存即可刷新页面。

1.3 进阶:Android 与 Flutter 传递参数

(1)Android 向 Flutter 传参(基础类型)
java 复制代码
// Java 代码,跳转时传递基础类型参数

Intent intent = FlutterActivity

        .withNewEngine()

        .initialRoute("actionId=2&actionName=Ollie") // 传递路由参数

        .build(this);

startActivity(intent);
(2)Flutter 接收参数
dart 复制代码
import 'package:flutter/material.dart';

void main() => runApp(MyApp(

  // 获取 Android 传递的路由参数

  initParams: WidgetsBinding.instance.window.defaultRouteName,

));

class MyApp extends StatelessWidget {

  final String initParams;

  const MyApp({super.key, required this.initParams});

  @override

  Widget build(BuildContext context) {

    return MaterialApp(

      home: Scaffold(

        body: Center(child: Text("Android 传入参数:$initParams")),

      ),

    );

  }

}

二、集成过程中常见报错及解决方案

报错1:java.io.FileNotFoundException: F:\ytdd\code\gospot-flutter.android\include_flutter.groovy

1. 报错原因

Android 项目找不到 Flutter Module 里的 .android/include_flutter.groovy 文件,该文件是 Flutter 自动生成的,未执行初始化命令则不会生成。

2. 解决方案(按顺序执行)

使用上文的命令行创建flutter 模块 ,然后

  1. 打开终端,进入 Flutter 模块目录(本文路径:F:\ytdd\code\gospot-flutter);

  2. 执行 Flutter 初始化命令,自动生成 .android 目录及目标文件:

bash 复制代码
flutter pub get
3. 验证与终极修复
  1. 执行命令后,检查目录结构,确认 .android/include_flutter.groovy 已生成:

    gospot-flutter/

    ├─ .android/

    │ └─ include_flutter.groovy ✅ 生成成功

    └─ lib/

  2. 若仍未生成,删除 .android、.ios 目录,重新执行 flutter pub get;

  3. 确认 settings.gradle 中引入路径与 Flutter 模块名一致(参考 1.2.1 步骤配置)。

报错2:Could not find a command named "make-host-app-editable"

1. 报错原因

Flutter 3.x 及以上版本已废弃 make-host-app-editable 命令,无需手动执行该命令,仅需执行 flutter pub get 即可自动生成 .android 目录。

2. 解决方案
  1. 进入 Flutter 模块目录(F:\ytdd\code\gospot-flutter);

  2. 仅执行以下命令,即可生成 .android 目录及 include_flutter.groovy 文件:

bash 复制代码
flutter pub get
  1. 回到 Android 项目,点击「Sync Project with Gradle Files」同步配置即可。

报错3:java.lang.ClassNotFoundException: Didn't find class "io.flutter.embedding.android.FlutterActivity" on path

1. 报错原因

Android 项目虽配置了 Flutter 依赖,但 Gradle 未同步成功、缓存异常,导致 FlutterActivity 类未被打包,运行时无法找到。

2. 解决方案(按顺序执行)
  1. 确认配置正确性:

    • app/build.gradle 中已添加 implementation project(':flutter') 依赖;

    • settings.gradle 中已正确引入 Flutter Module(参考 1.2.1 步骤)。

  2. 同步 Gradle:点击 Android Studio 右上角「Sync Project with Gradle Files」(大象图标);

  3. 清理并重新编译项目:

    • Build → Clean Project;

    • Build → Rebuild Project。

  4. 重启 Android Studio 和运行的 App;

  5. 若仍报错,进入 Flutter 模块目录,执行以下命令后重新同步编译:

bash 复制代码
flutter clean

flutter pub get

报错4:java.lang.IllegalArgumentException: Parcel: unknown type for value Action(...)}

1. 报错概述

在 Android 原生项目跳转 FlutterActivity 时,出现如下序列化相关报错:

java 复制代码
java.lang.IllegalArgumentException: Parcel: unknown type for value Action(id=2, category=街式, subCategory=平地, subCategoryEn=Flat, name=Ollie, difficulty=EASY, star=1, level=中阶, stance=Regular, learn=学习要领, error=常见错误, preAction=1)

核心结论:该报错与 Flutter 集成无关,属于 Android 原生 Intent 传递自定义对象时,序列化配置异常导致。

2. 报错根本原因

通过 Intent 传递自定义 Action 类对象时,未满足 Android 序列化要求,具体分为3种情况:

  1. Action 类未实现 Parcelable 或 Serializable 序列化接口;

  2. 若实现了 Parcelable,则 writeToParcel(写)与 createFromParcel(读)的字段顺序不一致;

  3. Action 类包含不支持序列化的字段类型(如自定义接口、未序列化的内部类等)。

Android 系统无法解析未正确序列化的自定义对象,因此抛出 Parcel: unknown type for value 异常。

3. 修复方案(按推荐优先级排序)
方案1:最简修复(推荐,适配 Flutter 跳转场景)

核心逻辑:跳转 FlutterActivity 时,无需传递完整自定义对象,仅传递基础数据类型(字符串、数字等)即可,避免序列化操作。

错误写法(当前报错写法)
java 复制代码
// 错误:直接传递 Action 自定义对象

Intent intent = new Intent(this, FlutterActivity.class);

intent.putExtra("action", action);  // 传递未正确序列化的对象

startActivity(intent);
正确写法
java 复制代码
// 正确:仅传递基础类型数据(id、名称、分类等)

Intent intent = FlutterActivity.createDefaultIntent(this);

// 传递 int、String 等基础类型,避免序列化

intent.putExtra("actionId", action.getId());

intent.putExtra("actionName", action.getName());

intent.putExtra("category", action.getCategory());

intent.putExtra("difficulty", action.getDifficulty().toString());

startActivity(intent);

说明:该方案无需修改 Action 类,直接规避序列化问题,适配 Flutter 跳转的核心需求(Flutter 仅需基础数据即可渲染页面)。

方案2:实现 Serializable 序列化(简单通用)

若必须传递完整 Action 对象,推荐使用 Serializable(代码侵入性低,无需手动实现读写方法)。

步骤1:修改 Action 类
java 复制代码
// 给 Action 类实现 Serializable 接口

public class Action implements Serializable {  // 核心修改:添加 Serializable

    // 原有字段(无需额外修改)

    private int id;

    private String category;

    private String subCategory;

    // ... 其他字段、getter/setter 方法

}
步骤2:传递与接收对象
java 复制代码
// 1. 传递 Action 对象

Intent intent = FlutterActivity.createDefaultIntent(this);

intent.putExtra("action", action);  // 此时可正常传递

startActivity(intent);

// 2. 接收 Action 对象(若需在 Android 端接收,如自定义 FlutterActivity)

Action action = (Action) getIntent().getSerializableExtra("action");

注意:Serializable 会序列化整个对象,若对象字段较多,建议优先使用方案1或方案3。

方案3:Flutter 最佳实践(传递 JSON 字符串)

核心逻辑:将 Action 对象转为 JSON 字符串传递,Flutter 端接收后再解析为对应实体类,既避免序列化异常,也适配 Flutter 数据处理习惯。

步骤1:依赖 Gson(用于对象转 JSON)

在 app/build.gradle 中添加 Gson 依赖(若未添加):

gradle 复制代码
dependencies {

    // Gson 依赖,用于对象与 JSON 互转

    implementation 'com.google.code.gson:gson:2.10.1'

}
步骤2:传递 JSON 字符串
java 复制代码
// 1. 将 Action 对象转为 JSON 字符串

String actionJson = new Gson().toJson(action);

// 2. 传递 JSON 字符串(基础类型,无序列化问题)

Intent intent = FlutterActivity.createDefaultIntent(this);

intent.putExtra("actionJson", actionJson);

startActivity(intent);
步骤3:Flutter 端接收解析(补充)

Flutter 端通过 ModalRoute 或 MethodChannel 获取 JSON 后,解析为实体类:

dart 复制代码
// Flutter 代码示例

import 'dart:convert';

// 获取 Android 传递的 JSON 字符串

String? actionJson = ModalRoute.of(context)?.settings.arguments as String?;

if (actionJson != null) {

  // 解析为 Action 实体类

  Map<String, dynamic> actionMap = json.decode(actionJson);

  Action action = Action.fromJson(actionMap); // 需自定义 fromJson 方法

}
4. 常见注意事项
  1. 跳转 FlutterActivity 时,优先使用 FlutterActivity.createDefaultIntent(this) 初始化 Intent,避免手动创建 Intent 时遗漏配置;

  2. 若使用 Parcelable 序列化(未推荐),务必保证 writeToParcel 与 createFromParcel 的字段读写顺序完全一致;

  3. 避免传递包含复杂引用的对象(如 Context、View 等),此类对象无法序列化,会导致报错;

  4. 修改序列化配置后,需 Clean Project → Rebuild Project,避免缓存导致配置不生效。

三、总结

  1. 核心流程:Android 原生集成 Flutter Activity,需先创建 Flutter Module,再配置 Gradle 依赖,最后通过 Intent 跳转;

  2. 常见坑点:文件找不到(执行 flutter pub get)、命令失效(放弃 make-host-app-editable)、类找不到(同步+清理编译)、序列化异常(传递基础类型/JSON);

  3. 最佳实践:跳转 Flutter 页面时,优先传递基础类型或 JSON 字符串,避免复杂对象序列化,降低报错概率。

相关推荐
Utopia^7 小时前
鸿蒙flutter第三方库适配 - 联系人备份工具
flutter·华为·harmonyos
CYRUS_STUDIO8 小时前
Frida 检测与对抗实战:进程、maps、线程、符号全特征清除
android·逆向
csj509 小时前
安卓基础之《(28)—Service组件》
android
lhbian11 小时前
PHP、C++和C语言对比:哪个更适合你?
android·数据库·spring boot·mysql·kafka
catoop12 小时前
Android 最佳实践、分层架构与全流程解析(2025)
android
ZHANG13HAO12 小时前
Android 13 特权应用(Android Studio 开发)调用 AOSP 隐藏 API 完整教程
android·ide·android studio
田梓燊13 小时前
leetcode 142
android·java·leetcode
angerdream13 小时前
Android手把手编写儿童手机远程监控App之JAVA基础
android
念格13 小时前
Flutter 仿微信输入框最佳实践:自适应高度 + 超行数智能切换全屏
前端·flutter
菠萝地亚狂想曲14 小时前
Zephyr_01, environment
android·java·javascript