CSDN话题挑战赛第2期
参赛话题:面试宝典

APK 打包的内容主要有:应用模块也就是自己开发的用到的源代码、资源文件、aidl 接口文件,还有就是依赖模块即源代码用到的第三方依赖库如:aar、jar、so 文件
AAPT2(Android Asset Packaging Tool):Android 资源打包工具
AndroidSDK/build-tools/31.0.0/aapt2.exe
Android Gradle 插件 3.0.0 以上会默认启用 AAPT2,AAPT2 支持通过启用增量编译实现更快的资源编译。这是通过将资源处理拆分为两个步骤来实现的
编译(compile)
将资源文件res目录下的文件编译成.arsc.flag或.flat的二进制文件
aapt2 compile MyApplication/app/src/main/res/values/strings.xml -o compiled/
aapt2 compile MyApplication/app/src/main/res/drawable/myimage.png -o compiled/
-o:指定已编译资源的输出路径(前提是该路径必须存在,否则编译不通过)
上述第一个命令产出 --> values_strings.arsc.flat
上述第二个命令产出 --> drawable_myimage.png.flat
链接(link)
合并在编译阶段生成的所有中间文件(如资源表、二进制 XML 文件和处理过的 PNG 文件),并将它们打包成一个 APK。另外还会生成 R.java 和 ProGuard 规则文件,但是生成的 APK 不包含 DEX 字节码且未签名,也就是说,无法将此 APK 部署到设备
aapt2 link -o output.apk
-I android_sdk/platforms/android-31/android.jar
compiled/res/values_values.arsc.flat
compiled/res/drawable_Image.flat --manifest /path/to/AndroidManifest.xml -v
-o:指定链接的资源 APK 的输出路径
-I:提供平台的 android.jar 或其他 APK(如 framework-res.apk)的路径
--manifest:指定要构建的 Android 清单文件的路径
-v:可提高输出的详细程度
上述命令在当前目录生成一个out.pak,无法部署到设备上
目前版本R文件位置:
build/intermediates/compile_and_runtime_not_namespaced_r_class_jar/R.jar
解压后用Androidstudio编译器可查看


如何解决资源冲突
// library Module的build.gradle中设置资源前缀
android{
resourcePrefix "<前缀>"
}
2022-9-22 19:35:21
Android的资源分为两个部分:assets和res,保存的是一些原始的文件,并且不会压缩保持原始状态打包进apk文件中
AssetManager assetManager = context.getAssets();
InputStream is = assetManager.open("myimage.png");
res目录下就有很多其它目录了,animator、anim、color、raw、layout等,这其中除了raw和mipmap下的Bitmap资源外,其它均会被aapt2编译成二进制格式的XML文件
aapt2的编译流程主要是以下几个流程:
AIDL(Android Interface Denifition Language):Android接口定义语言
AndroidSDK/build-tools/31.0.0/aidl.exe
使用aidl命令可以将AIDL文件转换为java接口
aidl -Iaidl -AndroidSDK/platforms/android-31/framework.aidl -obuild aidl/com/android/vending/billing/IInAppBillingService.aidl
-I 指定 import 语句的搜索路径,注意 -I 与目录之间一定不要有空格
-p 指定系统类的 import 语句路径,如果是要用到 android.os.Bundle 系统的类,一定要设置 sdk 的 framework.aidl 路径
-o 生成 java 文件的目录,注意 -o 与目录之间一定不要有空格,而且这设置项一定要在 aidl 文件路径之前设置
源代码编译分为两步,分别是将java代码编译成class文件、将Class文件编译成Dex文件
使用Javac把项目中所有的Java代码编程成.class文件,包括.java文件、R.java以及AIDL生成的Java接口文件
AndroidStudio/jre/bin/javac.exe
javac -target 1.8 -bootclasspath platforms/android-31/android.jar -d ./java/com/testjni/*.java
Android Studio 和 Android Gradle 插件使用该工具来将项目的 Java 字节码(包括三方库中的class文件)编译为在 Android设备上运行的 DEX 字节码,该工具支持您在应用的代码中使用 Java 8 语言功能,该过程主要是将Java字节码转成ART字节码
AndroidSDK/build-tools/31.0.0/lib/d8.jar
java -jar d8.jar --dex --ouput=classes.dex ./java/com/testjni/*.class
--dex:将 class 文件转成dex文件
--output:指定生成 dex 文件到具体位置
使用Apkbuilder,将所有的Dex文件、Resource.arsc、Res文件夹、Assets文件夹、AndroidManifest.xml打包成apk文件(未签名)
Android\SDK\tools\lib\sdklib-26.0.0-dev.jar
apkbuilder为一个脚本文件,实际调用的是(Android\SDK\tools\lib\sdklib-26.0.0-dev.jar)文件中的com.android.sdklib.build.ApkbuilderMain类
对于apk,使用apksigner,对于App Bundle,使用jarsigner。无论哪种方式,都需要使用keytool生成一个私钥
keytool -genkey -v -keystore my-release-key.jks -keyalg RSA -keysize 2048 -validity 10000 -alias my-alias
输入上述命令后会提示输入私钥密码,并提示在DistinguishedName字段中给私钥输入相应的名称。之后就会生成一个`my-relese-key.jks`的密钥文件
对apk签名的步骤为
zipalign对齐未签名的apkzipalign -v -p 4 my-app-unsigned.apk my-app-unsigned-aligned.apk
zipalign 可以确保所有未压缩数据的开头均相对于文件开头执行特定的字节对齐,从而减少应用占用的 RAM 量
apksigner用私钥给apk签名apksigner sign --ks my-release-key.jks --out my-app-release.apk my-app-unsigned-aligned.apk
上述命令会输出一个`my-app-release.apk`的apk文件
apksigner 工具支持其他签名方法,包括使用单独的私钥和证书文件为 APK 文件签名,以及由多个签名者为 APK 签名
以上的打包过程中的aidl以及源码编译部分,以及改成bundletool工具来构建app bundle,而apk的构建可以使用assemble的方式进行构建
C:\Users\Administrator>gradle
JAVA_HOME is set to an invalid directory

这个问题是由于JAVA_HOME的目录带了bin,以及gradle目录带了bin,导致,把两个的配置路径都去掉\bin即可

C:\Users\Administrator>gradle
'gradle' 不是内部或外部命令,也不是可运行的程序
或批处理文件。
这个坑是由于当前执行gradle或者gradlew的目录不是项目根目录造成,切换到项目根目录执行该命令即可
构建release版本的软件包或apk:
如果是apk,则需要zipalign和apksigner。签名可被覆盖,原签名apk用新签名后,可替换原签名。
apksigner使用私钥进行签名(具体命令见链接)