前语
最近工作需求在项目中集成体系的 framework.jar,以此来调用体系的定制功用,可是依照之前计划装备之后发现无法调用 framework.jar 中的办法,默许使用的仍是 Android SDK 里边的办法。
通过一系列的排查之后总算找到解决计划,做此分享。
集成 framework.jar 计划
导入 framework.jar
首先将 framework.jar 导入项目中,以一个简略 Demo 项目举例,项目中有一个 app 模块,项目结构如下(只列出了关键文件)
# 项目结构
Demo
|---- .idea
| |---- modules
| | |---- app
| | | |---- Demo.app.main.iml
|---- app
| |---- libs
| |---- src
| |---- build.gradle.kts
|---- build.gradle.kts
|---- settings.gradle.kts
- 将 framework.jar 文件复制到
Demo/app/libs
途径下; - 在
Demo/app/build.gradle.kts
文件中增加依靠:
dependencies {
...
// 增加 framework.jar,仅编译
compileOnly(files("libs/framework.jar"))
}
装备依靠优先级
仅仅在项目中导入 framework.jar 是没有作用的,你会发现之前被标记为 @hide
的接口现在仍是不能使用,导入的 framework.jar 中的定制办法仍是不能调用,与之前不同的是此刻你能够调用 framework.jar 中体系原生不存在的类,这样的作用当然不能让咱们满意。
这是由于默许情况下,Android SDK 中的资源优先级是高于手动导入的资源的,因此咱们需求手动修正这个优先级,这部分界说在项目根目录下 .idea/modules/app/xxxx.iml
中,所以接下来需求在对应模块的 build.gradle.kts
中增加装备。
在 Demo 项目中,咱们要在 Demo/app/build.gradle.kts
中修正:
import groovy.namespace.QName
import groovy.util.Node
import groovy.xml.XmlParser
import groovy.xml.XmlUtil
import java.io.FileOutputStream
...
project.tasks.preBuild.get().doLast {
// 在 preBuild 使命履行完之后处理
// 界说修正 .iml 文件中 Android SDK 优先级办法
fun changeSdkOrder(path: String) {
runCatching {
val imlFile = File(path)
with(XmlParser().parse(imlFile)) {
// 从 .iml 文件中读取 NewModuleRootManager 节点
val rootManagerComponent = getAt(QName.valueOf("component"))
.map { it as Node }
.first { it.attribute("name") == "NewModuleRootManager" }
// 从 NewModuleRootManager 节点中获取 Android SDK 装备节点
val jdkEntry = rootManagerComponent.getAt(QName.valueOf("orderEntry"))
.map { it as Node }
.first { it.attribute("type") == "jdk" }
// 保存节点参数
val jdkName = jdkEntry.attribute("jdkName")
val jdkType = jdkEntry.attribute("jdkType")
println("> Task :${project.name}:preBuild:doLast:changedSdkOrder jdkEntry = $jdkEntry")
// 从 NewModuleRootManager 节点中移除 Android SDK 装备节点
rootManagerComponent.remove(jdkEntry)
// 重新将 Android SDK 装备节点增加到 NewModuleRootManager 的最后
rootManagerComponent.appendNode(
"orderEntry", mapOf(
"type" to "jdk",
"jdkName" to jdkName,
"jdkType" to jdkType
)
)
// 将新生成的 .iml 写入文件
XmlUtil.serialize(this, FileOutputStream(imlFile))
}
}
}
// 修正 .iml 文件
println("> Task :${project.name}:preBuild:doLast:changedSdkOrder")
changeSdkOrder(rootDir.absolutePath + "/.idea/modules/app/Demo.app.main.iml")
}
办法 changeSdkOrder
的参数为模块对应的 .iml
装备文件途径,可依照自己的项目装备,按需修正。
如此一来,在项目中就能够纵情的使用 framework.jar 中的办法了。
装备引导类途径
阅历了上面两个过程的装备,在开发过程中现已能够正常使用 framework.jar 中的内容的,在本地 Android Studio 中也能正常编译运行,可是假如你们公司装备在服务器编译构建就仍是会报错,那就需求在项目根目录的 build.gradle.kts
中增加相关装备。
在 Demo 项目中,咱们要在 Demo/build.gradle.kts
中修正:
...
allprojects {
beforeEvaluate {
// framework.jar 途径
val path = rootDir.absolutePath + "/app/libs/framework.jar"
tasks.withType<JavaCompile> {
// 低版别 gradle 的计划
options.compilerArgs.add("-Xbootclasspath/p:$path")
// 高版别 gradle 的计划
val newFileList = mutableListOf<File>()
newFileList.add(File(path))
options.bootstrapClasspath?.files?.let { oldFileList ->
newFileList.addAll(oldFileList)
}
options.bootstrapClasspath = files(*newFileList.toTypedArray())
}
}
}
通过上面的装备,咱们将 framework.jar 增加到引导类途径中,无论是在本地仍是在服务器构建,就都不会出现问题了。
高版别 Android Studio 适配
讲了这么多,总算到了咱们这篇文章的重点,便是高版别 Android Stuido (这里特指 3.6.3
之后的版别)的适配。
作者这边使用的 Android Studio 版别是 Iguana
,依照上面的过程装备完之后发现并没有起作用,详细现象便是导入的 framework.jar 中的定制办法不能调用,只能够调用 framework.jar 中体系原生不存在的类,那不便是 依靠优先级 的装备失效了吗,打开 Demo/.idea/modules/app/Demo.app.main.iml
文件,发现里边只剩简略的几行装备,依靠优先级 相关的几个节点都没有了,那该怎样装备?
通过屡次 Google、百度、Bing 无果,能找到的都是已知的装备,终究找到了 Android Studio 中的一个装备项,途径在 File -> Settings -> Build, Execution, Deployment -> Build Tools -> Gradle 中,有一个 Generate *.iml files for modules imported from Gradle
,把这个选项勾选上,restart Android Studio,.iml
文件中的装备就康复了。
通过多个版别的屡次尝试,终究发现:在 Android Studio 3.6.3
版别及以前,Generate *.iml files for modules imported from Gradle
选项默许是勾选上的,而在 3.6.3
之后的版别,该选项默许是没有勾选的。阅历了九九八十一难,总算解决了这个奇葩的问题,感谢各位的观看!
文章作者: WangJie0822
文章链接: www.wangjie0822.top/posts/d0b7d…
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 WangJie0822!