如何在命令行不依赖Gradle构建含Kotlin、C++及资源的APK?
解决Android资源与Kotlin/C++混合编译的问题
核心问题说明
你直接把aapt2输出的.flat/.arsc.flat文件丢给kotlinc的-cp参数是行不通的——这些是编译后的资源二进制文件,不是Kotlin能识别的字节码。Kotlin代码里引用的R.id.xxx、R.drawable.xxx这类资源标识,需要依赖aapt2生成的R类字节码,同时资源最终要打包进APK才能被Android系统识别。
正确实现步骤
1. 用aapt2完成资源的编译与链接,生成R类和资源包
aapt2分两个核心阶段:compile(编译单个资源)和link(整合资源并生成R类)
编译单个资源
将res/目录下的所有XML、PNG等资源编译为.flat文件,输出到res_compiled/目录:
aapt2 compile --dir res/ -o res_compiled/
链接资源生成R类和资源包
链接阶段必须指定AndroidManifest.xml,同时生成R类源码和资源APK片段,这里我们让aapt2直接生成R.java,后续编译为字节码:
aapt2 link -o resources.apk \ --manifest AndroidManifest.xml \ -I $ANDROID_HOME/platforms/android-33/android.jar \ --java gen/ \ res_compiled/*.flat
-I必须指定对应Android版本的平台jar包,否则aapt2无法识别Android基础类--java gen/会在gen/目录下生成与你包名对应的R.java文件
2. 编译R类为字节码
用javac把生成的R.java编译成.class文件,输出到bin/目录:
javac -d bin/ \ -classpath $ANDROID_HOME/platforms/android-33/android.jar \ gen/com/your/package/R.java
替换com/your/package为你AndroidManifest.xml里声明的包名。
3. 编译Kotlin代码时引入R类字节码
编译Kotlin代码时,将bin/(包含R.class)和Android平台jar加入classpath:
kotlinc -d bin/ \ -classpath $ANDROID_HOME/platforms/android-33/android.jar:bin/ \ src/main/kotlin/**/*.kt
4. 整合C++编译产物
如果你已经单独编译好C++为.so库,将它们放到jniLibs/对应架构目录下(比如jniLibs/arm64-v8a/),后续打包APK时一并打包。
5. 打包并签名最终APK
首先用d8把Kotlin和R类的.class文件转成dex格式:
d8 bin/*.class --output dex/
然后将dex、资源、so库打包成未签名APK:
zip -r unsigned.apk dex/ res/ jniLibs/ AndroidManifest.xml
最后用zipalign优化并apksigner签名:
zipalign -v 4 unsigned.apk aligned.apk apksigner sign --ks your-keystore.jks aligned.apk
关键注意点
- 永远不要直接把
.flat文件加入Kotlin的classpath,它们是给Android系统解析的资源二进制,不是编译依赖 - 必须通过aapt2的
link阶段生成R类,Kotlin代码才能正确引用资源ID - 所有编译步骤都要依赖对应版本的Android平台jar包,否则会出现类找不到的错误
内容的提问来源于stack exchange,提问作者Rohan Pande
相关产品推荐
相关产品推荐

