如何在Android Studio中添加自定义framework.jar?

这两天有一个新的功能需求要实现, 要在Android原生代码的Settings(代码目录android/frameworks/base/core/java/android/provider)数据库添加一个新的数据项, 一个系统应用(独立于Android系统源码编译)需要引用该数据项. 那么, 怎么将新的数据项引用到系统应用中了? <! – more –>

备注: 以下所有的示例都基于Android Studio 3.2/操作系统Ubuntu 18.04.1

首先, 在Android源码中修改完成后, 执行本地编译, 在/android/out目录下, 找到编译产生的新的framework模块的jar包:

1
out/target/common/obj/JAVA_LIBRARIES/framework_intermediates/classes-full-debug.jar

最开始, 打开该jar包, 将/android/provider/目录下的所有class文件复制到Android Studio中的SDK的platforms/android-23, 重新clean/build一次, 项目中对新建的数据项的符号引用立刻就正常了.但一提交到远程服务器, 后台编译出错, 提示找不到符号了~~~what!

马上就要发布版本了, 怎么办?只好硬着头皮找其他法子了…参考了网上已有的很多文档, 编译一直报错. 不得已开始想着要通过广播的形式来替换掉现有的通过ContentProvider的方式, 这样就避开修改Android SDK了, 但广播存在这么几个问题:

  • 任何人都可以监听接收该广播, 安全性与性能都大打折扣;
  • 如果接收方线程阻塞, 会导致广播超时, 造成应用ANR

整个需求的方案已经定了, 再去该明显会被打回的, 而且就该功能的实现而言, 只有在某个状态变化时, 才要求告知上层, 这个正是ContentProvider可以达成的逻辑. 转了一圈, 只好又回到原来的方案. 跟同事沟通了配置的方法, 编译终于通过, 但是验证测试时又碰到了问题….这里记录下来整个过程, 也算是为后来的Android SDK定制积攒点经验.

添加framework.jar到AS

将编译好的Android框架层jar包framework.jar放到/app/libs/下面, 然后在应用app的配置build.gradle下面添加一个依赖项, 这里的provided表示该依赖只在编译时起作用, 不会把对应的jar文件编译到最终的APK中去:

1
2
3
4
dependencies {
provided files('libs/framework.jar')
//compile fileTree(include: ['*.jar'], dir: 'libs')
}

将framework.jar设置为bootclass

为了让库生效, 需要在编译开始时, 将framework.jar设置为当前所有子项目的启动文件(boot class):

1
2
3
4
5
6
7
8
9
10
11
12
13

allprojects {
repositories {
jcenter()
}

// 设置为bootclass
gradle.projectsEvaluated {
tasks.withType(JavaCompile) {
options.compilerArgs << '-Xbootclasspath/p:app/libs/framework.jar'
}
}
}

同时, 还需要在app/build.gradle中添加一个编译的类路径(class path):

1
2
3
4
5
6
7
8
9

project.afterEvaluate {
JavaCompile javaTask = project.tasks.compileDebugAndroidTestJavaWithJavac
if (javaTask) {
FileCollection dependentFiles = javaTask.getClasspath()
dependentFiles = dependentFiles.plus(project.files('libs/framework.jar'))
javaTask.setClasspath(dependentFiles)
}
}

网上的大部分资料都说到了这一步就好了, 但是这时看引用的Java文件中, 仍然提示找不到新的符号, 重新看了下网络上的教程, 原来还需要更改下app.iml中的引用先后顺序.

修改app.iml中的库引用顺序

app.iml包含了某个项目的信息以及依赖状态, 找到framework.jar以及Android SDK对应的<orderEntry>, 将framework.jar对应的调整到Android SDK之前就可以了:

1
2
3
4
5
6

<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" exported="" name="app/libs/framework.jar:unspecified@jar" level="project" />
....
<orderEntry type="module" module-name="lib_config" exported="" />
<orderEntry type="jdk" jdkName="Android API 23 Platform" jdkType="Android SDK" />

在实际操作过程, 注意不要在app/build.gradle中添加如下两个配置, 不然编译虽然可以通过, 但是执行时会出现异常:

1
2
3
4
5

dependencies {
provided files('libs/framework.jar')
//compile fileTree(include: ['*.jar'], dir: 'libs')
}

参考资料