虽然在开发中使用隐藏API是不推荐的,但是为了一些需求,还是得做的。
获取安卓架包
在sdk中这个包叫做android.jar,有两种方式,
第一种方式 从github上获取,android-hidden-api,下载对应安卓版本的android.jar文件
第二种方式 从编译完成的安卓源码中获取,
在安卓源码目录/out/target/common/obj/JAVA_LIBRARIES/framework_intermediates获取一个叫做classes.jar文件,如图所示:
添加架包至安卓studio
在安卓studio project中新建文件夹名为lib,名字无关紧要,将第一步获取的android.jar(这个名字也可以随便取)文件复制到lib文件夹下。如图所示:
编写子项目的build.gradle
什么是子项目?如图红框所示:
把guestuser称为子项目,根项目为AndroidRomLearn。
在子项目的build.gradle文件中添加framework.jar的依赖,如图所示:
编写根项目中的build.gradle
实现思路分为两步,第一步加载jar文件,在根项目的build.gradle文件中添加以下代码:
project('guestuser') {
gradle.projectsEvaluated {
tasks.withType(JavaCompile) {
options.compilerArgs.add('-Xbootclasspath/p:'lib/framework.jar)
}
}
}
其中add函数的参数 Xbootclasspath/p:是Java编译的寻址优先设置,不确定路径可以用绝对路径,目录结构和我之前展示的一样无需使用绝对路径,绝对路径需对路径符号“/”进行转义,"\\"
第二步,降低安卓sdk 的优先级。先看一个文件名为guestuser.iml,以子项目名称命名的文件,如图所示:
其部分内容如下所示:
这些orderEntry标签的从上到下顺序决定了在碰到同包名同类名的情况下的架包的顺序,默认情况下sdk是排在第二位的,现在要做的是将sdk标签位置置后。
在根项目中的build.gradle文件中添加一个方法,如下所示:
def pushDownSDK(iml) {
def imlFile = file(iml)
try {
def parsedXml = (new XmlParser()).parse(imlFile)
def jdkIndexOf = parsedXml.component[1].orderEntry.findIndexOf { it.'@type' == 'jdk' }
if (jdkIndexOf <= 1) {
def jdkNode =parsedXml.component[1].orderEntry.find { it.'@type' == 'jdk' }
parsedXml.component[1].remove(jdkNode)
new Node(parsedXml.component[1], 'orderEntry',['type': 'jdk', 'jdkName': 'Android API 26 Platform', 'jdkType': 'Android SDK'])
def writer = new StringWriter()
new XmlNodePrinter(new PrintWriter(writer)).print(parsedXml)
imlFile.text = writer.toString()
println "Push File: $iml jdk priority ok"
groovy.xml.XmlUtil.serialize(parsedXml,new FileOutputStream(imlFile))//简书上有个blog因为少写这个,搞了我好久
}
} catch (Exception e) {
// do nothing
}
}
在项目编译完成后应用此方法:
project('guestuser') {
gradle.projectsEvaluated {
tasks.withType(JavaCompile) {
options.compilerArgs.add('-Xbootclasspath/p:lib/framework.jar')
}
}
gradle.buildFinished {
pushDownSDK("guestuser/guestuser.iml");
}
}
完整的build.gradle文件如下所示:
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
repositories {
google()
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.1.1'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
def pushDownSDK(iml) {
def imlFile = file(iml)
try {
def parsedXml = (new XmlParser()).parse(imlFile)
def jdkIndexOf = parsedXml.component[1].orderEntry.findIndexOf { it.'@type' == 'jdk' }
if (jdkIndexOf <= 1) {
def jdkNode =parsedXml.component[1].orderEntry.find { it.'@type' == 'jdk' }
parsedXml.component[1].remove(jdkNode)
new Node(parsedXml.component[1], 'orderEntry',['type': 'jdk', 'jdkName': 'Android API 26 Platform', 'jdkType': 'Android SDK'])
def writer = new StringWriter()
new XmlNodePrinter(new PrintWriter(writer)).print(parsedXml)
imlFile.text = writer.toString()
println "Push File: $iml jdk priority ok"
groovy.xml.XmlUtil.serialize(parsedXml,new FileOutputStream(imlFile))
}
} catch (Exception e) {
// do nothing
}
}
allprojects {
repositories {
google()
jcenter()
}
}
project('guestuser') {
gradle.projectsEvaluated {
tasks.withType(JavaCompile) {
options.compilerArgs.add('-Xbootclasspath/p:lib/framework.jar')
}
}
gradle.buildFinished {
pushDownSDK("guestuser/guestuser.iml");
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}
重新编译项目就可以使用隐藏的api了
编写lint.xml抑制错误
在使用AndroidMainfest.xml配置了系统权限时,android studio会报错,导致无法编译,如下图所示:
在开发系统应用时这是不行的,所以需要一个方法抑制这个报错,lint.xml就是这个方法,在子项目中添加一个lint.xml文件,内容如下:
<?xml version="1.0" encoding="utf-8"?>
<lint>
<issue id="ProtectedPermissions" severity="warning"/>
</lint>
其中ProtectedPermissions定义了系统级别的权限,降为警告就行了