图1:包大小分为下载大小(Download)和安装大小(Install)两个概念,苹果的200MB限制是基于下载大小的,我们一般关注的也是下载大小。在不同的设备上,iOS包体的表现不尽相同,我们以设备中下载大小最大的数值作为参照指标(我们一般看iPhoneX)
图2:超过200MB的App在运营商网络下载时提示的「Wifi下载提示弹框
图3:苹果手机的流量下载弹框的配置位置:Settings→App Store→App Downloads。默认配置是「Ask If Over 200MB」
2 包体治理的思路
包体的治理可以简单分为「优化」和「防劣化」
2.1 优化 - 造减量
常见的优化方案如:
工程配置层面:编译等级配置/StripCode配置/TEXT段转移等(针对TEXT段转移,小伙伴们可能比较陌生,可以参考下这篇文章:http://www.kffy.cn/meiwen/359417.html,本篇不详情展开)
未使用文件清理:未使用资源清理/未使用源文件清理等
大资源优化:压缩/远程化等
2.2 防劣化 - 防增量
随着业务的持续迭代,我们的的包体的自然行为几乎必然是持续变大的,他们主要包含:
新增的业务代码增量
新增的三方库增量
新增的直接放置到包体的大资源
废弃的未移除的旧代码/旧资源
我们当前基本防劣化思路是:
约定软性的增量准入规则
进行版本包体变化监控,跟进处理逾越准入规则的增量项目
不定期进行包体优化
Soul包体防劣化思路说明图
3 Soul的包体分析
讲到包体分析,我们第一想到的未使用资源(图片)的清理,它需要基于工程源码进行分析。但在我们基于源码分析进行工具开发的过程中发现,它很难准确分析模块迭代的二进制增量,因此我们进一步引入了LinkMap分析,形成了 「LinkMap分析二进制 & 源码分析资源」的基本模式,每种模式都包含「增量监控」和「存量分析」。
Soul包体分析的功能支持
3.1 LinkMap - 分析二进制
什么是LinkMap?
生成的LinkMap一般在DrivedData目录下面。
3.1.1 为什么要基于LinkMap分析
基于源文件的大小变化来判断包体二进制增量,我们发现它的局限性很大:
源文件的增量&包体的二进制增量很难建立起有效的映射关系;
随着二进制组件的增多,源文件对包体增量归因愈发不准确;
因为归因准确性不强,问题的反馈&跟进阻碍重重
我们亟需一种方式,能更真实准确地反应包体二进制的真实变化分布。经过调研发现,基于LinkMap的分析可以获取到每个模块的二进制大小,进而比对增量,符合我们需求。
包体各模块二进制增量呈现
LinkMap文件 Object files段示意
LinkMap文件 - Symbols段示意
LinkMap - Object files段包含模块信息
两份工程LinkMap的对比结果
3.1.3 LinkMap分析的工具架构
了解了LinkMap分析的关键技术流程,再关注一下我们LinkMap分析工具的架构。
Soul LinkMap分析工程架构
负责 Section 单行信息的解析
4)Utils
4.1)CYFileWritter
提供文件输出的相关操作,封装定制输出csv文件接口
4.2)LineIterator
支持文件的流式逐行读取
3.2 工程源码 - 分析资源
从源文件中提取目标图片名
3.2.2 技术点 - 基于TagString的效率优化
基于「未使用资源查找」来简单介绍下TagString的查找算法思路与优势。
场景举例:一份工程中有 5000个png图片 和 20000份.m源文件
noUsedImageArray = [] // 未使用图片数组
for (image in allImages) { // 共5000张图片
imageUsed = false // 标记某个资源是否被使用
for (file in allFiles) { // 共20000份源文件
if (file中包含image的名称) {
imageUsed = true
break
}
}
if (imageUsed = false) {
noUsedImageArray.append(image)
}
}
return noUsedImageArray
tagStringSet = Set()
for (file in allFiles) { // 共20000份源文件
tagStrings = extractTagStringFromFile(file)
tagStringSet.addObjects(tagStrings)
}
noUsedImageArray = [] // 未使用图片数组
for (image in allImages) { // 共5000张图片
if (image not in tagStringSet) {
noUsedImageArray.append(image)
}
}
return noUsedImageArray
self.conf_regexDic = @{
@"h": @[@"([a-zA-Z0-9_-]*)\\.(png|jpg|imageset|svg|json|mp3|gif|caf)"],
@"m": @[@"@\"(.*?)\""],
@"mm": @[@"@\"(.*?)\""],
@"swift": @[@"\"(.*?)\""],
@"xib": @[@"image name=\"(.+?)\""],
@"storyboard": @[@"image name=\"(.+?)\""],
@"strings": @[@"=\\s*\"(.*)\"\\s*;"],
@"c": @[@"([a-zA-Z0-9_-]*)\\.(png|jpg|imageset|svg|json|mp3|gif|caf)"],
@"cpp": @[@"([a-zA-Z0-9_-]*)\\.(png|jpg|imageset|svg|json|mp3|gif|caf)"],
@"html": @[@"img\\s+src=[\"'](.*?)[\"']"],
@"js": @[@"[\"']src[\"'],\\s+[\"'](.*?)[\"']"],
@"json": @[@":\\s*\"(.*?)\""],
@"plist": @[@">(.*?)<"],
@"css": @[@"([a-zA-Z0-9_-]*)\\.(png|jpg|imageset|svg|json|mp3|gif|caf)"],
};
3.2.3 技术类比 - 无用源文件的发现思路
tagString仅仅可以用于无用资源检索么?不,这套模式还可以用于其他的分析,比如:基于头文件判定的无用源码文件发现(提取头文件引用内容作为tagString进而判断未使用的文件,当然,对swift无效……)。下面是一些常见文件中提取import文件名TagString的正则参考:
// 无用源码文件发现-提取头信息
self.conf_regexDic = @{
@"h": @[
@"#import[ ]*<([a-zA-Z0-9_\\-\\+]*)\\.h",
@"#import[ ]*\"([a-zA-Z0-9_\\-\\+]*)\\.h",
@"#import.*/([a-zA-Z0-9_\\-\\+]*)\\.h",
@"#include[ ]*<([a-zA-Z0-9_\\-\\+]*)\\.h",
@"#include[ ]*\"([a-zA-Z0-9_\\-\\+]*)\\.h",
@"#include.*/([a-zA-Z0-9_\\-\\+]*)\\.h",
@"@import[ ]*([a-zA-Z0-9_\\-\\+]*)",
],
@"m": @[
@"#import[ ]*<([a-zA-Z0-9_\\-\\+]*)\\.h",
@"#import[ ]*\"([a-zA-Z0-9_\\-\\+]*)\\.h",
@"#import.*/([a-zA-Z0-9_\\-\\+]*)\\.h",
@"#include[ ]*<([a-zA-Z0-9_\\-\\+]*)\\.h",
@"#include[ ]*\"([a-zA-Z0-9_\\-\\+]*)\\.h",
@"#include.*/([a-zA-Z0-9_\\-\\+]*)\\.h",
@"@import[ ]*([a-zA-Z0-9_\\-\\+]*)",
],
@"mm": @[
@"#import[ ]*<([a-zA-Z0-9_\\-\\+]*)\\.h",
@"#import[ ]*\"([a-zA-Z0-9_\\-\\+]*)\\.h",
@"#import.*/([a-zA-Z0-9_\\-\\+]*)\\.h",
@"#include[ ]*<([a-zA-Z0-9_\\-\\+]*)\\.h",
@"#include[ ]*\"([a-zA-Z0-9_\\-\\+]*)\\.h",
@"#include.*/([a-zA-Z0-9_\\-\\+]*)\\.h",
@"@import[ ]*([a-zA-Z0-9_\\-\\+]*)",
],
@"c": @[
@"#import[ ]*<([a-zA-Z0-9_\\-\\+]*)\\.h",
@"#import[ ]*\"([a-zA-Z0-9_\\-\\+]*)\\.h",
@"#import.*/([a-zA-Z0-9_\\-\\+]*)\\.h",
@"#include[ ]*<([a-zA-Z0-9_\\-\\+]*)\\.h",
@"#include[ ]*\"([a-zA-Z0-9_\\-\\+]*)\\.h",
@"#include.*/([a-zA-Z0-9_\\-\\+]*)\\.h",
@"@import[ ]*([a-zA-Z0-9_\\-\\+]*)",
],
@"cpp": @[
@"#import[ ]*<([a-zA-Z0-9_\\-\\+]*)\\.h",
@"#import[ ]*\"([a-zA-Z0-9_\\-\\+]*)\\.h",
@"#import.*/([a-zA-Z0-9_\\-\\+]*)\\.h",
@"#include[ ]*<([a-zA-Z0-9_\\-\\+]*)\\.h",
@"#include[ ]*\"([a-zA-Z0-9_\\-\\+]*)\\.h",
@"#include.*/([a-zA-Z0-9_\\-\\+]*)\\.h",
@"@import[ ]*([a-zA-Z0-9_\\-\\+]*)",
],
@"swift": @[
@"import[ ]*([a-zA-Z0-9_\\-\\+]*)",
]
};
/* 基础文件信息 */
@interface CYFileItem : NSObject
@property (nonatomic, strong) NSString *filePath; /* 文件路径 */
@property (nonatomic, strong) NSString *fileReletivePath; /* 文件相对路径 */
@property (nonatomic, assign) uint64_t fileSize; /* 文件大小 */
@property (nonatomic, strong) NSString *fileName; /* 文件名称(含后缀) */
@property (nonatomic, strong) NSString *pureFileName; /* 文件名称(不含后缀)*/
@property (nonatomic, strong) NSString *fileSuffix; /* 文件后缀 */
@property (nonatomic, strong) NSString *fileTag; /* 文件标签,用以匹配 */
@property (nonatomic, assign) CGSize imageSize; /* 当文件是图片类型文件时,的size大小信息 */
@end
工程对比发现的迭代新增资源
3.2.5 工程源码分析的架构简述
LinkMap分析的自动化流程示意
大资源问题推进思路示意
我们可以通过git log的方式获取到资源的调整人信息。
操作git log 这个环节,我们也是可以让工具协助的。为了保障工具的执行效率,我们只针对关键的资源进行资源调整人信息的补充,它们包括:
gitlog命令操作示意
日期正则:"^Date:[ ]*(.*)"
对象-模块 映射关系表示意
单例发现示意
以上为该次分享的内容,感谢您的阅读。