• apk构建过程


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

    1. 构建系统

    img

    APK 打包的内容主要有:应用模块也就是自己开发的用到的源代码、资源文件、aidl 接口文件,还有就是依赖模块即源代码用到的第三方依赖库如:aar、jar、so 文件

    2. 构建步骤

    2.1 aapt2

    AAPT2(Android Asset Packaging Tool):Android 资源打包工具

    AndroidSDK/build-tools/31.0.0/aapt2.exe
    

    Android Gradle 插件 3.0.0 以上会默认启用 AAPT2,AAPT2 支持通过启用增量编译实现更快的资源编译。这是通过将资源处理拆分为两个步骤来实现的

    • 编译(compile):将资源文件编译成二进制文件
    • 链接(link):合并所有已编译的文件并将它们打包到一个软件包中

    编译(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,无法部署到设备上
    

    2.1.1 寻找资源ID

    目前版本R文件位置:

    build/intermediates/compile_and_runtime_not_namespaced_r_class_jar/R.jar
    

    解压后用Androidstudio编译器可查看

    img

    img

    如何解决资源冲突

    // library Module的build.gradle中设置资源前缀
    android{
        resourcePrefix "<前缀>"
    }
    

    2.1.2 资源的分类

    直面底层 Apk是如何生成的?

    2022-9-22 19:35:21

    Android的资源分为两个部分:assetsres,保存的是一些原始的文件,并且不会压缩保持原始状态打包进apk文件中

    AssetManager assetManager = context.getAssets();
    InputStream is = assetManager.open("myimage.png");
    

    res目录下就有很多其它目录了,animatoranimcolorrawlayout等,这其中除了raw和mipmap下的Bitmap资源外,其它均会被aapt2编译成二进制格式的XML文件

    aapt2的编译流程主要是以下几个流程:

    1. 解析 AndroidManifest.xml,获得应用程序的包名称,创建资源表
    2. 添加被引用资源包,被添加的资源会以一种资源 ID 的方式定义在 R.java 中
    3. 资源打包工具创建一个 AaptAssets 对象,收集当前需要编译的资源文件,收集到的资源保存在 AaptAssets 对象对象中
    4. 将上一步 AaptAssets 对象保存的资源,添加到资源表 ResourceTable 中去,用于最终生成资源描述文件 resources.arsc
    5. 编译 values 类资源,这类资源包括数组、颜色、尺寸、字符串等值
    6. 给 style、array 这类资源分配资源 ID
    7. 编译 XML 资源文件,编译的流程分为:① 解析 XML 文件 ② 赋予属性名称资源 ID ③ 解析属性值 ④ 将 XML 文件从文本格式转换为二进制格式
    8. 生成资源索引表 resources.arsc

    2.2 AIDL

    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 文件路径之前设置
    

    2.3 SourceCode编译

    源代码编译分为两步,分别是将java代码编译成class文件、将Class文件编译成Dex文件

    1. 将 Java 代码编译成 Class 文件

    使用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
    
    1. 将 Class 文件编译成 Dex 文件

    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 文件到具体位置
    

    2.4 生成apk

    使用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类
    

    2.5 签名

    对于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签名的步骤为

    1. 使用zipalign对齐未签名的apk
    zipalign -v -p 4 my-app-unsigned.apk my-app-unsigned-aligned.apk
    
    zipalign 可以确保所有未压缩数据的开头均相对于文件开头执行特定的字节对齐,从而减少应用占用的 RAM 量
    
    1. 通过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 签名

    3. gradlew

    从命令行构建您的应用 | Android 开发者 | Android Developers (google.cn)

    以上的打包过程中的aidl以及源码编译部分,以及改成bundletool工具来构建app bundle,而apk的构建可以使用assemble的方式进行构建

    C:\Users\Administrator>gradle
    JAVA_HOME is set to an invalid directory
    

    img

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

    img

    C:\Users\Administrator>gradle
    'gradle' 不是内部或外部命令,也不是可运行的程序
    或批处理文件。
    

    这个坑是由于当前执行gradle或者gradlew的目录不是项目根目录造成,切换到项目根目录执行该命令即可

    构建release版本的软件包或apk

    如果是apk,则需要zipalignapksigner。签名可被覆盖,原签名apk用新签名后,可替换原签名。

    1. 使用zipalign先对齐需要签名的apk(具体命令见链接)
    2. 通过apksigner使用私钥进行签名(具体命令见链接)
    3. 验证apk是否签名(具体命令见链接)
  • 相关阅读:
    【Java并发】聊聊并发编程中的锁
    前端xlsx插件简单说明
    跨平台编译工具--CMake上手教程
    将数据、代码、栈放入不同的段
    分类预测 | MATLAB实现基于Isomap降维算法与改进蜜獾算法IHBA的Adaboost-SVM集成多输入分类预测
    go写webasmbly
    自定义实现:头像上传View
    云原生微服务-理论篇
    rhce第一天笔记
    XGBOOST案例
  • 原文地址:https://blog.csdn.net/qq_37776700/article/details/127119213