IDE环境下调用Android系统隐藏API
Comment概述
在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需要额外配置的内容
添加到构建参数
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中即可修改依赖的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有差异,如果调用的方法在其他版本上没有,运行时即会报错.