Android Studio 導入自己編譯的 framework jar

網上的文章大多是 Android Studio 2.x 環境,實行起來,坑比較多。
本文適用於 Android Studio 3.x 及以上,親測可行。

一、編譯生成 framework.jar 包

系統級 App 開發,很多時候需要訪問 framework 層隱藏的接口(接口前的註釋里加了@hide),有時候甚至是定製的系統,在 framework 層加入了新的接口,爲了使用這些接口,需要自己編譯 framework 的源碼生成 jar 包,如果編譯 debug 版本,直接把 out/target/product/projectXX/system/framewor framework.jar 下面拷出來,
如果是 user 版本:
Android N/O:
out/target/common/obj/JAVA_LIBRARIES/framework_intermediates/classes.jar
Android P/Q:
out/soong/.intermediates/frameworks/base/framework/android_common/combined/framework.jar
Android R:
out/soong/.intermediates/frameworks/base/framework-minus-apex/android_common/combined/framework-minus-apex.jar

二、將 framework.jar 導入 Android Studio 工程

  1. 將framework.jar放在Module的libs下面

    add lib

  2. 添加對 framework.jar 的依賴
    在 module 的 build.gradle 文件中添加:

repositories {
    flatDir {
        dirs 'libs'
    }
}

同時, dependencies 中添加依賴:

dependencies {
    compileOnly fileTree(dir: 'libs', include: ['*.jar'])
}

注意:
使用 compileOnly(默認是 implementation),compileOnly 表示 jar 包只參與編譯,不會打包進去。

如果同時還需要依賴其它 jar 包,並且其它需要打包進去,則分開對每個 jar 包單獨進行依賴。

compileOnly files('libs/framework.jar')
implementation files('libs/XXX.jar')
  1. 在 module 的 build.gradle 文件中添加如下代碼:
gradle.projectsEvaluated {
    tasks.withType(JavaCompile) {
        Set<File> fileSet = options.bootstrapClasspath.getFiles()
        List<File> newFileList =  new ArrayList<>();
        //"../framework.jar" 爲相對位置,需要參照着修改,或者用絕對位置
        newFileList.add(new File("libs/framework.jar"))
        newFileList.addAll(fileSet)
        options.bootstrapClasspath = files(newFileList.toArray())
    }
}
  1. 在 module 的 build.gradle 文件中,加入如下代碼:
preBuild {
    doLast {
        //此處文件名根據實際情況修改:
        def imlFile = file("../.idea/modules/xxxlib/xxx.xxxlib.iml")
        try {
            def parsedXml = (new XmlParser()).parse(imlFile)
            def jdkNode = parsedXml.component[1].orderEntry.find { it.'@type' == 'jdk' }
            parsedXml.component[1].remove(jdkNode)
            def sdkString = "Android API " + android.compileSdkVersion.substring("android-".length()) + " Platform"
            new Node(parsedXml.component[1], 'orderEntry', ['type': 'jdk', 'jdkName': sdkString, 'jdkType': 'Android SDK'])
            groovy.xml.XmlUtil.serialize(parsedXml, new FileOutputStream(imlFile))
        } catch (FileNotFoundException e) {
            // nop, iml not found
            println "no iml found"
        }
    }
}

這個 task 在編譯之前, 自動更改module.iml,將下面代碼會移動最後

<orderEntry type="jdk" jdkName="Android API 30 Platform" jdkType="Android SDK" />

才能在編譯時使用我們引入的 framework.jar。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章