一、前语

在上一篇文章,咱们介绍了包体积优化的必要性、安装包组成部分和生成进程、国内外大厂APP包体积剖析、百度APP包体积优化技能计划及各项收益,本文重点讲述图片优化,解压IPA包后发现,百度APP中asset和bundle里边图片共有94M,这是咱们重点优化的对象。

本系列文章目录如下:

《百度APP iOS端包体积50M优化实践(一)总览》(点击标题即可跳转)

百度APP选用如下办法对不同的图片资源进行了优化:

榜首、无用图片优化,处理的是跟着版别迭代,一些图片现已没有了引证联系,但还在IPA包中保存,发掘这部分图片并删去,这个优化是一切包体积优化项目中ROI最高的,影响范围限制在单个组件内,质量可控,关键是提高查找无用图片的准确度;

第二、Asset Catalog优化:运用Asset Catalog办理的图片能被App Store东西App Thinning处理,处理后用户只会下载匹配其设备分辨率的图片资源,然后降低了用户下载的包体积;

第三、HEIC图片优化:跟PNG、JPEG、WebP比较,HEIC图片编码格局体积削减最小,从解码效率视点来说,跟WebP比较,HEIC硬解码效率高。

二、无用图片优化

2.1 计划总述

首要获取一切图片资源,然后开发东西获取Objective-C、Swift、xib、storyboard、html、js、css、json、plist文件或许引证图片的静态字符串,接着前面两个集合做diff即可排查未引证的图片,最终针对字符串拼接的常见case做二次过滤,掩盖的case越多准确度越高,当然也要考虑ROI。

2.2 获取一切图片

敞开每个库的源码,用脚本检测一切图片及图片所属联系,为后续分发及落地优化供给方便。假如不开源码运用二进制库或许ipa包会带来很多麻烦,如获取asset.car里边的图片资源比较困难,一起只能知道图片称号,不能直接获取图片归于哪一个库。敞开每个库的源码后,用脚本递归遍历可获取一切图片,从图片路径可知道所属联系,参阅代码如下所示:


def findAllPictures(path):
    pathDir = os.listdir(path)
    for allDir in pathDir:
        child = os.path.join('%s%s' % (path, allDir))
        if os.path.isfile(child):
            # 获取读到的文件的后缀
            end = os.path.splitext(child)[-1]
            if  end == ".png" or end == ".webp" or end == ".gif" or end == ".jpeg" or end == ".jpg":
                print("文件" + child + " 后缀 " + end)
        else:
            # 递归遍历子目录
            child = child + "/"
            findAllPictures(child)

2.3 获取或许引证图片静态字符串

在这个环节,咱们重点是要找到在代码中或许会引证图片的字符串集合,如在Objective-C的.m文件中,咱们经常用如下代码去加载图片account_login来创立一个UIImageView对象, 针对Objective-C的.m文件内容,用正则过滤,匹配表达式为 @”(.*?)”,即可获取一切或许加载图片的字符串集合。

imgView.image = [UIImageimageNamed:@"account_login"];
br

关于Swift文件咱们一般经过如下代码去加载图片account_login,加载办法彻底不一样,针对Swift这种文件,正则表达式应为”(.?)”。

let imageView = UIImageView(frame: CGRectMake(100, 10, 200, 200))
imageView.image = UIImage(named:"account_login.jpg")
self.view.addSubview(imageView)

关于html文件咱们一般用如下代码去加载图片,正则表达式应为img\s+src=”‘[“‘]。

<html>
<body>
<img src="图片地址" alt="文本阐明" width=** height=**>
</body>
</html>

不同的文件加载图片的办法不同,如Objective-C、Swift、xib、storyboard、html、js、plist、json和css都不尽相同,鄙人面的表格,我整理出常用文件过滤图片运用的正则表达式。

百度APP iOS端包体积50M优化实践(二) 图片优化

2.4 获取未引证图片

经过2.2章节咱们获取的工程中的一切图片,经过2.3章节咱们获取代码中一切或许引证图片的静态字符串,那么关于每张图片而言,假如不在引证图片的静态字符串集合中,这张图片或许便是未引证的图片。

2.5 字符串拼接的常见case做二次过滤

经过上面的环节,咱们经过全字符串匹配获取了未引证的图片,实践开发进程,有一些常见状况,代码中引证图片的称号是经过字符串拼接生成的,因而咱们需求进行二次过滤。榜首种常见的case,便是当手机支撑暗黑办法时,同一个方位的图片一般会有两套,经过后缀如light、dark或许day、night来做区分;第二种常见的case,便是后缀是数字的图片序列,iOS端有一种动画类型是ImageView加载多图动画,图片称号是由字符串和动态数字后缀拼接而成,过滤时需求掩盖如下后缀_%d,_%ld,_%zd,_%lu。

三、Asset Catalog 图片优化

3.1 背景

Asset Catalog 是 Xcode 供给的在iOS7体系开端引进的资源办理东西,将分散在项目中大巨细小的资源进行一致寄存和会集办理,包含但不限于images、sprites、textures, ARKit resources和PDF,咱们能够把之前放在bundle的图片或许其他资源放入Asset catalog中,XCode最终一致紧缩成一个Assets.car的文件。

在Asset Catalog之前,咱们一般将图片直接放到工程的bundle,这种办法存在一些缺点:榜首、空间糟蹋,不同设备需求不同分辨率图片,所以在bundle里对同一张图片一起存在二倍图和三倍图,糟蹋资源;第二、图片紧缩只能针对单个文件,没有一致的紧缩功用;第三、信息冗余,每个图片资源都会存储自己的元数据和其他的一些特色信息,假如存在很多同类型的资源,这些相同的信息会发生冗余,形成空间糟蹋。

3.2 Asset Catalog优点

针对bundle存在的上述问题,Asset Catalog做了诸多优化,无论是包体积优化、一致的图片紧缩和便当的资源办理,仍是高效的IO操作,每一项优化都做到了极致,下面具体介绍:

榜首、包体积减肥:Asset Catalog为不同类型设备(分辨率不同)或许相同类型设备但不同装备(磁盘和内存不同)供给定制化资源下载,之前在bundle需求放二倍图和三倍图,同一张图片最终在用户手机上会有两份,有了Asset Catalog后,当用户下载App时,只有跟用户手机硬件设备参数相匹配的资源才会被下载,其他不会下载,比如说,iphone8手机用户只会下载二倍图片,iphone13的用户只会下载三倍图片,这样可显着削减下载包巨细。

第二、一致的图片无损紧缩:Asset Catalog默许对文件夹中的一切图片选用无损紧缩,紧缩办法是Apple Deep Pixel Image Compression,这是苹果新引进的一种紧缩办法,会依据图片的色谱特性挑选最优的算法进行紧缩,紧缩比能提高15~20%。WWDC2018:Optimizing App developer.apple.com/videos/play… 有具体介绍。具体来说,针对不同类型的图片选用有不同的优化办法,一类是简略的图片资源,如很多icon图片,这类图片只有相对简略的配色和设计。另一类指的是复杂的图片资源,Apple Deep Pixel Image Compression针对这两种办法都做了不同办法的优化,图片资源体积越大运用Asset Catalog后优化的作用就越显着,一致的紧缩更有利于完成包体积减肥,下面这张图是苹果官方给出的Apple Deep Pixel Image Compression体积紧缩比的优化。

百度APP iOS端包体积50M优化实践(二) 图片优化

第三、便当的资源办理:假如将图片直接放在工程目录下面,项目打包后图片文件是散落在iPA包里边,而假如用Asset Catalog来办理放在xcassets中,在打包后会将这些图片一致紧缩成一个Assets.car的文件。

第四、高效的I/O操作:Assets Catalogs图片加载耗时比一般的bundle加载图片耗时要少两个数量级,这是由于编译最终生成Assets.car文件包含了BOM文件,BOM文件供给了图片加载时需求的的rendition、renditionKey和attribute特色值,rendition是 CoreUI.framework 对某一图画资源的不同样式的总称,如@2x,@3x,每一个rendition有一个renditionKey与之对应,经过renditionKey获取到对应的attribute,attribute中包含了各种特色,如图片的分辨率、笔直巨细、水平巨细等参数。

用Assets Catalogs办理的图片,经过imageNamed办法进行加载,由于car文件里边的上述资源信息是XCode编译时生成好的,当解析完car文件后,能够直接经过图片称号获取renditionKey和attribute特色并读取图片资源,没有任何多余操作,相反关于用bundle办理的图片,额定的操作太多导致耗时严重。关于bundle办理图片有两种加载办法,榜首种经过imageName办法加载图片,需求先去Assets.car里边查询,由于图片资源并不在Assets.car里边,所以在获取rendition和renditionKey时多次调用canGetRenditionWithKey,canGetRenditionWithKey,最终再重新经过mmap加载读取图片特色和图片资源,形成rendition和renditionKey,总体耗时最大;第二种经过imageWithContentsOfFile加载图片,不需求去Assets.car里边查询,没有生成rendition和renditionKey的相关操作和缓存操作,只有读取图片特色和图片二进制的操作耗时,可是没有图片特色等相关缓存所以耗时比较长。

3.3 Assets.car生成进程

具体来说,Xcode 在处理Asset Catalog节点时, 构建 Asset Catalog 的东西 actool 会先对 Asset Catalog 中的 png 图片进行解码,得到 Bitmap 数据,然后再运用 actool 的紧缩算法进行编码紧缩处理生成Assets.car 文件,这就能够解释在Asset Catalog中放jpg格局图片,最终生成的Assets.car 文件中却是png格局图片。

3.4 Assets.car操作

用Assets Catalogs办理的图片,XCode编译时并不是简略的复制操作,而是将一切资源打包生成的Assets.car文件,这是一种紧缩文件,直接解压无法操作的,运用XCode 自带东西assetutil能够剖析.car文件,剖析命令如下所示:

sudo xcrun --sdk iphoneos assetutil --info ./Assets.car > ./AssetsInfo.js

经过AssetsInfo.json获取图片相关特色,可是无法获取里边的图片。

百度APP iOS端包体积50M优化实践(二) 图片优化

假如想将car文件中的图片提取出来,引荐一个开源东西叫Asset Catalog Tinkerer,能够从github下载,这里给出github地址:github.com/insidegui/A…

百度APP iOS端包体积50M优化实践(二) 图片优化

3.5 Asset Catalog的紧缩算法

运用3.4节介绍的XCode 自带东西assetutil能够知道每张图片的紧缩算法,Compression字段值代表不同图片的选用的不同紧缩算法,经过实践发现actool支撑的紧缩算法有 deepmap2、deepmap_lzfse、zip、lzfse、palette_img,具体选用哪种紧缩算法跟很多要素有关,如图片本身特性、打包的XCode版别、Framework支撑的iOS最低版别、编译装备(Asset Catalog Compiler – Options Optimization),从实践作用来看,XCode会依据归纳上述要素挑选一个紧缩比最优的算法,别的这些紧缩算法都是无损的。

百度APP iOS端包体积50M优化实践(二) 图片优化

3.6 不要做无损紧缩

开发者在图片放入Asset Catalog之前千万不要做无损紧缩,无损紧缩算法是经过改动图片的紧缩编码算法到达削减体积巨细的目的,不会改动解码后的Bitmap 数据,从3.3节中咱们知道Assets.car 文件的生成进程中,Asset Catalog 的东西 actool先做解码得到Bitmap数据,然后再编码紧缩处理,针对无损紧缩算法actool接纳的Bitmap 数据并没有改动,所以无损紧缩无法优化包体积,UI设计师给出的PNG图片假如选用Asset Catalog优化就千万不要做无损紧缩。

3.7 bundle多倍图片Asset优化

Asset Catalog是Apple在2013年发布的iOS7的体系开端引进的,从iOS 9 之后开端支撑做资源办理,老代码(尤其是16年前的代码)都是用bundle的办法去办理图片,为此,咱们开发脚本专门针对bundle多倍图片做查看,然后选用Asset优化,这种优化办法能够完成包体积立减一半,参阅脚本如下所示:


def find_all_bundle_pic(app_package_path, all_pic_list):
    """
    将一切bundle图片存入list中
    """
    pathDir = os.listdir(app_package_path)
    for child_file in pathDir:
        child_path = os.path.join('%s/%s' % (app_package_path, child_file))
        # isfile:假如child是一个存在的文件则回来true,否则(bundle、文件夹会等)回来false
        if os.path.isfile(child_path):
            if child_path.endswith(".png") or child_path.endswith(".jpg") or child_path.endswith(".jpeg") or child_path.endswith(".gif") or child_path.endswith(".webp"):
                if child_path.find(".bundle") > 0:
                    all_pic_list.append(child_path)
        else:
            find_all_bundle_pic(child_path, all_pic_list)
def find_opt_pic(all_picture_list,final_opt_pic_list):
    """
    查找bundle中重复的多倍图片
    """
    for picture in all_picture_list:
        if picture.endswith("@2x.png"):
            prefix_2x = picture[0: len(picture) - 7]
            for picture1 in all_picture_list:
                # 前缀匹配
                if picture1 != picture and picture1.startswith(prefix_2x):
                    if (len(picture) == len(picture1) and picture1.endswith("@3x.png")) or len(picture) == len(picture1) + 3:
                        final_opt_pic_list.append(picture)
                        final_opt_pic_list.append(picture1)

3.8 有损图片紧缩可削减Assets.car巨细

从3.6节咱们得知无损紧缩关于Asset Catalog是没有体积优化作用的,可是有损紧缩可削减Assets.car 巨细,由于Asset Catalog本身也会对图片进行紧缩优化,所以有损紧缩图片的收益没有bundle转Asset Catalog收益显着,常用的有损紧缩东西有TinyPng和pngquant。

TinyPng是一个网页版的东西,经过合并图片中相似的颜色,将 24 位的 PNG 图片紧缩成 8 位色值的图片,而且去掉了图片中不必要的元数据来完成紧缩。关于单张图片紧缩运用十分方便,链接地址如下:tinypng.com/ ,可是假如要处理批量图片紧缩,上传进程中简单出现上传不成功等问题,这个东西不支撑自界说紧缩装备。

pngquant是一个有损的PNG紧缩开源库,供给了命令行和源码库两种办法。将24位或32位的RGBA PNG图转换成8位PNG图并保存透明度通道。经过这个库的转化能够显著削减png文件巨细,pngquant选用的是本地脚本紧缩,东西下载地址:pngquant.org ,对批量紧缩图片支撑的比较友爱,pngquant支撑自界说紧缩质量,装备紧缩质量小于90后紧缩率会高于TinyPng,而且pngquant是开源的,能够自界说,这是百度APP图片紧缩的首选。

四、HEIC图片编码优化

4.1 HEIC图片编码优点

HEIC(High Efficiency Image Coding)是一种图画编码标准,它能够极大提升紧缩率,并有用减小贮存占用,自iOS 11和macOS High Sierra(10.13)开端,苹果将HEIC设置为图片存储的默许格局,它由动态印象专家小组(MPEG)开发,并在MPEG-H Part 12(ISO/IEC 23008-12)中界说,以下是HEIC图片的特色:

紧缩率高:HEIC图片比JPEG图片紧缩率高1.5倍,比PNG图片紧缩率高3倍,也比GIF图片紧缩率高3倍。

节约内存:HEIC图片比JPEG图片节约20%的存储空间,比PNG图片节约50%的存储空间,比GIF图片节约80%的存储空间。

解码效率高:在iOS体系中,HEIC选用硬解码,解码效率高,跟WebP(软编码)比较,是其100倍,但略慢于JPEG。

保存原始图画质量:HEIC图片选用H.264和JEP格局紧缩,能够保存原始图画质量。

支撑无损扩大:HEIC图片支撑无损扩大,能够将图片扩大两倍而不失真。

颜色处理方面:HEIC图片能够依据像素点的亮度散布主动亮度、对比度和饱和度,然后更好地还原图画的实在颜色。

体系兼容性好:咱们知道iOS 11开端HEIC是图片存储的默许格局,也便是iOS 11以后的体系都支撑HEIC图片,但咱们百度APP目前还支撑iOS10体系,对这部分用户怎么处理?在实践中发现,在iOS10体系上,当把HEIC图片放xcasset文件里,最终图片也是能够正常显现的,咱们做了一番原因排查,用Asset Catalog Tinkerer东西解压出Assets.car 文件,发现在xcasset里的HEIC图片,关于iOS10的体系,在打包时会被体系转化为png格局图片,Asset Catalog处理了HEIC图片的兼容性问题。

4.2 怎么生成HEIC图片

运用Mac自带功用完成png转HEIC办法:右键图片,快速操作-》转换图画, 格局选HEIF,挑选原图画。

百度APP iOS端包体积50M优化实践(二) 图片优化

优化成果如下所示,左面是png原图(1.6M),右边是HEIC图片(106KB)。

百度APP iOS端包体积50M优化实践(二) 图片优化

4.3 HEIC图片运用办法

4.3.1 有必要在Asset Catalog运用

HEIC图片有必要放在Asset Catalog中才能运用,bundle办法不支撑HEIC图片加载。

百度APP iOS端包体积50M优化实践(二) 图片优化

HEIC图片的加载运用办法和一般的asset图片一样,如下所示:

imgView.image = [UIImage imageNamed:@"account_login"];

4.3.2 关于大图HEIC格局显着体积小

理论上来说,HEIC格局图片的体积是PNG格局图片的三分之一,但实践进程发现关于大图,这个优化作用很显着,可是关于小图尤其是小于10K的图片,HEIC图片还有或许超过PNG格局图片,所以咱们在做HEIC图片编码优化时,关于小图不建议用这种办法。

4.3.3 带有Alpha通道的PNG图片不要做有损紧缩

在实践进程中发现,一张PNG原图,尤其是带有Alpha通道,经过有损紧缩(TinyPng或ImageOptim)后,再生成HEIC图片时,在iOS12,13,14体系上会显现绿幕,所以带有Alpha通道的PNG图片不要做有损紧缩,存在兼容性问题。

五、总结

图片优化是包体积优化的重头戏,百度APP经过两个Q的优化落地9.75M的收益处理了存量图片的问题,随后树立图片运用规范和无用图片检测流水线处理增量图片的问题。

本文具体介绍了无用图片检测计划、Asset Catalog图片优化和HEIC图片优化计划,后续咱们会针对其他优化类型具体介绍其原理与完成,敬请期待。

——END——

参阅资料:

[1]Asset运用办法:developer.apple.com/library/arc…

[2]Asset介绍:help.apple.com/xcode/mac/c…

[3]WWDC2018:Optimizing App Assets:developer.apple.com/videos/play…

[4]TinyPng:tinypng.com/

[5]pngquant:pngquant.org

[6]HEIC图片介绍:mobiletrans.wondershare.com/heic-conver…

引荐阅览:

浅论散布式练习中的recompute机制

剖析多利熊业务怎么基于散布式架构实践稳定性建造

百度工程师的软件质量与测试随笔

百度APP iOS端包体积50M优化实践(一)总览

基于FFmpeg和Wasm的Web端视频截帧计划

百度研发效能从度量到数字化蜕变之路