如何组织合理稳定的Flutter工程结构?

06-01 1376阅读

在软件开发中,我们不仅要在代码实现中遵守常见的设计模式,更需要在架构设计中遵从基本的设计原则。而在这其中,DRY(即 Don’t Repeat Yourself)原则可以算是最重要的一个。通俗来讲,DRY 原则就是“不要重复”。这是一个很朴素的概念,因为即使是最初级的开发者,在写了一段时间代码后,也会不自觉地把一些常用的重复代码抽取出来,放到公用的函数、类或是独立的组件库中,从而实现代码复用。在软件开发中,我们通常从架构设计中就要考虑如何去管理重复性(即代码复用),即如何将功能进行分治,将大问题分解为多个较为独立的小问题。而在这其中,组件化和平台化就是客户端开发中最流行的分治手段。

组件化

组件化又叫模块化,即基于可重用的目的,将一个大型软件系统(App)按照关注点分离的方式,拆分成多个独立的组件或模块。每个独立的组件都是一个单独的系统,可以单独维护、升级甚至直接替换,也可以依赖于别的独立组件,只要组件提供的功能不发生变化,就不会影响其他组件和软件系统的整体功能。

4f49b09f5bc9fd33db010d9286ae2e82.webp

组件化的中心思想是将独立的功能进行拆分,而在拆分粒度上,组件化的约束则较为松散。一个独立的组件可以是一个软件包(Package)、页面、UI 控件,甚至可能是封装了一些函数的模块。

组件的粒度可大可小,那我们如何才能做好组件的封装重用呢?哪些代码应该被放到一个组件中?这里有一些基本原则,包括单一性原则、抽象化原则、稳定性原则和自完备性原则。

单一性原则指的是,每个组件仅提供一个功能。分而治之是组件化的中心思想,每个组件都有自己固定的职责和清晰的边界,专注地做一件事儿,这样这个组件才能良性发展。

一个反例是 Common 或 Util 组件,这类组件往往是因为在开发中出现了定义不明确、归属边界不清晰的代码:“哎呀,这段代码放哪儿好像都不合适,那就放 Common(Util)吧”。久而久之,这类组件就变成了无人问津的垃圾堆。所以,遇到不知道该放哪儿的代码时,就需要重新思考组件的设计和职责了。

抽象化原则指的是,组件提供的功能抽象应该尽量稳定,具有高复用度。而稳定的直观表现就是对外暴露的接口很少发生变化,要做到这一点,需要我们提升对功能的抽象总结能力,在组件封装时做好功能抽象和接口设计,将所有可能发生变化的因子都在组件内部做好适配,不要暴露给它的调用方。

稳定性原则指的是,不要让稳定的组件依赖不稳定的组件。比如组件 1 依赖了组件 5,如果组件 1 很稳定,但是组件 5 经常变化,那么组件 1 也就会变得不稳定了,需要经常适配。如果组件 5 里确实有组件 1 不可或缺的代码,我们可以考虑把这段代码拆出来单独做成一个新的组件 X,或是直接在组件 1 中拷贝一份依赖的代码。

自完备性,即组件需要尽可能地做到自给自足,尽量减少对其他底层组件的依赖,达到代码可复用的目的。比如,组件 1 只是依赖某个大组件 5 中的某个方法,这时更好的处理方法是,剥离掉组件 1 对组件 5 的依赖,直接把这个方法拷贝到组件 1 中。这样一来组件 1 就能够更好地应对后续的外部变更了。

我们再来看看组件化的具体实施步骤

首先,我们需要剥离应用中与业务无关的基础功能,比如网络请求、组件中间件、第三方库封装、UI 组件等,将它们封装为独立的基础库;然后,我们在项目里用 pub 进行管理。如果是第三方库,考虑到后续的维护适配成本,我们最好再封装一层,使项目不直接依赖外部代码,方便后续更新或替换。

基础功能已经封装成了定义更清晰的组件,接下来就可以按照业务维度,比如首页、详情页、搜索页等,去拆分独立的模块了。拆分的粒度可以先粗后细,只要能将大体划分清晰的业务组件进行拆分,后续就可以通过分布迭代、局部微调,最终实现整个业务项目的组件化。

在业务组件和基础组件都完成拆分封装后,应用的组件化架构就基本成型了,最后就可以按照刚才我们说的 4 个原则,去修正各个组件向下的依赖,以及最小化对外暴露的能力了。

Flutter 项目组件化(模块化)实现

下面以命令行(CLI)为主,演示如何在 Flutter 中快速搭建一个多模块工程。


一、目录规划

建议项目结构如下:

 

bash

代码解读

复制代码

/my_app # 主工程 ├── pubspec.yaml └── lib /modules # 存放各功能模块 ├── auth_module └── profile_module


二、创建主工程

 

bash

代码解读

复制代码

# 在任意工作目录下 flutter create my_app cd my_app


三、创建 Dart 功能包模块

我们使用 --template=package 来生成纯 Dart 包

 

ini

代码解读

复制代码

# 回到项目根目录 cd .. # 创建存放模块的文件夹 mkdir modules cd modules # 创建两个功能模块:auth_module、profile_module flutter create --template=package --org com.example auth_module flutter create --template=package --org com.example profile_module

此时,modules/auth_module/lib/ 下已有一个示例 Dart 文件。你可以在各模块内按需组织代码、资源、依赖。


四、在主工程中引入模块

编辑 my_app/pubspec.yaml,在 dependencies: 下加入本地路径依赖:

 

yaml

代码解读

复制代码

dependencies: flutter: sdk: flutter # 本地模块依赖 auth_module: path: ../modules/auth_module profile_module: path: ../modules/profile_module

执行:

 

arduino

代码解读

复制代码

cd my_app flutter pub get

这样,主工程就可以:

 

arduino

代码解读

复制代码

import 'package:auth_module/auth_module.dart'; import 'package:profile_module/profile_module.dart';


五、Android 平台配置

若模块中含有 Android 原生代码(如使用 --template=plugin 创建的模块),需在主工程的 android/settings.gradle 和 android/app/build.gradle 中注册子项目。

  1. 打开 my_app/android/settings.gradle,末尾添加:

     

    php

    代码解读

    复制代码

    include ':auth_module' project(':auth_module').projectDir = file('../modules/auth_module/android') include ':profile_module' project(':profile_module').projectDir = file('../modules/profile_module/android')
  2. 打开 my_app/android/app/build.gradle,在 dependencies 中引入:

     

    java

    代码解读

    复制代码

    dependencies { implementation project(':auth_module') implementation project(':profile_module') // ... 其他依赖 }
  3. 再次同步并运行:

     

    arduino

    代码解读

    复制代码

    cd my_app flutter clean flutter run

六、iOS 平台配置

同理,若模块内含 iOS 原生代码,需要在主工程的 iOS Podfile 中添加路径依赖:

  1. 打开 my_app/ios/Podfile,在 target 'Runner' do 内加入:

     

    ini

    代码解读

    复制代码

    pod 'auth_module', :path => '../modules/auth_module/ios' pod 'profile_module', :path => '../modules/profile_module/ios'
  2. 安装 Pod:

     

    bash

    代码解读

    复制代码

    cd my_app/ios pod install
  3. 回到根目录,运行:

     

    arduino

    代码解读

    复制代码

    cd .. flutter clean flutter run

七、模块化开发流程建议

  1. 代码隔离

    • 每个模块内部只关心自身功能,公用工具抽到 common 或 core 模块。
    • 版本管理

      • 模块也可以发布到私有或公有 Dart 仓库,使用版本号管理依赖。
      • 单元测试与 CI

        • 各模块独立维护测试用例,CI Pipelines 可针对单模块或全量运行。

通过以上步骤,即可快速搭建一个基于 CLI 的 Flutter 多模块工程,实现关注点分离、可复用、易维护的组件化结构。

八、如何将一个 Flutter/Dart 模块发布到公有仓库(pub.dev),以及如何在主工程中使用语义化版本号管理依赖。


1. 在 pub.dev 上创建 API Token

  1. 打开 pub.dev ,登录你的 Google/GitHub 帐号。
  2. 点击右上角头像 → Account → API tokens → Create token。
  3. 复制生成的 token(形如 xxxxxxxxxxxxxxxxxxxxxxxx),后续在本地配置使用。

2. 在本地添加认证凭据

方法 A:使用 dart pub token(推荐)

macOS 终端执行:

 

csharp

代码解读

复制代码

# 将 替换为上一步获得的 token dart pub token add --server=https://pub.dev

  • 该命令会把凭据写入 ~/.config/dart/pub-credentials.json,以后 dart pub publish 或 flutter pub publish 都能自动生效。
    方法 B:环境变量(不太常用)
     
    

    ini

    代码解读

    复制代码

    export PUB_TOKEN= # 可选:把这一行加到 ~/.zshrc 或 ~/.bash_profile 以便每次登录都生效


    3. 配置模块的 pubspec.yaml

    在你的模块目录(如 modules/auth_module)下,确保 pubspec.yaml 包含:

     
    

    yaml

    代码解读

    复制代码

    name: auth_module description: A reusable authentication module for Flutter apps. version: 1.0.0 # 遵循 SemVer homepage: https://example.com/auth_module # 可选 author: Your Name # 可选 publish_to: https://pub.dev # 发布到公有仓库(也可删掉此行,默认为 pub.dev)

    • version:MAJOR.MINOR.PATCH

      • MAJOR:不兼容的 API 变更
      • MINOR:向下兼容的新功能
      • PATCH:向下兼容的 Bug 修复

        4. 预检发布(dry run)

        在模块根目录运行:

         
        

        bash

        代码解读

        复制代码

        cd modules/auth_module dart pub publish --dry-run

        • 修正 pubspec.yaml 警告(如缺少描述、缺少 LICENSE 等)。
        • 确保所有示例代码、README、CHANGELOG 都准备齐全。

          5. 正式发布

           
          

          rust

          代码解读

          复制代码

          dart pub publish

          • 如果使用 Flutter 项目,也可运行 flutter pub publish,效果一样。
          • 按提示确认,一旦发布成功,你的包就能在 pub.dev/ 上找到。

            6. 在主工程中使用版本号管理依赖

            编辑主工程 pubspec.yaml,在 dependencies: 下加入:

             
            

            yaml

            代码解读

            复制代码

            dependencies: flutter: sdk: flutter # 使用 caret 语法,接受 1.0.x 的所有版本,但 =1.0.0

免责声明:我们致力于保护作者版权,注重分享,被刊用文章因无法核实真实出处,未能及时与作者取得联系,或有版权异议的,请联系管理员,我们会立即处理! 部分文章是来自自研大数据AI进行生成,内容摘自(百度百科,百度知道,头条百科,中国民法典,刑法,牛津词典,新华词典,汉语词典,国家院校,科普平台)等数据,内容仅供学习参考,不准确地方联系删除处理! 图片声明:本站部分配图来自人工智能系统AI生成,觅知网授权图片,PxHere摄影无版权图库和百度,360,搜狗等多加搜索引擎自动关键词搜索配图,如有侵权的图片,请第一时间联系我们。

目录[+]

取消
微信二维码
微信二维码
支付宝二维码