欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net

在这里插入图片描述

前言

之前我们介绍了 Kiwi。今天我们来聊聊另一个强有力的挑战者:auto_injector

在依赖注入(DI)的江湖中,主要分为两派:

  1. 运行时反射/查找派:如 GetItProvider。简单灵活,但运行时有轻微开销,且并在运行时抛出依赖缺失的错误。
  2. 编译时生成派:如 KiwiInjectableAutoInjector。在编译阶段通过代码生成解决依赖关系,类型安全零反射,性能极致。

auto_injector 属于第二派。虽然它的名气可能没有 Kiwi 大,但它在处理自动发现、模块化和参数注入方面有其独到之处。

对于 OpenHarmony 应用,编译时 DI 是首选,因为它不依赖 dart:mirrors(Flutter 不支持),且运行效率最高,符合鸿蒙系统对性能的高要求。

一、核心特性与对比

特性 AutoInjector Kiwi GetIt
原理 代码生成 (Build Runner) 代码生成 运行时 Service Locator
设置复杂度 中等 中等 简单
错误检测 编译时 编译时 运行时 (Crash)
样板代码 极少 多 (手动注册)

auto_injector 的独特优势

  • 更智能的自动发现机制。
  • 支持更复杂的参数注入。
  • 生成的代码结构非常清晰。

元数据

分析依赖

代码生成

加载

提供信息

源代码

AutoInjector 生成器

依赖解析器

di.g.dart

App

实例对象

二、集成与用法详解

2.1 添加依赖

dependencies:
  auto_injector: ^2.1.1

dev_dependencies:
  build_runner: ^2.4.0
  auto_injector_generator: ^2.1.1

2.2 基础用法

与其他生成器库类似,你需要定义一个“注册表”。

// di_container.dart
import 'package:auto_injector/auto_injector.dart';

// 引入需要注入的类
import 'services/api_service.dart';
import 'services/user_repository.dart';

part 'di_container.g.dart'; // 生成文件的名字

(
  // 在这里列出所有的注册类
  types: [
    AutoInjectorType(ApiService),
    AutoInjectorType(UserRepository),
  ],
)
class DIContainer extends _$DIContainer {} // 继承生成的类

在这里插入图片描述

2.3 类的定义

auto_injector 会自动检查构造函数。

class ApiService {
  // 无参构造
  ApiService();
}

class UserRepository {
  final ApiService api;
  // 自动注入 ApiService
  UserRepository(this.api);
}

2.4 生成与使用

运行:

dart run build_runner build

main.dart 中:

void main() {
  // 初始化容器
  final container = DIContainer();
  // 必须调用 commit() 来完成初始化 (这点很关键!)
  container.commit();

  // 获取实例
  final userRepo = container.resolve<UserRepository>();
}

在这里插入图片描述

三、OpenHarmony 适配与实战:模块化注入

在大型鸿蒙 APP 中,我们可能有很多功能模块(Module),比如 AuthModule, PaymentModuleauto_injector 支持将定义拆分。

3.1 定义多个容器

由于 auto_injector 将配置集中在注解参数里,拆分主要通过拆分注解配置来实现。

虽然 auto_injector 目前主要倾向于集中式管理,但我们可以通过 Dart 的 export 或者组合类来组织代码。

3.2 替换实现类 (Mock 与 Real)

在鸿蒙真机和本地测试之间切换实现。

abstract class LocationService {
  Future<Location> getLocation();
}

class SystemLocationService implements LocationService { ... }
class MockLocationService implements LocationService { ... }

(
  types: [
    // 将接口映射到实现
    AutoInjectorType(SystemLocationService, on: LocationService),
  ],
)
class ProdContainer extends _$ProdContainer {}

(
  types: [
    AutoInjectorType(MockLocationService, on: LocationService),
  ],
)
class TestContainer extends _$TestContainer {}

在初始化时,根据环境变量或配置选择不同的 Container。

3.3 解决循环依赖

编译时注入的一大好处是,如果 A 依赖 B,B 依赖 A,build_runner 在生成代码时就会报错(StackOverflow 或 Cycle Detected),而不是等到 APP 启动死循环。auto_injector 的分析器会非常早地告诉你这个问题。

四、高级特性:Tag 与变换

auto_injector 支持对注入对象进行转换。

AutoInjectorType(
  MyService,
  // 比如:只作为单例使用
  scope: Scope.singleton, 
  // 初始化后立即执行的方法
  postConstruct: #init, 
)

五、总结

auto_injector 是一个非常稳健的 DI 库。相比于 Kiwi 的分散注解(在每个类头上写 @Register),auto_injector 采用集中配置(在容器类上写 List)。

这两种风格各有千秋:

  • Kiwi 风格:适合微服务式开发,每个开发者只管好自己的类。
  • AutoInjector 风格:适合集中管控,架构师可以在一个地方看到所有的依赖图谱。

对于 OpenHarmony 开发者,推荐在项目初期就引入编译时 DI。随着业务增长,它能有效防止代码变成“意大利面条”,确保架构的清晰度。

最佳实践

  1. 接口优先:始终针对 Interface 编程,在 DI 配置中绑定 Implementation。
  2. 区分 Scope:明确区分 Singleton(全剧单例)和 Factory(瞬态实例)。Service 层通常是 Singleton,Bloc/Cubit 层通常是 Factory。
  3. 定期清理:随着代码迭代,auto_injector 列表里可能会残留废弃的类,记得利用 IDE 的查找引用功能定期清理。

六、完整实战示例

import 'package:auto_injector/auto_injector.dart';

// 1. 定义抽象层
abstract class Api {
  String getBaseUrl();
}

// 2. 定义实现层
class ProdApi implements Api {
  
  String getBaseUrl() => 'https://api.prod.com';
}

class DevApi implements Api {
  
  String getBaseUrl() => 'https://dev.local';
}

class UserRepository {
  final Api _api;
  // 构造函数注入,不关心 Api 是谁实现的
  UserRepository(this._api);
  
  void login() => print('正在登录服务器: ${_api.getBaseUrl()}');
}

void main() {
  // 3. 配置容器(通常在 main.dart 初始化)
  final injector = AutoInjector(
    on: (injector) {
      // 注册单例:API 实现
      // 在开发环境,这里可以用 DevApi
      injector.addSingleton<Api>(ProdApi.new);
      
      // 注册工厂:Repo 依赖 API,自动解析
      injector.add<UserRepository>(UserRepository.new);
      
      // 提交配置,构建依赖图
      injector.commit();
    },
  );

  // 4. 业务中使用
  // 直接获取组装好的对象
  final repo = injector.get<UserRepository>();
  repo.login(); // Output: 正在登录服务器: https://api.prod.com
}

在这里插入图片描述

Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐