iOS9-by-Tutorials-学习笔记四:APP-瘦身

iOS9-by-Tutorials-学习笔记四:APP-瘦身

本文版权归作者所有,如需转载请联系孟祥月

CSDN博客:http://blog.csdn.net/mengxiangyue

独立博客:http://mengxiangyue.com

这篇文章在书中的标题是App Thinning,这里我给翻译成了App 瘦身。

本文然然进行了一些语法的修改,很开心她为我修改这些东西。她说我转折只会用但是,被她这么一说想想还真是只是会用但是,嘿嘿。

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

在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中,能够标记资源被使用设备的 MemoryGraphics ,如下:

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)
        }
      })
    }

  }

这时候我们运行代码,可能会在控制台输出错误,这是因为我们对应的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)
      }
    })
  }

}

如果用户已经下载过某个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()
  }

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

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

时间: 2024-12-30 23:29:15

iOS9-by-Tutorials-学习笔记四:APP-瘦身的相关文章

Caliburn.Micro学习笔记(四)----IHandle<T>实现多语言功能

Caliburn.Micro学习笔记(四)----IHandle<T>实现多语言功能 说一下IHandle<T>实现多语言功能 因为Caliburn.Micro是基于MvvM的UI与codebehind分离, binding可以是双向的所以我们想动态的实现多语言切换很是方便今天我做一个小demo给大家提供一个思路 先看一下效果 点击英文  变成英文状态点chinese就会变成中文                          源码的下载地址在文章的最下边 多语言用的是资源文件建

代码管理工具 --- git的学习笔记四《重新整理git(1)》

1.创建版本库 mkdir  创建目录 cd  地址,到该地址下 pwd 显示当前目录 1.创建目录 $ mkdir startGit $ cd startGit $ pwd 显示当前目录 或者cd到桌面,然后再创建目录 2.初始化版本库 $ git init 初始化仓库 提示信息:Initialized empty Git repository in /Users/xingzai/Desktop/startGit/.git/ 建立一个空的git仓库在/Users/xingzai/Desktop

Linux学习笔记四:Linux的文件搜索命令

1.文件搜索命令  which 语法:which [命令名称] 范例:$which ls  列出ls命令所在目录 [[email protected] ~]$ which ls alias ls='ls --color=auto' /bin/ls 另外一个命令:whereis [名称名称],也可以列出命令所在目录. [[email protected] ~]$ whereis ls ls: /bin/ls /usr/share/man/man1/ls.1.gz /usr/share/man/ma

小猪的数据结构学习笔记(四)

小猪的数据结构学习笔记(四) 线性表之静态链表 --转载请注明出处:coder-pig 本章引言: 在二,三中中我们分别学习了顺序表中的线性表与单链表,线性表有点类似于 我们前面所学的数组,而单链表使用的最多的是指针,这里问个简单的问题, 如果是在以前没有指针的话,前辈先人们怎么实现单链表呢?大家思考下! 没有指针,那么用什么来代替呢?前辈先人们非常机智,想出了使用下标+游标的方式 来实现单链表的效果!也就是今天要讲的--静态链表! 当然你也可以直接跳过本章,因为有了单链表就没有必要用静态链表了

Swift学习笔记四:数组和字典

最近一个月都在专心做unity3d的斗地主游戏,从早到晚,最后总算是搞出来了,其中的心酸只有自己知道.最近才有功夫闲下来,还是学习学习之前的老本行--asp.net,现在用.net做项目流行MVC,而不是之前的三层,既然技术在更新,只能不断学习,以适应新的技术潮流! 创建MVC工程 1.打开Visual studio2012,新建MVC4工程 2.选择工程属性,创建MVC工程 3.生成工程的目录 App_Start:启动文件的配置信息,包括很重要的RouteConfig路由注册信息 Conten

NLTK学习笔记(四):自然语言处理的一些算法研究

自然语言处理中算法设计有两大部分:分而治之 和 转化 思想.一个是将大问题简化为小问题,另一个是将问题抽象化,向向已知转化.前者的例子:归并排序:后者的例子:判断相邻元素是否相同(与排序). 这次总结的自然语言中常用的一些基本算法,算是入个门了. 递归 使用递归速度上会受影响,但是便于理解算法深层嵌套对象.而一些函数式编程语言会将尾递归优化为迭代. 如果要计算n个词有多少种组合方式?按照阶乘定义:n! = n*(n-1)*...*1 def func(wordlist): length = le

Android学习笔记四:添加Source

问题描述 Source not foundThe JAR file D:\.....\sdk\platforms\android-20\android.jar has no source attachment. 问题原因及解决办法 1. 使用SDK Manager下载最新版本的Sources for Android SDK 一般文件下载目录默认在SDK下的sources文件中即 \adt-bundle-windows-x86_64-20130522\sdk\sources\android-20

【Unity 3D】学习笔记四十二:粒子特效

粒子特效 粒子特效的原理是将若干粒子无规则的组合在一起,来模拟火焰,爆炸,水滴,雾气等效果.要使用粒子特效首先要创建,在hierarchy视图中点击create--particle system即可 粒子发射器 粒子发射器是用于设定粒子的发射属性,比如说粒子的大小,数量和速度等.在创建完粒子对象后,在右侧inspector视图中便可以看到所有的粒子属性: emit:是否是使用粒子发射器. min size:粒子最小尺寸. max size:粒子最大尺寸. min energy:粒子的最小生命周期

WEB前端学习笔记 四

接上一篇,web学习笔记 四,在此感谢您对此篇笔记的认可,但转发时请注明文章出自网知博学. 2.0  html的语法格式 html的标签要写在尖括号中 :<> 在在英文输入法状态下,按住shift键然后再按它左侧的尖括号就可了, 先学习一个简单的h1标签,是个标题标签,在html中这样写: <h1>我在h1标签中,我就是标题</h1> 那么h1标签中所包裹的文字,就标记成标题了.通过浏览器的解析后在页面上显示出来的效果就是字体加粗,加黑,和word中的标题性质一样! 大

初探swift语言的学习笔记四(类对象,函数)

作者:fengsh998 原文地址:http://blog.csdn.net/fengsh998/article/details/29606137 转载请注明出处 假设认为文章对你有所帮助,请通过留言或关注微信公众帐号fengsh998来支持我,谢谢! swift扩展了非常多功能和属性,有些也比較奇P.仅仅有慢慢学习,通过经验慢慢总结了. 以下将初步学习一下类的写法. 码工,最大爱好就是看码,而不是文字,太枯燥. // // computer.swift // swiftDemo // // C