概述

在Android Studio环境开发APP依赖的android.jar中不包含系统源码中的隐藏api,最终编译apk时无法通过.
少量的系统api在Android Studio中可以通过反射调用,或者在源码环境下编译.
不过在源码环境编译相对效率较低,通过在gradle进行一些配置即可编译依赖源码编译最终生成的framework.jar.

从out文件夹获取对应jar包

out是Android源码编译后生成的内容,对应版本的framework和core还有support的jar都生成在out/target/common/obj/JAVA_LIBRARIES/
比如framework的class.jar在framework_intermediates

添加依赖

将jar命名为对应内容,拷贝到AS的module下存放jar包的位置,默认为module根目录下的libs文件夹.

在module的build.gradle的dependencies中添加编译依赖 compileOnly files('libs/framework.jar')

针对framework.jar需要额外配置的内容

  1. 添加到构建参数

    gradle.projectsEvaluated {
    tasks.withType(JavaCompile) {
    options.compilerArgs << '-Xbootclasspath/p:xxxx/libs/framework.jar' //xxx为你的module名称
    }
    }

    如果需要对整个Project生效,直接配置到Project的build.gradle中的allprojects节点即可,但是这会造成你所有的module构建时优先依赖这个版本的framework.jar
    比如findViewById的泛型方式是添加于很后面的版本,如果framework.jar中是旧版本,会造成其他已经使用新的api的出现报错.
    仅对单个module添加构建参数直接将根.gradle中的allprojects全部复制到对应module的.gradle中即可

  2. 修改依赖的jar权限高于android.jar
    添加了构建参数之后还是会继续报错,还是优先依赖了Android Studio中自带的android.jar,需要修改依赖优先级.
    依赖的优先级在编译临时生成的.iml文件中,依据最底部的orderEntry节点的顺序,可以手动修改,但直接或自动触发sync之后都会造成重建.
    直接在module中针对构建操作时添加调序处理,处理的内容就是找到type为jdk和包含android-的内容调到最后.

    <orderEntry type="jdk" jdkName="Android API 28 Platform" jdkType="Android SDK"/>
    <orderEntry type="library" name="Gradle: android-android-xx" level="project"/>

    在module的gradle中添加如下内容:
    意思是在预构建的最后进行xml节点操作,try必须包含,因为在linux环境下不会生成这个iml文件

    preBuild {
    doLast {
    def imlFile = file(project.name + ".iml")
    println('Change ' + project.name + '.iml order')
    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 groovy.util.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
    }
    }
    }

    在Android Studio的4.0版本之后,iml文件生成到了.idea文件夹中,需要进行修改
    修改imlFile的路径为../.idea/modules/${project.name}/" + project.name + ".iml即可

    def imlFile = file("../.idea/modules/${project.name}/" + project.name + ".iml")

总结

进行如上操作后,即可在android studio的ide环境中依靠源码编译的framework.jar进行开发访问hide的api,即使有时候会显示为红色,但是最终也能正常通过编译.
framework.jar仅仅进行编译依赖,并不会包含到apk中,实际运行时是调用的系统中的内容.
注意不同版本的framework有差异,如果调用的方法在其他版本上没有,运行时即会报错.