高版本 Android Studio 集成 framework.jar

高版本 Android Studio 集成 framework.jar

高版本 Android Studio 集成 framework.jar

前语

最近工作需求在项目中集成体系的 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
  1. framework.jar 文件复制到 Demo/app/libs 途径下;
  2. 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!