1. 跨平台项目初始化与目录结构设计
为什么初始化阶段就要设计目录结构
跨平台项目最容易失控的地方不是业务代码,而是平台差异代码的散落。如果一开始就把 Android、iOS、Web、Windows、macOS 的适配代码混在业务目录里,后续每加一个平台都会牵动全局。因此初始化阶段的核心任务只有两件:建立一套共享代码库,以及用目录边界把平台差异隔离在固定位置。
本例采用 Flutter 作为跨平台骨架(同一套 Dart 代码可编译到移动端与桌面端),目录设计遵循一条原则:共享层只依赖抽象接口,平台层只负责实现接口。这样新增平台时只需新增一个平台目录,而不修改共享层。
目录结构设计
下面是一套可直接落地的目录骨架,核心是把代码分为 core(与平台无关的共享层)、platform(平台差异实现)、features(业务功能)三层:
cross_platform_app/
├── lib/
│ ├── main.dart # 入口,按平台选择适配实现
│ ├── core/ # 共享层:不 import 任何平台库
│ │ ├── models/ # 数据模型
│ │ ├── services/ # 业务服务(依赖抽象接口)
│ │ └── contracts/ # 平台能力抽象接口
│ │ └── platform_info.dart
│ ├── platform/ # 平台差异层:只实现 contracts
│ │ ├── platform_info_stub.dart # 默认/兜底实现
│ │ ├── platform_info_mobile.dart # Android / iOS
│ │ ├── platform_info_desktop.dart # Windows / macOS / Linux
│ │ └── platform_info_web.dart # Web
│ └── features/ # 业务功能,只依赖 core
│ └── home/
│ └── home_page.dart
├── test/
│ └── core/ # 共享层可脱离平台单测
├── pubspec.yaml
└── analysis_options.yaml
关键实现:用条件导入隔离平台差异
Dart 的条件导入(conditional import)让同一份共享代码在不同平台编译时自动选择对应实现,这是目录隔离能真正生效的机制。
先在 core/contracts/platform_info.dart 定义抽象接口:
// lib/core/contracts/platform_info.dart
abstract class PlatformInfo {
String get platformName;
bool get isDesktop;
}
// 条件导入:默认用 stub,移动端/桌面端/Web 各自替换
import 'package:cross_platform_app/platform/platform_info_stub.dart'
if (dart.library.io) 'package:cross_platform_app/platform/platform_info_io.dart'
if (dart.library.js_interop) 'package:cross_platform_app/platform/platform_info_web.dart'
as impl;
PlatformInfo createPlatformInfo() => impl.createPlatformInfo();
其中 platform_info_io.dart 再根据 Platform.isAndroid / Platform.isWindows 等运行时判断,返回移动端或桌面端实现。共享层只调用 createPlatformInfo(),永远不直接 import 平台库。
初始化命令与验证
- 创建工程:
flutter create --platforms=android,ios,windows,macos,web cross_platform_app - 按上面的结构建立
core/、platform/、features/三个目录。 - 在
main.dart中调用createPlatformInfo(),把platformName显示在首页。 - 验证:分别运行
flutter run -d windows与flutter run -d chrome,首页应显示不同平台名,而core/与features/代码完全未改动。
判断目录设计是否合格的标准:删除任意一个
platform/ 下的文件,只有对应平台编译失败,其余平台不受影响。可扩展性检查清单
| 检查项 | 合格标准 | 不合格信号 |
|---|---|---|
| 共享层纯净度 | core/ 中无 dart:io、dart:html 等平台库 | core 里出现 Platform.isAndroid |
| 接口收敛 | 平台能力都定义在 contracts/ | 业务代码直接 import platform 目录 |
| 新增平台成本 | 只新增一个实现文件 | 需要改动 core 或 features |
| 可测试性 | test/core/ 可脱离设备运行 | 单测必须启动模拟器 |
不要把平台判断写成散落的
if (Platform.isAndroid)。一旦这类判断超过三处,目录隔离就形同虚设,应立刻收敛回 contracts/ 接口。