创建 Flutter Module:flutter create --template module

好,咱们进入实操环节。

前面聊了那么多为什么要迁移、怎么规划,现在终于要动手了。创建 Flutter Module 是整个迁移流程的第一步,也是基础中的基础。这一步走稳了,后面就顺了。

命令长什么样?

其实就一行命令:

flutter create --template module my_flutter_module

嗯,就这么简单。但这里有几个细节,我得跟你聊聊。

--template module 这个参数是关键。它告诉 Flutter 工具链:我要创建的不是一个独立 App,而是一个可被宿主工程嵌入的模块。说白了,它生成的项目结构跟普通 Flutter 项目不一样——没有 lib/main.dart 里的 runApp(),取而代之的是 lib/main.dart 里只导出一个 MyApp 组件,等着原生工程来调用。

核心区别:

  • 普通 Flutter 项目:flutter create my_app → 生成独立 App
  • Flutter Module:flutter create --template module my_module → 生成可嵌入模块

项目结构长啥样?

执行完命令后,你会看到这样一个目录结构:

my_flutter_module/
├── .android/          # Android 宿主工程模板(自动生成)
├── .ios/              # iOS 宿主工程模板(自动生成)
├── lib/               # Dart 代码目录
│   └── main.dart      # 模块入口(注意:不是 App 入口)
├── test/              # 测试代码
├── pubspec.yaml       # 依赖管理
└── README.md

这里有个坑,我当年第一次用的时候踩过——.android/.ios/ 这两个目录是隐藏的(以点开头)。很多新手会问:「怎么没有 Android 和 iOS 文件夹?」其实它们就在那,只是默认不显示。你可以在终端用 ls -a 看到它们。

注意:这两个目录是自动生成的,不要手动修改里面的内容。如果你需要自定义原生配置,应该通过 pubspec.yaml 或插件机制来做。我曾经手欠改过 .android/ 里的 Gradle 配置,结果下次 flutter pub get 直接给我覆盖了……

生成的 lib/main.dart 长啥样?

打开看看:

import 'package:flutter/material.dart';

void main() {
  // 注意:这里没有 runApp()
  // 模块的入口由原生工程控制
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Module',
      home: const MyHomePage(),
    );
  }
}

class MyHomePage extends StatelessWidget {
  const MyHomePage({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Flutter Module')),
      body: const Center(child: Text('Hello from Flutter Module!')),
    );
  }
}

看到了吗?main() 函数里没有 runApp()。这是因为 Flutter Module 不是独立启动的,它需要由原生 Android/iOS 工程通过 FlutterEngine 来加载。说白了,MyApp 只是一个组件,等着被原生代码「插」进去。

我个人的习惯

每次创建新模块,我会顺手做三件事:

  1. pubspec.yaml 里的 name——确保模块名跟项目命名规范一致,比如 com.example.my_flutter_module 这种格式。
  2. 删掉默认的 main.dart 里的示例代码——只保留一个空的 main() 函数,然后从零开始写业务逻辑。
  3. 创建 lib/src/ 目录——把业务代码都放在 src 下,main.dart 只做导出。这样结构更清晰。

小技巧:如果你想让模块支持热重载(Hot Reload),记得在原生工程里以 --debug 模式运行。我刚开始做迁移时,总以为模块不能热重载,后来发现是启动方式不对。

核心逻辑流程图

下面这张图帮你理清 Flutter Module 的创建和嵌入逻辑:

Flutter Module 创建与嵌入流程 步骤1:执行命令 flutter create --template module my_module 步骤2:生成项目结构 .android/ .ios/ lib/ test/ pubspec.yaml 注意:.android/.ios 为隐藏目录,自动生成 步骤3:编写 Dart 业务代码 lib/main.dart → 导出 MyApp 组件 无 runApp(),由原生工程控制启动 步骤4:原生工程通过 FlutterEngine 加载 Android: FlutterEngine / iOS: FlutterViewController 关键提醒 • 不要手动改 .android/ • main.dart 无 runApp() • 模块名要规范 • 支持热重载 • 依赖通过 pubspec.yaml • 原生配置通过插件 • 调试用 --debug 模式 • 发布用 --release 模式

避坑指南

我遇到过几个常见问题,给你提个醒:

  • 路径问题:创建模块时,最好在项目根目录下执行命令。如果你在子目录里创建,后面引用路径会变得很麻烦。
  • 命名规范:模块名不要用大写字母或特殊符号,Flutter 工具链对命名有要求。我习惯用下划线分隔,比如 payment_module
  • 版本兼容:确保你的 Flutter SDK 版本 >= 1.12,否则 --template module 可能不支持。老版本用的是 flutter create --module,参数不一样。

一句话总结:创建 Flutter Module 不难,难的是理解它跟普通 Flutter 项目的区别。记住——模块没有 runApp(),它等着被原生工程「请」进去。

好了,模块创建完了。下一步就是把它集成到你的 Android 项目里。别急,咱们下一章细聊。


公众号:蓝海资料掘金营,微信deep3321