58同城Android Qigsaw升级-v1.4.1多ABI构建

2023-12-14 00:40

本文主要是介绍58同城Android Qigsaw升级-v1.4.1多ABI构建,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

58同城 Android Qigsaw升级-v1.4.1多ABI构建

  • 1.背景
  • 2.方案调研与设计
  • 3.升级过程

1.背景

Qigsaw 是 Wafers 动态化能力使用到的开源框架,承载着 58App、任意门、Mocha 的运行。小组于 2020/03 月份从 Qigsaw v1.3.2.2 fork 接入

https://github.com/iqiyi/Qigsaw

v_1.3.2.2 版本只支持单 ABI 维度构建,随着国内越来越多应用商店需要上传64位 APK,对于 Qigsaw 支持 Base APK 和 Split APKs 基于 ABI 维度拆分的需求越来越强烈

Qigsaw v1.4.0 开始支持 APK 基于 ABI 维度进行拆分:

2.方案调研与设计

概括为:

  • 对齐 Qigsaw 最新版本代码
  • 保留旧有的自定义业务逻辑、bug 修复
  • 改造 58App 打包脚本、ftp 备份、AVM 发版流程、任意门后台
  • 无线基础能力测试、任意门、Mocha 业务线测试

原有发包流程:

目标发包流程:

3.升级过程

3.1 Qigsaw

(1) 获取 Qigsaw v1.4.1 最新代码

基于 WubaQigsawLib 新开一分支,拉取 Qigsaw v1.4.1 最新代码(此分支完全是最新代码,无任何旧有改造代码)

(2) 手动添加之前的修改点

#changelog
1maven 发布脚本
2实现 split apk 上传逻辑
3SplitConfiguration 增加设置 FakeActivty/Service/Receiver 的接口支持
4去除 AABExtension 类的 group 调用限制
5处理当前基础组件未跳转场景下资源加载问题
6增加 multi dex 安装 Activity、启动 Activity 过滤配置
7增加移动网络下载弹出外部处理选项
8断点下载、并行下载器修复
9增加上传 split config 文件的 task
10增加插件过滤注入 resources 的 Activity 列表属性选项
11修复 5,6系统适配问题
12修复资源加载抛出异常问题
13fix downloader nullpointer
14适配AGP4.0 (最新版官方已修复)
15支持R8编译

(3) 遇到的问题

AndResGuard适配问题
AndResGuard 是资源混淆工具,可以用来减少 APK 的大小。微信团队中的人开源出来的项目,它直接针对 APK 文件进行修改

AndResGuard 原理:

(1) 混淆资源
Android 在调用资源时,使用的都是 int 值,而不是直接使用 res name, 这种对应的关系打包后会被储存resource.arsc 文件里。AndResGuard 就是通过修改 res name, 使其变短,改成 a、b、c 这样的名字,从而减少文件大小

(2) 7z 压缩
AndResGuard 采用了 7z 极限压限,将图片,资源文件压缩(包括上面提到的 resource.arsc)来减少 apk 的大小

58App AndResGuard 打包流程 (输出的为 v7a 的包)

升级 Qigsaw 之后的打包流程:

很明显,流程是不正确的,这样会导致分包出来的 abi 包大小变大,应该先对基础包进行 resguard 再进行分包,所以修改 Qigsaw 打包脚本如下:

// source: buildSrc/com.iqiyi.qigsaw.buildtool.gradle/QigsawAppBasePlugin:if (QigsawSplitExtensionHelper.isMultipleApkForABIs(project)) {SplitBaseApkForABIsTask splitBaseApkForABIs = project.tasks.create("split${baseVariant.name.capitalize()}BaseApkForABIs", SplitBaseApkForABIsTask)splitBaseApkForABIs.baseVariant = baseVariantsplitBaseApkForABIs.apkSigner = apkSignersplitBaseApkForABIs.dynamicFeaturesNames = dynamicFeaturesNamessplitBaseApkForABIs.supportABIs = QigsawSplitExtensionHelper.getSupportABIs(project)splitBaseApkForABIs.baseAppCpuAbiListFile = baseAppCpuAbiListFilesplitBaseApkForABIs.baseApkFiles = baseApkFilessplitBaseApkForABIs.packageAppDir = packageAppDirsplitBaseApkForABIs.baseApksDir = baseApksDirTask resguardTask = AGPCompat.getResguardTask(project, "${baseVariant.name.capitalize()}")// apply plugin: 'AndResGuard' 必须在 qigsaw application 插件前应用,否则会查找不到 resguardTaskif (resguardTask != null) {SplitLogger.w("found resguardTask")resguardTask.dependsOn baseAssemblebaseAssemble.finalizedBy resguardTasksplitBaseApkForABIs.dependsOn resguardTaskresguardTask.finalizedBy splitBaseApkForABIs} else {SplitLogger.w("not found resguardTask")baseAssemble.dependsOn splitBaseApkForABIspackageApp.finalizedBy splitBaseApkForABIs}}

此处有一个知识点:

宿主 App apply 插件 A、B,如果先 Apply A,再 Apply B,那么在 A 插件中无法获取到 B 插件中的 task. 所以需要调整 58App Qigsaw 插件和 resguard 插件的 apply 顺序

// apply plugin: 'AndResGuard' 必须在 qigsaw application 插件前应用,否则会查找不到 resguardTask
if (Boolean.parseBoolean(ON_JENKINS)) {apply from: 'andResguard.gradle'
}
if (Boolean.parseBoolean(AAB_SWITCH)) {apply from: '../DynamicFeatures/qigsaw-application-apply.gradle'
}

Qigsaw 7z 深度压缩问题
58App 在使用 AndroResGuard 插件时,是开了 7z 压缩的,所以 Qigsaw 插件中也需要开启 7z 压缩,保持包大小一致

// 58App AndResGuard 配置
apply plugin: 'AndResGuard'andResGuard {enableResGuard = Boolean.parseBoolean(rootProject.enableResGuard)mappingFile = file("./resource_mapping.txt")use7zip = true // 开启 7z 深度压缩useSign = true// ....
}

Qigsaw 打包插件也有 7z 压缩选项:

// buildSrc/com.iqiyi.qigsaw.buildtool.gradle.task.SplitBaseApkForABIsTask
// 对分包出的 apk 包进行重新压缩处理
if (use7z) {run7zCmd("7za", "a", "-tzip", unsignedBaseApk.absolutePath, unzipBaseApkDirForAbi.absolutePath + File.separator + "*", "-mx9")
} else {ZipUtils.zipFiles(Arrays.asList(unzipBaseApkDirForAbi.listFiles()), unzipBaseApkDirForAbi, unsignedBaseApk, compress)
}

开启之后发现,58App v7a 包缩小到 113M,运行时出现资源找不到异常。

我们先来了解下 7z 压缩:

7z 是一种主流高效的压缩格式,它拥有极高的压缩比

eg: 7z -tZip a test.zip ./test/* -mx0
把 test 文件夹中所有文件以存储压缩的模式压缩成 zip 格式的文件,压缩文件为 test.zip

a 为添加选项
-tZip 为压缩格式(-t7z…)
压缩率具体参数如下:
-mx0 仅存储不压缩,速度最快,无压缩,zip 大小等同原始文件夹
-mx1 极速压缩
-mx3 快速压缩
-mx5 标准压缩
-mx7 最大压缩
-mx9 极限压缩

我们先看下 Qigsaw 分包逻辑:

所以出现以上问题的原因为:

AndResGuard 插件已经对 58App 基础包 APK 进行了一次 mx9 深度压缩,由于 Qigsaw 插件在分包时需要解压原始包,
对 libs, abi 配置文件做处理,然后再进行压缩。不管是再次压缩时使用 7z 还是 zip,都会破坏原有基础包

解决方案:

分包时不解压 APK,直接使用 zip 操作修改再重签名,解决此问题的同时,也可以加快打包速度

// buildSrc/com.iqiyi.qigsaw.buildtool.gradle.task.SplitBaseApkForABIsTaskFile baseApk = baseApkFiles[0]List<String> abiList = supportABIs != null ? supportABIs.split(",") : nullif (abiList == null || abiList.isEmpty()) {SplitLogger.e("Base apk ${baseApk.absolutePath} has no native-library abi folder, multiple apks don't need.")return}if (abiList.size() == 1) {SplitLogger.e("Base apk ${baseApk.absolutePath} has only one native-library abi folder, multiple apks don't need.")return}abiList.each { String abi ->if (SUPPORTED_ABIS.contains(abi)) {// 不能直接使用 7z 深度压缩,会影响 resources.arsc 的使用,导致资源找不到,所以这边使用 zip 命令操作// Copy base apkFile copyBaseApk = new File(baseApksDir, "${project.name}-${baseVariant.name.uncapitalize()}-${abi}${SdkConstants.DOT_ANDROID_PACKAGE}")if (!copyBaseApk.parentFile.exists()) {copyBaseApk.parentFile.mkdirs()}if (copyBaseApk.exists()) {copyBaseApk.delete()}FileUtils.copyFile(baseApk, copyBaseApk)String copyBaseApkPath = copyBaseApk.getAbsolutePath()// Delete signature related filesrunCmd("zip", "-d", copyBaseApkPath, "META-INF/CERT.RSA")runCmd("zip", "-d", copyBaseApkPath, "META-INF/CERT.SF")runCmd("zip", "-d", copyBaseApkPath, "META-INF/MANIFEST.MF")Set<String> masterSplitHandleFlags= new HashSet<>()abiList.each { String ABI ->if (abi != ABI) {// Delete other ABI's librunCmd("zip", "-d", copyBaseApkPath, "lib/${ABI}/**")// Delete other ABI's built-in splits (include master)dynamicFeaturesNames.each { String splitName ->if (!masterSplitHandleFlags.contains(splitName)) {runCmd("zip", "-d", copyBaseApkPath, "assets/qigsaw/${splitName}-master**.zip")masterSplitHandleFlags.add(splitName)}runCmd("zip", "-d", copyBaseApkPath, "assets/qigsaw/${splitName}-${ABI}**.zip")}}}// Update base apk cpu abi list fileFile baseAppCpuAbiListFileForAbi = new File(baseApksDir,"assets/${baseAppCpuAbiListFile.name}")if (!baseAppCpuAbiListFileForAbi.parentFile.exists()) {baseAppCpuAbiListFileForAbi.parentFile.mkdirs()}if (baseAppCpuAbiListFileForAbi.exists()) {baseAppCpuAbiListFileForAbi.delete()}baseAppCpuAbiListFileForAbi.write("abiList=${abi}")// ProcessBuilder execute multi commandsFile baseAppCpuAbiScript = new File(baseApksDir,"baseAppCpuAbiScript")if (baseAppCpuAbiScript.exists()) {baseAppCpuAbiScript.delete()}baseAppCpuAbiScript.write("#!/usr/bin/env bash\ncd \$1\nzip -d \$2 \$3\nzip -m \$2 \$3")runCmd("chmod", "755", baseAppCpuAbiScript.getAbsolutePath())runCmd(baseAppCpuAbiScript.getAbsolutePath(), copyBaseApk.getParent(), copyBaseApk.getName(), "assets/${baseAppCpuAbiListFile.name}")// Resign apk if needSigningConfig signingConfig = nulltry {signingConfig = apkSigner.getSigningConfig()} catch (Throwable ignored) {}boolean isSigningNeed = signingConfig != null && signingConfig.isSigningReady()if (isSigningNeed) {File signedBaseApk = new File(baseApksDir, "${project.name}-${baseVariant.name.uncapitalize()}-${abi}-signed${SdkConstants.DOT_ANDROID_PACKAGE}")if (signedBaseApk.exists()) {signedBaseApk.delete()}apkSigner.signApkIfNeed(copyBaseApk, signedBaseApk)File destBaseApk = new File(packageAppDir, signedBaseApk.name)if (destBaseApk.exists()) {destBaseApk.delete()}FileUtils.copyFile(signedBaseApk, destBaseApk)} else {File destBaseApk = new File(packageAppDir, copyBaseApk.name)if (destBaseApk.exists()) {destBaseApk.delete()}FileUtils.copyFile(copyBaseApk, destBaseApk)}}}	

此处也有一个知识点:

使用 ProcessBuilder 执行命令时,只能一次执行单条命令。想一次执行多条命令,可以自行包装成一个脚本文件,再使用 ProcessBuilder 执行

以上两个问题都向 Qigsaw 提交了 merge request 并通过 merge:

修复宿主 app 应用 resguard 插件后导致分包的 ABI APK 包大小增加问题 & 7z 深度压缩导致资源找不到问题 #57

https://github.com/iqiyi/Qigsaw/pull/57

3.2 58App

(1) 移除SPLITS_APK、UNIVERSAL_APK相关配置

// 移除 splits 配置,Qigsaw 自己实现了一套分包机制,与系统分包机制存在冲突
splits {abi {enable !Boolean.parseBoolean(AAB_SWITCH) && Boolean.parseBoolean(rootProject.SPLITS_APK)reset()universalApk Boolean.parseBoolean(rootProject.UNIVERSAL_APK)  // If true, also generate a universal APKrootProject.CPU_ARCH.split(",").each { value ->include value}}}

(2) 修改WubaPackage jenkins 打包配置

  • v7a 为默认包,58Client_vxxx_release.apk
  • 备份全包、v7a、v8a 包到 FTP
  • 任意门动态更新基础包下载地址改为全包地址

(3) Qigsaw API 变更

// WubaQigsawLib/QigsawManager
public static void applicationOnCreate() {Qigsaw.onApplicationCreated();Qigsaw.registerSplitActivityLifecycleCallbacks(new QigsawSplitActivityLifecycleCallbacks());// 需要手动调用 Qigsaw.preloadInstalledSplits,否则启动时不会调用已安装 splits 的 Applicationtry {Set<String> splitNames = AABExtension.getInstance().getSplitNames();Qigsaw.preloadInstalledSplits(splitNames);} catch (Exception e) {LOGGER.e(e);}
}

3.3 AVM

涉及如下改动点:

  • 发版管理 - 打包配置加入 CPU_ARCHES=armeabi-v7a,arm64-v8a
  • 发版管理 - 基础底包改为 v7a 包
  • 任意门 - 基础底包改为全包地址
  • 任意门 - 基础包下载地址展示全包、v7a、v8a

这篇关于58同城Android Qigsaw升级-v1.4.1多ABI构建的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/490536

相关文章

嵌入式QT开发:构建高效智能的嵌入式系统

摘要: 本文深入探讨了嵌入式 QT 相关的各个方面。从 QT 框架的基础架构和核心概念出发,详细阐述了其在嵌入式环境中的优势与特点。文中分析了嵌入式 QT 的开发环境搭建过程,包括交叉编译工具链的配置等关键步骤。进一步探讨了嵌入式 QT 的界面设计与开发,涵盖了从基本控件的使用到复杂界面布局的构建。同时也深入研究了信号与槽机制在嵌入式系统中的应用,以及嵌入式 QT 与硬件设备的交互,包括输入输出设

Android实现任意版本设置默认的锁屏壁纸和桌面壁纸(两张壁纸可不一致)

客户有些需求需要设置默认壁纸和锁屏壁纸  在默认情况下 这两个壁纸是相同的  如果需要默认的锁屏壁纸和桌面壁纸不一样 需要额外修改 Android13实现 替换默认桌面壁纸: 将图片文件替换frameworks/base/core/res/res/drawable-nodpi/default_wallpaper.*  (注意不能是bmp格式) 替换默认锁屏壁纸: 将图片资源放入vendo

Retrieval-based-Voice-Conversion-WebUI模型构建指南

一、模型介绍 Retrieval-based-Voice-Conversion-WebUI(简称 RVC)模型是一个基于 VITS(Variational Inference with adversarial learning for end-to-end Text-to-Speech)的简单易用的语音转换框架。 具有以下特点 简单易用:RVC 模型通过简单易用的网页界面,使得用户无需深入了

Android平台播放RTSP流的几种方案探究(VLC VS ExoPlayer VS SmartPlayer)

技术背景 好多开发者需要遴选Android平台RTSP直播播放器的时候,不知道如何选的好,本文针对常用的方案,做个大概的说明: 1. 使用VLC for Android VLC Media Player(VLC多媒体播放器),最初命名为VideoLAN客户端,是VideoLAN品牌产品,是VideoLAN计划的多媒体播放器。它支持众多音频与视频解码器及文件格式,并支持DVD影音光盘,VCD影

maven 编译构建可以执行的jar包

💝💝💝欢迎莅临我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。 推荐:「stormsha的主页」👈,「stormsha的知识库」👈持续学习,不断总结,共同进步,为了踏实,做好当下事儿~ 专栏导航 Python系列: Python面试题合集,剑指大厂Git系列: Git操作技巧GO

android-opencv-jni

//------------------start opencv--------------------@Override public void onResume(){ super.onResume(); //通过OpenCV引擎服务加载并初始化OpenCV类库,所谓OpenCV引擎服务即是 //OpenCV_2.4.3.2_Manager_2.4_*.apk程序包,存

从状态管理到性能优化:全面解析 Android Compose

文章目录 引言一、Android Compose基本概念1.1 什么是Android Compose?1.2 Compose的优势1.3 如何在项目中使用Compose 二、Compose中的状态管理2.1 状态管理的重要性2.2 Compose中的状态和数据流2.3 使用State和MutableState处理状态2.4 通过ViewModel进行状态管理 三、Compose中的列表和滚动

嵌入式Openharmony系统构建与启动详解

大家好,今天主要给大家分享一下,如何构建Openharmony子系统以及系统的启动过程分解。 第一:OpenHarmony系统构建      首先熟悉一下,构建系统是一种自动化处理工具的集合,通过将源代码文件进行一系列处理,最终生成和用户可以使用的目标文件。这里的目标文件包括静态链接库文件、动态链接库文件、可执行文件、脚本文件、配置文件等。      我们在编写hellowor

macOS升级后SVN升级

问题 svn: error: The subversion command line tools are no longer provided by Xcode. 解决 sudo chown -R $(whoami) /usr/local/Cellar brew install svn

Android 10.0 mtk平板camera2横屏预览旋转90度横屏拍照图片旋转90度功能实现

1.前言 在10.0的系统rom定制化开发中,在进行一些平板等默认横屏的设备开发的过程中,需要在进入camera2的 时候,默认预览图像也是需要横屏显示的,在上一篇已经实现了横屏预览功能,然后发现横屏预览后,拍照保存的图片 依然是竖屏的,所以说同样需要将图片也保存为横屏图标了,所以就需要看下mtk的camera2的相关横屏保存图片功能, 如何实现实现横屏保存图片功能 如图所示: 2.mtk