Android SDK 中有很多带有 @hide 注解的 api,这些API为系统隐藏的 api,上层应用无法直接调用。我们开发时如果必须使用有两种方式,一是利用java反射机制。二则是在我们项目中导入 Android 系统源码编译出的classes.jar 包,该 jar 包生成在out/target/common/obj/JAVA_LIBRARIES/framework_intermediates/classes.jar。这里我重点介绍Android Studio如何导入classes.jar.
1.考虑到 libs 目录下可能会有其他 jar 包,我们在app目录下建立 syslibs 文件夹,并将 classes.jar 包放入该路径,因为这里的 classes.jar 包只用于编译,无须打包进 apk 中。
2.右键工程–>【Open Module Settings】,点击左侧【Dependencies】,选择app,点击【+】选择【2 Jar Dependency】,添加jar包,如下图。
3.经过步骤2之后,Module的build.gradle中,dependencies自动增加依赖配置 如下:
implementation files('syslibs\\classes.jar')
修改为:
1 | compileOnly files('syslibs\\classes.jar') |
这么做是因为我们使用该jar包只用于编译,不打包进apk中,该包里包含的是Android SDK,当apk运行到手机里时,手机里有运行所需的sdk环境。
4.project 的 build.gradle添加如下代码:
1 | gradle.projectsEvaluated { |
添加位置如下:
5.修改jar包优先级,在Moduels的app.iml文件中找到我们的classes.jar包所在行
1 | <orderEntry type="library" name="Gradle: __local_aars__:D.\AndroidStudioProjects\Blue\app\syslibs\classes.jar:unspecified@jar" level="project" /> |
将其移动到
1 | <orderEntry type="jdk" jdkName="Android API 28 Platform" jdkType="Android SDK" /> |
之上。
这么做是为了让项目编译时优先用我们提供的jar包里的SDK,而不是原有Android SDK。
6.经过第5步之后,就能正常使用我们jar里的SDK了,但是,每次编译之后,app.iml 中的
1 | <orderEntry type="jdk" jdkName="Android API 28 Platform" jdkType="Android SDK" /> |
又会被移动到最上面。下次编译时我们又得将他移动到
1 | <orderEntry type="library" name="Gradle: __local_aars__:D.\AndroidStudioProjects\Blue\app\syslibs\classes.jar:unspecified@jar" level="project" /> |
的后面,这样比较麻烦。网上提供了一种一劳永逸的方法,将下面的代码加入到Moudle的build.gradle里:
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 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
}
}
}
加入位置如下:
至此,classes.jar导入完成,我们可以在Android Studio里可以直接调用系统隐藏的api里,如果遇到某些系统隐藏的api在使用时报红,一般为ide为bug,可以尝试clean project,然后rebuild project恢复正常了