OkHttp项目中applyOsgi与applyOsgiMultiplatform函数的详细分析

11 阅读2分钟

OkHttp项目中applyOsgi与applyOsgiMultiplatform函数的详细分析

1. 函数实现分析

1.1 applyOsgi函数

graph LR
    A[applyOsgi] --> B[创建osgi SourceSet]
    A --> C[配置osgiApi依赖]
    A --> D[配置Jar任务的BundleTaskExtension]
    D --> E[设置类路径]
    D --> F[应用bnd属性]
    A --> G[在Jar任务完成后添加OSGi元数据]
  • 设计目的:为标准JVM项目提供OSGi支持

  • 关键特性

  • 创建专用的osgi SourceSet

  • 自动添加Kotlin OSGi依赖

  • 灵活的bnd配置参数传递

1.2 applyOsgiMultiplatform函数

graph LR
    A[applyOsgiMultiplatform] --> B[创建main源集转发到jvmMain]
    A --> C[配置osgiApi依赖]
    A --> D[配置jvmJar任务的BundleTaskExtension]
    D --> E[设置类路径]
    D --> F[应用bnd属性]
    A --> G[在jvmJar任务完成后添加OSGi元数据]
  • 设计目的:解决Kotlin多平台项目与bnd工具的兼容性问题

  • 关键特性

  • 创建转发源集解决bnd工具对"main"源集的硬编码依赖

  • 特殊处理多平台项目的类路径

  • 更复杂的依赖管理

2. 函数应用差异

2.1 标准模块 vs 多平台模块

特性applyOsgi (标准模块)applyOsgiMultiplatform (多平台模块)
源集处理创建新的osgi SourceSet创建转发到jvmMain的main源集
任务配置直接配置Jar任务配置jvmJar任务
依赖管理相对简单需要处理多平台依赖
兼容性处理无特殊处理解决bnd工具与多平台的兼容性问题

2.2 实际应用示例

okhttp-tls模块 (applyOsgi) :

// 简单直接的应用方式
applyOsgi(
  "Export-Package: okhttp3.tls,okhttp3.tls.internal.*;okhttpinternal=true;mandatory:=okhttpinternal",
  "Import-Package: org.bouncycastle.*;resolution:=optional,*",
  "Automatic-Module-Name: okhttp3.tls",
  "Bundle-SymbolicName: com.squareup.okhttp3.tls"
)

okhttp主模块 (applyOsgiMultiplatform) :

// 更复杂的配置,处理多平台特性
applyOsgiMultiplatform(
  "Export-Package: okhttp3,okhttp3.internal.*;okhttpinternal=true;mandatory:=okhttpinternal",
  "Import-Package: " +
    "com.oracle.svm.core.annotate;resolution:=optional," +
    "org.conscrypt;resolution:=optional," +
    "org.bouncycastle.*;resolution:=optional," +
    "org.openjsse.*;resolution:=optional,*",
  "Automatic-Module-Name: okhttp3",
  "Bundle-SymbolicName: com.squareup.okhttp3"
)

3. 设计考量与技术实现

3.1 共同设计原则

1. 模块化配置

  • 将OSGi配置集中管理,避免重复代码

  • 提供一致的配置风格

2. 灵活的参数传递

  • 使用可变参数接受bnd配置

  • 允许模块自定义OSGi特性

3. 自动化处理

  • 自动添加必要的依赖

  • 在构建任务完成后自动生成OSGi元数据

3.2 特殊技术处理

applyOsgiMultiplatform中的转发源集

val mainSourceSet = object : SourceSet by jvmMainSourceSet {
  override fun getName() = "main"
  // 重写任务名称避免冲突
  override fun getProcessResourcesTaskName() = "${jvmMainSourceSet.processResourcesTaskName}ForFakeMain"
  // ...
}

这种设计解决了bnd工具对"main"源集的硬编码依赖问题,是多平台项目能够使用OSGi的关键。

4. 实际效果与最佳实践

4.1 生成的OSGi特性

两个函数最终都会生成包含以下特性的MANIFEST.MF文件:

  • 正确的Bundle标识信息

  • 精确的包导出控制

  • 灵活的包导入策略

  • Java模块系统兼容性

4.2 使用建议

1. 标准JVM项目

  • 使用applyOsgi

  • 保持bnd配置简洁

2. 多平台项目

  • 必须使用applyOsgiMultiplatform

  • 注意处理平台特定依赖

3. 配置原则

  • 明确导出公共API包

  • 合理使用optional和resolution指令

  • 保持与Java模块系统的一致性