App Thinning介绍
iOS9开始,Apple推出了一项新功能称为App Thinning,字面理解就是App瘦身。简单说来就是开发者将整个App包传到App Store,当不同用户设备下载App的时候,App Store通过根据不同设备特性分发经过剪裁的App,从而减少了用户包大小。
关于App Thinning有三种特性:slicing, bitcode, on-demond resource(ODR)。
Slicing介绍
Slicing通过将app bundle资源根据不同的设备特性分为不同的版本。对于图片资源,会根据设备(如iphone6 plus需要@3x,iphone 6需要@2x)所需图片分辨率不同分发给对应设备所需对应的图片资源。
例如在6plus中,大屏储存需要3x的图片,所以会分发对应的图片资源。
如何使用Slicing
对于Slicing的使用很简单只需要满足下面几个条件:
Nova-Merchant中对App Slicing的使用
关于Nova-Merchant中对Slicing的使用,首先要对Apple是如何通过asset catalog管理图片进行介绍。
经过调研发现,Apple对与那些通过asset catalog管理的图片在编译后,会在DPScope中生成Asset.car文件,该文件中包含了其管理的图片资源。App Slicing会对不同尺寸设备 编译之后的分发设备所需的@2x和@3x图片。
Nova-Merchant中对图片的使用主要在三个地方,1.Nova-Merchant target中的Images.xcassets.2.Development Pods中的NVImages。3.每个Pods中的Assets文件夹。
通过统计相关图片资源数量如下:
Images.xcassets |
Local Pods |
Remote Pods |
824张 |
230张 |
153张 |
目前对Nova-Merchant中如何使用Slicing有两种方案,并且都进行了调研和测试。
方案1
每个Pod单独建立各自的asset catalog,管理Pod自身的图片资源。这样在编译之后,会将项目中所有的asset catalog编译成一个Assets.car文件。
优点:每个pods单独管理自身的图片资源。
缺点:1.需要更改各个pod的podspec文件中的s.resource。指向该pod所建立的Asset.xcassets。2.不方便本地测试,只能通过发布到testflight测试。 3.需要推动各个pod去完成图片的管理工作。
方案2
仍然通过Nova-Merchant target中的Images.xcassets来管理整个项目中的图片资源。在pod install完毕后,各个Pod中的图片资源放到Images.xcassets中来统一管理。(具体方法就是将图片拷贝到Images.xcassets中,生成对应图片名字的.imageset文件夹,文件夹下生成Contents.json文件来指定对应的1x,2x,3x版本图片用于分发),同时删除掉这些图片放在原Pods下路径的图片。
优点:各个pod不需要任何工作量
缺点:1.需要在pod install完毕后,删除Target Support Files中Pods-Jovi-resources.sh中对应图片的 install_resource 行。不然编译会报错。2.通过脚本,在pod install完毕后,将NVImages 以及Pods下的图片资源放到Images.xcassets中,并删除指定的shell脚本行数。 脚本运行时间大概为40s左右
通过对方案1,方案2的优缺点分析,最终打算采用方案2的方法来对Nova-Merchant中图片进行管理。
结果展示
通过使用App slicing,编译后发现,不同设备所分发的Asset.car文件中图片确实是如预期所预料的那样
上图所示的是我通过iphon6设备编译后获得的Asset.car文件,我们可以发现只下发了该设备所需的@2x图片而不会下发设备不需要的@3x图片。
由于Nove-Merchant中在Pods中使用的图片量不多,并且大多数为对资源的使用通过s.resouce_bundle的形式,造成类似于MTADXSDK这种pods中的图片不能进行迁移,而目前只作了对于资源的使用通过s.resources的形式才进行图片迁移。所以执行脚本后只有少量的图片进行了迁移,迁移图片数量103张,但尽管如此,还是让安装包从63.9M缩减到了63.6M,安装包减小了0.3M。虽然效果不明显,但是确实有用,而对于主app那边,他们图片多半在NVImages和pods下,所以他们迁移后,app安装包瘦身效果达到了喜人的20%。
下面是执行完脚本后图片存放在JVPodsImages.xcassets下的截图:
图片迁移脚本采用了两个段脚本代码,一个是寻找图片所在的路径,另外一个是将图片拷贝到JVPodsImages.xcassets下,并且删除其对应在pods下路径的图片。
第一段脚本findImagesPath.rb是通过遍历podfile里面的每行内容,找到找到每个pods对应的podspec.json或者podspec文件,然后去以json格式方式读取podspec文件里面的内容, 来获取pods的资源引用方式——是通过s.resources还是通过s.resource_bundle方式,这里所说的资源是指图片,并且只是.png格式的图片。将所有可能包含有图片的路径全部放在一个array中,并返回给第二段脚本的使用。
第二段脚本merge_images.rb是将第一段脚本寻找图片路径的地址集合进行遍历,遍历该路径下的每个文件下,找到所有的.png格式图片的路径并存放在一个array中,然后将这个路径进行图片拷贝到指定的JVPodsImages.xcassets 下totalImages包下,并生成json文件,与此同时删除掉pods下相应的图片和Target Support Files中Pods-Jovi-resources.sh中对应图片的 install_resource 行。
由于我们项目中的Podfile文件里面的pods有些是本地localPods下的,有些是远程dianping pods库,所以执行脚本来分为两次,第一次执行本地Pods图片迁移,第二次执行远程图片迁移。执行命令:
ruby merge_images.rb local 和ruby merge_images.rb remote,这两行命令为了jenkins打包方便已加入到pods_install.shell脚本中。
最后,为了方便开发本地不必执行图片迁移脚本,而保持原来的执行pod_install脚本习惯。现在添加新的pod_install shell脚本,叫new_pod_install.sh,这个脚本只是用来我们开发人员在本地更新pods库时执行,不会影响现有的jenkins打包。执行命令行:sh new_pod_install.sh [clean] ,clean参数和以前一样是可选的。
后续有个问题是关于podspec文件中的引用资源方式为s.resource_bundle方式如何将图片进行迁移,将继续作为app sining方向。