当业务方的 Java 环境是 1.8 时,如果 SDK 是使用 Java 11 编译,则调用 SDK 相关代码的地方在编译时将会报错:
类文件具有错误的版本 55.0(jdk 11), 应为 52.0(jdk 8)
所以,SDK 在非必要情况下,Java 版本尽量兼容到最低,除非遇到特殊情况,例如 SDK 需要适配 Android 12,但 Deprecated 的 ElementType�.MODULE 标明需要 Java 9 才支持,SDK 被迫要升级 Java 版本,这种情况也能允许,但对外提供的接入文档最好明确标明最低的 Java 版本。
META-INF/xxxx_release.kotlin_module: Module was compiled with an incompatible version of Kotlin. The binary version of its metadata is 1.9.0, expected version is 1.7.1.
上面这类错误相信遇到的应该不少,Java 有一套自己的 JDK 判断准则,Kotlin 也有,Kotlin metadata 的版本来自 KGP 版本,也即意味着,当你的 SDK 使用高版本的 KGP 编译时,业务方要么编译不过,要么被迫升级 KGP 版本,这会使业务方因为升级 Kotlin 而带来其他业务的不稳定性。所以,如果非必要的情况下,尽量保持低版本的 KGP 版本,与 Java 版本类似;或是,SDK 就不要使用 Kotlin 来开发,减少影响业务方的变量。
参考文档:
组件依赖的 AndroidManifest.xml 会保留 minSdkVersion 与 targetSdkVersion, 业务方在打包时,如果 SDK(23) 的 minSdkVersion 比业务方(21)高的话,打包将会报错:
Manifest merger failed : uses-sdk:minSdkVersion 21 cannot be smaller than version 23 declared in library
如果业务方被迫升级 23 的话,将会导致业务项目机型覆盖面出现很大的问题,所以,在保障 SDK 兼容性的情况下,尽量将 minSdkVersion 调整到合适的版本
Dependency 'androidx.compose.ui:ui-geometry:1.3.0' requires libraries and applications that depend on it to compile against version 33 or later of the Android APIs. :app is currently compiled against android-32. Recommended action: Update this project to use a newer compileSdkVersion of at least 33, for example 33.
上面这个报错是在接入 Compose 依赖后报错的一个 app 工程 compileSDK 版本过低的问题,升级到 33 即可,这时我就在想了,一个依赖组件是怎么影响主工程的 compileSDK 版本的。从 External Libraries
也看不出来啥,只好看了下 transformed,惊喜发现:
image.png
可以通过 minCompileSdk 来控制主工程的最低 compileSDK 版本,这算是一个依赖版本的反向应用了。
配置 proguard-rules.pro 混淆,keep 住对外的接口与方法,混淆实现类,SDK 发布时,不带上 sourceJar,外部只能查看 class 文件,进一步增加外部观摩 SDK 核心代码难度
SDK 对外方法尽量向下兼容,如遇到必须要移除的,可提前几个版本将方法标注 @Deprecated 过期,并提供的新的调用方法,例如:
image.png
调用效果如下,将鼠标移至方法处会提示:
image.png
对外接口必须标明入参与返回值的可空与非空,避免业务方发生 NPE 问题,下面列个对比:
image.png
kotlin 调用效果:
image.png
Java 调用效果:
image.png
一个方法最基本的注释包括:
例如:
参考文档:
如果对外提供的 SDK 有多个依赖,并且不同版本可能会出现兼容性问题,则可以使用 Bom 来管理版本,例如官方示例 Using the Bill of Materials[3]:
dependencies {
// Import the Compose BOM
implementation platform('androidx.compose:compose-bom:2024.01.00')
implementation 'androidx.compose.material3:material3'
implementation 'androidx.compose.foundation:foundation'
}
material3 与 foundation 将会使用 compose-bom 定义的版本,未来 SDK 升级或是版本修复,都只需提供 compose-bom 的版本即可。
SDK 提供抽象接口,业务方依赖接口调用,这么做的好处是,业务方面向接口调用使用简单,还能避免使用不稳定的内部实现,并且,内部实现可以进行混淆。
如果 SDK 有针对一些系统版本兼容的处理,则不仅仅通过 Build.VERSION.SDK_INT 来判断机型版本就够了,还要判断应用的 targetSdkVersion 版本,避免业务方使用的 targetSdkVersion 比系统兼容版本低而导致没有效果的现象。
例如 Android 12 新增的 BLUETOOTH_SCAN 权限,SDK 内部判断 SDK_INT 是否大于 Android 12,可业务方的 targetSdkVersion 并没有适配 12,清单文件也不会申明该权限,因此,该判断可能会发生不可预知的错误,所以,这里最好再做下 targetSdkVersion 的判断。
参考文档:
SDK 难免会依赖一些三方库,如果业务方依赖的三方库版本比 SDK 依赖的三方库高,并且三方库兼容性差,则可能会出现 SDK 使用到三方库的一些 api 调用发生类找不到、方法找不到等异常,这似乎并没有好的解决办法,但也不是不能解:
[1]
Kotlin 填坑记之 Compatibility: https://johnsonlee.io/2022/12/07/do-you-really-know-kotlin-compatibility/
[2]
Javadoc 规范: https://www.damo.icu/pages/javadoc/#_1-%E6%A6%82%E8%BF%B0
[3]
Using the Bill of Materials: https://developer.android.com/jetpack/compose/bom
[4]
5.2.1 一个检查更新的功能: https://juejin.cn/post/6844904193082261518?searchId=20240201160831B97DABD23F9EDF22AF8A#heading-20