安卓源码环境下编译多module app
- 背景
- apk 源码结构
- 思路
- Android.bp编写
- c++静态库,动态库
- jar 或 aar
- 编译apk
- 将整个目录放到安卓源码下
背景
项目的背景是要将 android studio 下开发的 apk 源码,放到安卓系统源码中进行编译,并随系统版本发布。对于稍复杂一些的 apk,可能存在多模块,这类文章比较少。这里对于这类项目,本文至少可以提供一些实践及思路。
apk 源码结构
一个标准的 Android Studio apk 项目源码结构。
--app
----....//一些项目文件
----module1
------...//一些module文件
------src/main/java
------src/main/res
------src/main/cpp
------src/main/AndroidManifest.xml
----module2
------...//一些module文件
------src/main/java
------src/main/res
------src/main/cpp
------src/main/AndroidManifest.xml
----module3
------...//一些module文件
------src/main/java
------src/main/res
------src/main/cpp
------src/main/AndroidManifest.xml
思路
实际上 Android Studio 使用的 gradle 构建 apk,而安卓源码,使用Soong 构建系统。因此,需要编写 Android.bp 文件,才能将 apk 添加到源码构建过程中进行构建。
因为是在Android Studio中开发维护,尽量保留整体项目的结构,可以通过添加 Make 配置 和 Sonng 配置(.bp) 达到这样的目的。
--app
----Android.mk
----....//一些项目文件
----module1
------Android.bp
------...//一些module文件
------src/main/java
------src/main/res
------src/main/cpp
------src/main/AndroidManifest.xml
----module2
------Android.bp
------...//一些module文件
------src/main/java
------src/main/res
------src/main/cpp
------src/main/AndroidManifest.xml
----module3
------Android.bp
------...//一些module文件
------src/main/java
------src/main/res
------src/main/cpp
------src/main/AndroidManifest.xml
其中根目录的Android.mk很简单
include $(call all-subdir-makefiles)
作用也很简单,就是将当前目录下的所有子目录的 Make 配置(.mk)和 Soong 配置(.bp)全部包含进来。
我们在相应的每个module下,都创建了一个Android.bp,来完成每个 module 的构建工作。Anroid.mk,将他们联合到一起。在不改变目录结构,和原有项目完整性的基础上,通过添加 Android.mk 和 Android.bp,对原有代码无侵入的完成整合。
接下来就是各个module的Android.bp编写,这部分需要根据具体情况来分析,大体介绍几种。
Android.bp编写
Android.bp 文件中的模块以模块类型开头,后跟一组 name: “value”, 格式的属性:
Soong示例
cc_library_shared {
name: "libxmlrpc++",
rtti: true,
cppflags: [
"-Wall",
"-Werror",
"-fexceptions",
],
export_include_dirs: ["src"],
srcs: ["src/**/*.cpp"],
target: {
darwin: {
enabled: false,
},
},
}
这里模块类型是 cc_ilbrary_shared,表明这是一个共享库(.so)的配置。
name即是共享库的名字,成功编译会生成libxmlrpc++.so。
其余配置,可参考文档Android.bp 文件格式。
更详细的文档,具体到每个参数,还是要参考下的:
Soong Modules Reference
c++静态库,动态库
c++静态库,动态库的一个简单例子,libtwo动态库引用libone静态库。
最终生成libone.a ,libtwo.so
cc_library_static{
name:"libone",
srcs: ["src/main/cpp/one.cpp"],
local_include_dirs: ["src/main/cpp"],
export_include_dirs: ["."],
sdk_version: "current",
min_sdk_version: "21",
cflags: [
"-Werror",
"-Wno-error=deprecated-declarations",
"-Wall",
"-std=c++11",
"-frtti",
"-fexceptions",
"-Wno-unused-parameter",
],
// for including the jni.h file
header_libs: ["jni_headers"],
}
cc_library_shared{
name:"libtwo",
srcs: ["src/main/cpp/two.cpp"],
local_include_dirs: ["src/main/cpp"],
export_include_dirs: ["."],
static_libs: ["libone"],
shared_libs: ["liblog"],
sdk_version: "current",
min_sdk_version: "21",
cflags: [
"-Werror",
"-Wno-error=deprecated-declarations",
"-Wall",
"-std=c++11",
"-frtti",
"-fexceptions",
"-Wno-unused-parameter",
],
// for including the jni.h file
header_libs: ["jni_headers"],
}
jar 或 aar
这里以aar为例,且带有aidl资源
android_library {
name: "libtest",
srcs: ["src/main/java/**/*.java",
"src/main/aidl/**/*.aidl"],
aidl:{
local_include_dirs: ["src/main/aidl",
"src/main/java",
],
},
resource_dirs: ["src/main/res"],
manifest: "src/main/AndroidManifest.xml",
libs: ["android-support-v7-appcompat"],
sdk_version: "current",
min_sdk_version: "21",
java_version: "1.8",
}
将 aidl 和 java 都参与编译,且将资源文件打包到 aar。
使用 java_library 打包成 jar,但是资源文件无法打包进 jar,没有resource_dirs 选项,这是由 jar 和 aar 的特点决定的,所以需要注意 java_library 和 android_library 在选项上的异同,并不是换个模块类型那么简单。
编译apk
android_app {
name: "testapp",
srcs: ["src/main/java/**/*.java"],
resource_dirs: ["src/main/res"],
manifest: "src/main/AndroidManifest.xml",
static_libs: ["android-support-v7-appcompat",
"gson-prebuilt-jar",
],
jni_libs:["libtwo"],
sdk_version: "current",
min_sdk_version: "21",
java_version: "1.8",
certificate: "platform",
}
这里,static_libs 选择依赖的库,包括appcompat和gson,也可以是之前编译的libtest。
jni_libs选择之前编译的动态so,libtwo。会将该so放到 /system/lib/下。
将整个目录放到安卓源码下
找到合适的位置,放置apk源码,同时,找到某个.mk文件,将该目录添加进即可。
PRODUCT_PACKAGES += \
app