iPhone经过这几年的发展,已经发生了很大的变化,例如屏幕变得更加多样,尺寸更多,内存变得更大,CPU的架构也在变化。伴随着iPhone的变化,iOS也在变化,例如AutoLayout、size classes、split view controller等。这些技术及设备的变化给我在开发的过程中也造成了许多的问题,不仅如此苹果通过不断推出新的技术,努力在帮助我们使用同一套代码开发适应多个设备的Universal的App。另一方面Universal App虽然在开发的过程中,方便了我们开发人员,可是对于用户来说就不那么友好了,由于需要适配多种设备,所以里包含所有设备的代码,但真正的在运行的时候,我们并不需要那么多相关的代码及资源。

例如下面的一张图,是一个App运行在iPhone 6+上,使用的各个资源相关的情况: 

上图中对勾标出来的是在iPhone 6+上真实运行的时候使用到的相关的资源及代码,对比有对勾的部分,更多的是没有被对勾标出来的部分。可以想象我们下载了一个App(前提这个App是Universal的),然后至少一半的代码及资源是我们不需要的,白白占用着我们的空间。这样对用户体验也不好。为了解决这个问题苹果在iOS 9给出了新的解决方案:

  • App Slicing 当你提交你的iOS 9 打包文件到App Store的时候,苹果编译你的资源和可执行文件,然后为每个设备生成一个特定的可执行文件。最终,设备只会下载适应与其特性的,并且它使用到的内容。这些特性包含显卡性能(原文单词:graphics capabilities)、内存级别、CPU架构、size classes、屏幕 scaling等。
  • On Demand Resouces 应用程序的资源只有在需要使用的时候才会下载,并且如果其他资源需要空间这些资源可以被移除。
  • Bitcode 在你提交App到App Store的时候,Bitcode可以作为中间产物一起提交。包含bitcode配置的程序将会在App store上被编译和链接。bitcode允许苹果在后期重新优化我们程序的二进制文件,而不需要我们重新提交一个新的版本到App store上。

这三个技术加起来,统一称为App Thinning。

Getting started

打开本章节的初始项目,然后选在iPad Air 2运行,这时候运行效果如下: 

伴随着模拟器启动起来的还打开了一个Finder窗口: 

这个Finder窗口能够打开,是因为在程序中添加了一个脚本,每次运行的时候都会执行,脚本所在地方如下: 

echo "App Size in KB:  `du -sk \"${CONFIGURATION_BUILD_DIR}/${EXECUTABLE_NAME}.app\"`"
if [ "${CONFIGURATION}" = "Debug" ]; then
open ${CONFIGURATION_BUILD_DIR}
fi
  • 1
  • 2
  • 3
  • 4
  • 1
  • 2
  • 3
  • 4

在Finder的Old CA Maps点击右键,选择显示包内容,如下: 

上图中标注的说明如下: 
1. Assets.car是Assets.xcassets被Xcode进行编译后的文件。 
2. Old CA Maps是真实运行在设备上的可执行文件。 
3. Santa Cruz PNGs 这个是图片文件,但是没有被编译到Assets.car文件中,这是因为它并没有放到Assets.xcassets中,而是放到了工程的顶层文件中。 
4. SD_Map.bundle 这个就是地图图片文件,但是将近120MB。

Measuring your work

本章介绍一些App瘦身相关的东西,所以我们必须能够测量App是否减少了。工程里面已经内置了一个脚本(上面代码里面有),能够在build的过程中输出App的大小。查看的位置如下: 

Slicing up app slicing

App slicing包含两部分内容:可执行文件分片(Executable slicing)和资源分片(resource slicing)。

Executable slicing 指的是在设备下载App的时候会根据设备的相关信息只是下载对应该设备的相关的可执行文件,并不会包含其他设备及架构的可执行文件,达到App安装包的缩小。并且这个功能并不需要我们做太多,App Store默认支持的。

默认情况下提交到App Store的包是包含所有的内容的,这些都在配置文件里面,App Store会自动创建对应于每个类型的可执行文件。这个在iOS9+上支持。

Being smart with resources

Resource slicing 需要我们一小部分简单的工作就能实现。如果使用Resource slicing,则要保证我们的资源都被Asset Catalogs管理。在Xcode 7中,能够标记资源被使用设备的 Memory 和 Graphics ,如下: 

Your first fix

在开始的时候介绍过Santa Cruz PNGs这个文件因为被放到Main bundle中,所以不能被编译进入到Assets.car,进而也不能使用Resource slicing。下面看一下我们怎么修改,使其能够使用: 

选择New Image Set后,将新加入的set命名为Santa Cruz,紧接着做如下操作: 

纠正一下 上图左边的内容应该是删除,包括在Finder内也应该删除

然后在不同的设备上运行App,最后发现Asset.car文件的大小并不一致。这个是因为在安装的时候,会根据设备安装对应的资源。

Lazily (down)loading content

苹果提供On-Demand Resources技术,简称ODR。ODR允许你将资源存储在苹果的服务器上,然后在你App使用的时候再去下载。NSBundleResourceRequest是处理ODR的类,使用这个类能够通过tag下载对应的资源。images, data, OpenGL shaders, SpriteKit Particles, Watchkit Complications等都可以使用ODR。

Wire things up to use tags

下面我们修改代码,实现资源的下载,修改MapChromeViewController.Swift对应方法如下:

  private func downloadAndDisplayMapOverlay() {
// displayOverlayFromBundle(NSBundle.mainBundle())
guard let bundleTitle = mapOverlayData?.bundleTitle else {
return
} let bundleResource = NSBundleResourceRequest(tags: [bundleTitle]) bundleResource.beginAccessingResourcesWithCompletionHandler { [weak self] (error) -> Void in
NSOperationQueue.mainQueue().addOperationWithBlock({ () -> Void in
if error == nil {
self?.displayOverlayFromBundle(bundleResource.bundle)
}
})
} }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

这时候我们运行代码,可能会在控制台输出错误,这是因为我们对应的bundle并没有tag,我们需要给bundle添加tag: 

然后我们重新编译运行我们的程序,然后按照上面的查看编译运行的程序的大小,发现小了许多。对比之前的编译生成的文件,发现运行文件里面不包含bundle了。 

如果你的App在App Store上可能这个资源文件下载的很慢。但是在开发的过程中,Xcode会利用本地网络作为服务器,然后在设备上能够下载到,所以在开发的过程中如果电脑关了,那ODR也就不能使用了。

Make it download faster

在我们使用ODR的过程中,如果bundle比较大,可能再下载的过程中就会比较耗时,并且在下载过程中用户不知道,这样用户体验就不好。我们可以再Resource下载的过程中给用户一些提示,修改下面的代码:

// add 为新添加的 ProgressView是程序已经添加上的
private func downloadAndDisplayMapOverlay() {
// displayOverlayFromBundle(NSBundle.mainBundle())
guard let bundleTitle = mapOverlayData?.bundleTitle else {
return
} let bundleResource = NSBundleResourceRequest(tags: [bundleTitle]) bundleResource.loadingPriority = NSBundleResourceRequestLoadingPriorityUrgent //add loadingProgressView.observedProgress = bundleResource.progress // add loadingProgressView.hidden = false // add
UIApplication.sharedApplication().networkActivityIndicatorVisible = true // add bundleResource.beginAccessingResourcesWithCompletionHandler { [weak self] (error) -> Void in
NSOperationQueue.mainQueue().addOperationWithBlock({ () -> Void in
self?.loadingProgressView.hidden = true // add
UIApplication.sharedApplication().networkActivityIndicatorVisible = false // add
if error == nil {
self?.displayOverlayFromBundle(bundleResource.bundle)
}
})
} }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27

如果用户已经下载过某个bundle,下次在使用的时候就不会再去下载了。

The many flavors of tagging

虽然添加了ProgressView,在体验是好了一点,但是需要注意测试的时候是使用的本地的网络,所以比较快,但是如果要是提交到App Store上,那可能下载就是比较慢了,如果再配上用户没有WiFi那可能就没法用了,所以我们还需要做其他的一些调整。

Initial install tags

使用Initial install tags,我们可以设置哪些bundle会在我们App初始化安装的时候就会被下载。 下面下介绍一下ODR三种下载的时机吧: 
Initial Install Tags 在ipa下载的时候一同下载 
Prefetched Tag Order 在程序下载完成后,下载对应的资源,然后按顺序排列。 
Prefetched Tag Order 按需下载 
下面是配置的地方: 

Purging content

应用程序在使用的过程中通过ODR下载了对应的bundle,但是有时候我们需要清理一些已经下载过的并且不使用的bundle。在介绍怎么删除之前先看一下怎么查看下载的ODR: 

Set a resource to be purged

在MapChromeViewController.swift添加如下代码:

  // new add 是新加的代码
var overlayBundleResource: NSBundleResourceRequest? // new add
private func downloadAndDisplayMapOverlay() {
// displayOverlayFromBundle(NSBundle.mainBundle())
guard let bundleTitle = mapOverlayData?.bundleTitle else {
return
} let bundleResource = NSBundleResourceRequest(tags: [bundleTitle])
overlayBundleResource = bundleResource // new add bundleResource.loadingPriority = NSBundleResourceRequestLoadingPriorityUrgent //add loadingProgressView.observedProgress = bundleResource.progress // add loadingProgressView.hidden = false // add
UIApplication.sharedApplication().networkActivityIndicatorVisible = true // add bundleResource.beginAccessingResourcesWithCompletionHandler { [weak self] (error) -> Void in
NSOperationQueue.mainQueue().addOperationWithBlock({ () -> Void in
self?.loadingProgressView.hidden = true // add
UIApplication.sharedApplication().networkActivityIndicatorVisible = false // add
if error == nil {
self?.displayOverlayFromBundle(bundleResource.bundle)
}
})
} } // new add
override func viewDidDisappear(animated: Bool) {
super.viewDidDisappear(animated)
// 告诉系统结束了对资源的访问
overlayBundleResource?.endAccessingResources()
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36

上面的代码,我做测试的时候不清楚会在什么时候会删除,我也模拟了内存警告,如果谁清楚,还请告诉我,谢谢。

坚持了好几天中午写完了,这篇笔记,一篇笔记13张截图,好累。

【转】app瘦身的更多相关文章

  1. iOS - Bitcode App 瘦身中间码

    1.Bitcode 随着 Xcode7 的发布,Apple 提供了一项新的技术来支持 App 瘦身功能,那就是 Bitcode. 1.BitCode 是什么 Bitcode is an interme ...

  2. App瘦身、性能优化总结

    App瘦身 资源瘦身 使用tinypng压缩PNG图片.视频可以通过 Final cut等软件进行分辨率压缩.音频则降低码率即可. 非必须资源文件可以放到自己服务器上 启动图使用 LaunchScre ...

  3. 包建强的培训课程(6):Android App瘦身优化

    v\:* {behavior:url(#default#VML);} o\:* {behavior:url(#default#VML);} w\:* {behavior:url(#default#VM ...

  4. app瘦身和包压缩技术有什么区别?

    APP瘦身 针对app文件中的文件进行优化,利用素材的拉伸,祛除不必要的文件,优化png, jpg素材,压缩音视频素材等方式实现app文件的减小. 包压缩技术 所谓包压缩,顾名思义就是将手游的安装包体 ...

  5. 如何实现手游app瘦身?

    手游服务商来说,手游包体大一直是个很困扰的问题.一款手游产品而言,包体大小和更新方式对于有效用户的转化率往往起到非常关键的作用,话说手游安装包越小,用户转化率越高,那该如何实现app瘦身呢? 工具/原 ...

  6. iOS App 瘦身方案

    缩减iOS安装包大小是很多中大型APP都要做的事,一般首先会对资源文件下手,压缩图片/音频,去除不必要的资源.这些资源优化做完后,我们还可以尝试对可执行文件进行瘦身,项目越大,可执行文件占用的体积越大 ...

  7. APP瘦身绝技(快速减少包大小)

    如果要清理无用类文件和无用图片,参考博客<iOS 清理Xcode项目中没有使用到的图片资源和类文件>.当下众多app项目,尤其是初创公司,明显的特点就是,开发周期短,迭代更新快,甚至一周一 ...

  8. App瘦身

    http://www.zoomfeng.com/blog/ipa-size-thin.html https://github.com/ming1016/SMCheckProject

  9. IOS APP 瘦身

    只保留其中一宗编译环境包 lipo -thin armv7 XXAPP -output XXAPP.armv7

随机推荐

  1. jquery find选择器在不同浏览器下的差异

    初步测试,5000个节点的隐藏. 代码如下: <!doctype html> <html lang="en"> <head> <scrip ...

  2. C++普通函数与模板函数以及特化函数重载的优先级问题

    在面对C++模板的时候,需要十分注意,因为模板的复杂性有很多情况,所以最好学习模板的方法我个人认为就是用到就去学,用不到就尽量别去看各种奇门怪技,因为你就算看了,好不容易搞懂模板的实现内部了,包括元编 ...

  3. [Python笔记]第十一篇:面向对象

    以上就是本节对于面向对象初级知识的介绍,总结如下: 面向对象是一种编程方式,此编程方式的实现是基于对 类 和 对象 的使用 类 是一个模板,模板中包装了多个“函数”供使用 对象,根据模板创建的实例(即 ...

  4. Day3 set集合、函数和装饰器

    set特性:无序,不重复,可嵌套 创建setset_example = set("123", "213", "234", "432 ...

  5. FCKEditor使用说明

    1.基本设置   先看看效果是什么样的:   效果图: 那么为什么说是FCKeditor的冰冷之心呢?这不是哗众取宠,主要是说它使用起来有点麻烦,下文就详细说明如何搞定这玩意儿. 1.FCKedito ...

  6. Python下划线的使用 _ __ __obj__

    Python 用下划线作为变量前缀和后缀指定特殊变量.   _xxx 不能用'from moduleimport *'导入 __xxx__ 系统定义名字 __xxx 类中的私有变量名   核心风格:避 ...

  7. P1896 [SCOI2005]互不侵犯King

    题目描述 在N×N的棋盘里面放K个国王,使他们互不攻击,共有多少种摆放方案.国王能攻击到它上下左右,以及左上左下右上右下八个方向上附近的各一个格子,共8个格子. 输入输出格式 输入格式: 只有一行,包 ...

  8. oracle中字符串的大小比较,字符串与数字的比较和运算

    Oracle比较字符串是根据ASCII码来的,第一个字母的ASCII大小比较如果相等再比较下一个,类推.字符串和数字进行操作是会报异常的,因为类型不一样不能进行比较. Oracle在执行SQL的时候有 ...

  9. SAE、搜狐云景和百度云之初见

    近期有需求将我们的应用部署到公有云的服务平台上,于是找了几家公有云服务做了一下调研, 首先对比一下他们提供的功能: 功能 SAE 搜狐云景 百度云 版本控制工具 svn  GIT,和百度云的比起来,用 ...

  10. 转:MFC之COleVariant

    COleVariant 本质上是一个枚举,用同一种类型来表达不同的子类型.如同boost中的variant. 例子 COleVariant var(3.6f); float v = var.fltVa ...