iOS--App功耗优化
良好的用户体验需要如下要素:
电池寿命长。随着能效降低,电池寿命也会降低。但用户想让自己的移动设备全天候待命。
速度快。iOS系统处理复杂操作时仍能提供很好的性能。
响应快。同一时刻消耗太多资源会使UI卡顿,响应用户速度变慢。
温度低。app消耗的硬件资源的越多,系统工作越繁重,设备的温度就会逐渐上升。这时系统会通过一些措施降低设备温度。
iOS运用了很多先进的节能技术确保用户有很好的用户体验,包括软硬件配合优化、先进的App调度机制、网络延时操作、任务优先级管理机制等。
App中很小的低效行为在整个系统中累加后,会对电池寿命、性能、响应速度和温度产生明显的影响。使用苹果推荐的API,以确保系统可以正确地判断如何更好地管理我们的app和app使用的各种资源。分批、减少网络操作。尽可能避免不需要的UI刷新。功耗大的操作应该在用户的控制之中。比如,如果用户正在玩一个视图非常复杂的大型游戏,电量消耗很快用户是可以理解的。不响应用户操作时,app尽量不要执行任何操作。
基本概念
没有一劳永逸地解决能耗问题的方案。很多技术和操作影响着电量的使用:
CPU。 CPU是电能消耗大户,高CPU使用量会迅速消耗掉用户的电池电量。app做的每件事几乎都需要用CPU,所以使用CPU要精打细算,真正有需要时通过分批、定时、有序地执行任务。
设备唤醒。iOS设备通过睡眠来节能。只要设备被唤醒,屏幕和其他的硬件资源就必须通电,会产生很高的间接功耗。如非必须,app要尽量保持闲置,不要推送消息或用其他方式唤醒设备,特别是app在后台的时候。
网络操作。大多数app都需要网络操作。网络通信时,蜂窝数据和Wi-Fi等元器件开始工作就会消耗电能。分批传输、减少传输、压缩数据、恰当地处理错误,你的app省电效果会很显著。
图像、动画、视频。app内容每次更新到屏幕上都需要消耗电能处理像素信息。动画和视频格外耗电。不经意的或者不必要的内容更新同样会消耗电能,所以UI不可见时,应该避免更新其内容。
位置。很多app为了记录用户的活动或者提供基于位置的服务会进行定位。定位精度越高,定位时间越长,消耗电量也就越多。所以app应该尽量降低定位精度、缩短定位时间。不需要位置信息之后立即停止定位。
动作传感器。长时间用不上加速度计、陀螺仪、磁力计等设备的动作数据时,应该停止更新数据,不然也会浪费电能。应按需获取,用完即停。
蓝牙。蓝牙活动频度太高会消耗电能,应该尽量分批、减少数据轮询等操作。
简化、有序地工作
减少后台工作
实现UIApplicationDelegate中的方法,应用进入后台前做好暂停任务,保存数据等工作。如果确实需要完成用户执行的一些任务,应该调用UIApplicationDelegate中的beginBackgroundTaskWithExpirationHandler: 方法,这样后台任务可以继续执行几分钟。任务执行完毕后一定要调用endBackgroundTask:方法,不要等着系统强行挂起进程。
iOS8之后,系统引入了CPU监控机制,以观察后台app的CPU使用量是否超过了限制,如果超出限制,进程可能会被关闭。大多数情况下正常的后台任务不会遇到这种情况,如果遇到了可以查看崩溃日志信息,异常类型为EXC_RESOURCE,子类型为CPU_FATAL。
用QoS分级有序工作
多个app和众多操作需要共享CPU、缓存、网络等资源,为了保持高效,系统需要根据不同任务的优先级智能地管理这些工作。比如更新UI这种重要的事需要多分配资源,而一些后台任务可以延迟一些执行。服务质量(quality of service, 以下简称QoS, iOS8引入)级别可以通过NSOperation, NSOperationQueue, NSThread objects, dispatch queues, 和pthreads (POSIX threads)指定工作的优先级。有4种QoS级别(和2种特殊的级别),如表2所示,划线的两个特殊的级别一般不应该使用,仅作了解即可。最好情况是,用户不交互的时候,90%以上的时间让app运行在Utility或更低级别。
原来GCD中的全局并发队列(global_queue)用高、默认、低、后台来指定队列的优先级。现在应该改用QoS,两者的对应关系如表。
少使用定时器
app经常滥用定时器。想一下你app中的定时器,是否真的有必要存在。抛开具体场景不说,如果定时器触发太频繁,能耗影响是比较大的。
用事件通知代替定时器。有些app用定时器监控文件内容、网络或者其他状态的变化,这会导致CPU无法进入闲置状态而增加功耗。建议使用事件通知来代替定时器,比如使用dispatch source监测文件变化。对于系统提供的服务,尽量使用事件通知,表是常见的系统通知和对应的监测方法。
GCD里的dispatch queues、dispatch semaphores等同步工具比定时器效率高很多,尽量不要用定时器做同步工具。
所有需要指定一个最后期限的函数或方法都属于定时器,比如:
1. 高级定时器包括dispatch timer sources、CFRunLoopTimerCreate和其他CFRunLoopTimer函数、NSTimer、performSelector:withObject:afterDelay:方法。
2. 底层定时器包括sleep, usleep, nanosleep, pthread_cond_timedwait, select, poll, kevent, dispatch_after, dispatch_semaphore_wait。
如果一定要用定时器,尽量高效地使用,可以参照下列指导方针:
1. 设置一个合适的超时时间。
2. 不再需要时及时关闭重复性定时器。
3. 设置触发公差。
优化I/O访问
app每次执行I/O任务,比如写文件,会导致系统退出闲置模式。而且写入缓存格外耗电。通过下列方法可以提高能效、改善app性能。
1. 减小写入数据。数据有变化再写文件,尽量把多个更改攒到一起一次性写入。如果只有几个字节的数据改变,不要把整个文件重新写入一次。如果你的app经常要修改大文件里很少的内容,可以考虑用数据库存储这些数据。
2. 避免访问存储频度太高。如果app要存储状态信息,要等到状态信息有变化时再写入。尽量分批修改,不要频繁地写入这些小变动。
3. 尽量顺序读写数据。在文件中跳转位置会消耗一些时间。
4. 尽量从文件读写大数据块,一次读取太多数据可能会引发一些问题。比如,读取一个32M文件的全部内容可能会在读取完成前触发内容分页。
5. 读写大量重要数据时,考虑用dispatch_io,其提供了基于GCD的异步操作文件I/O的API。用dispatch_io系统会优化磁盘访问。
6. 如果你的数据由随机访问的结构化内容组成,建议将其存储在数据库中,可以使用SQLite或Core Data访问。特别是需要操作的内容可能增长到超过几兆的时候。
7. 了解系统如何缓存文件、如何优化缓存的使用。如果你不打算多次引用某些数据,不要自己缓存数据。
低电量模式
iOS9之后,iPhone增加了低电量模式,用户如果希望延长iPhone电池的寿命,可以在设置 > 电池中开启该功能。开启该功能之后iOS会采取一些措施,比如:
1. 降低CPU和GPU性能
2. 暂停随意的和后台的活动,包括网络
3. 降低屏幕亮度
4. 缩短自动锁屏时间
5. 关闭邮件刷新
6. 关闭视角缩放
7. 关闭动态壁纸
你的app也应该做一些事情帮助系统节省电能,比如,可以减少动画、降低帧率、停止位置更新、关闭同步和备份功能等等。可以通过向NSNotificationCenter注册NSProcessInfoPowerStateDidChangeNotification 通知监听低电量模式状态。
网络操作
只要app一执行网络操作,就会产生大量间接能耗(overhead cost)。网络硬件,比如蜂窝数据和Wi-Fi电路,为了省电默认是不通电的。为了执行网络操作,这些资源必须通电,之后为了等待接下来可能出现的任务,它们在操作完成后会继续保持一段时间的活跃。零散的网络传输会导致很高的间接能耗,迅速消耗电池电量
缩减网络请求
1. 减少、压缩网络数据。可以降低上传或下载的多媒体内容质量和尺寸等。
2. 使用缓存,不要重复下载相同的数据。
3. 使用断点续传,否则网络不稳定时可能多次传输相同的内容。
4. 网络不可用时不要尝试执行网络请求,尽量只在Wi-Fi情况下联网。
5. 让用户可以取消长时间运行或者速度很慢的网络操作,设置合适的超时时间。
6. 网络请求失败后用SCNetworkReachability的通知监测网络状态,网络可用后再重试。
延迟联网
分批传输。比如,下载视频流时,不要传输很小的数据包,直接下载整个文件或者一大块一大块地下载。如果提供广告,一次性多下载一些,然后再慢慢展示。如果要从服务器下载电子邮件,一次下载多条,不要一条一条地下载。
网络操作能推迟就推迟。如果通过HTTP上传、下载数据,建议使用NSURLSession中的后台会话,这样系统可以针对整个设备所有的网络操作优化功耗。将可以推迟的操作尽量推迟到设备充电状态并且连接Wi-Fi时进行,比如同步和备份工作。
VoIP类应用应该用PushKit而不是长连接。
图像、动画、视频
以下列指导方针优化内容更新:
1. 减少app使用的视图数量。
2. 减少不透明视图的使用,比如视图上显示一个半透明模糊效果。如果要用不透明效果,避免用在内容频繁变化的地方。另外,由于内容变化后背景视图和半透明视图必须同时改变,这也会放大功耗。
3. 避免绘制不可见的内容,比如app的内容被其他视图遮挡、被剪切(clipped)或者出画了。
4. 动画尽可能用较低的帧率。比如,高帧率在玩游戏时有意义,但是菜单画面可能较低的帧率就够了。只有对用户体验有影响时才使用高帧率。
5. 执行动画时不要修改帧率。比如,你的app帧率是60fps,整个动画就保持这个帧率不要变。
6. 避免同时在屏幕上使用多种帧率。比如,你的游戏人物是60fps,天上的云彩移动又是30fps,不要出现这种状况,就算提高其中某一个的帧率,也要用相同的帧率。
7. 开发游戏时使用推荐的framework。这些framework针对性能和功耗是做过优化的:2D游戏用SpriteKit、3D游戏用SceneKit、画面非常逼真的游戏用Mietal。
全屏播放视频时iOS可以通过高效管理各种资源来优化能耗,但是在视频上下额外添加图层会影响功耗优化效果。app尽量不要在全屏视频上添加额外的图层(即使是隐藏的图层)。如果用户有需要,可以通过比如单击这样的方式来显示播放控制之类的UI,不需要了以后应该把这些图层移除掉。
优化定位和动作(Motion)
错误使用定位会阻碍设备进入睡眠模式,让定位硬件部分持续通电而消耗电池电量,这会使用户体验变的很差,下面来看一下如何针对功耗优化定位服务。
如果你的app只是需要快速确定一下用户的位置,最好用CLLocationManager的requestLocation (iOS9引入)方法。定位完成之后会自动让硬件断电。
除了导航,大多数app不需要一直实时更新位置。需要位置服务时开启一下定位,尽量多隔一些时间再进行下次位置更新,更新完了之后马上关掉定位。除非用户在移动的交通工具里,否则不频繁地更新位置一般没多大问题。
尽量降低定位精度。iOS设备默认采用最高精度定位,如果你的app不是确实需要米级的位置信息,不要用最高精度(kCLLocationAccuracyBest)或10米左右的精度(kCLLocationAccuracyNearestTenMeters)。一般来说Core Location提供的精度比你设置的要好,比如你设置为3公里左右的精度,可能会收到100米左右的精度信息。
如果定位精度一直达不到设置的精度时,停止更新位置,稍后再试。
需要后台更新位置时,尽量把pausesLocationUpdatesAutomatically设为YES,如果用户不太可能移动的时候系统会自动暂停位置更新。
后台定位时延时更新位置。如果要做一个健身类的软件追踪用户徒步的距离,可以等用户移动一段距离或者过一段时间之后再更新位置,这样可以让系统优化能耗。
合理使用访问监控(visit monitoring)。访问监控允许app接收用户频繁或长时间访问的场所的进出通知,比如在家、公司或者去喜欢的咖啡馆。
尽量不要用significant-change位置服务,优先考虑用region monitoring、 visit monitoring。
用户移动、摇晃、倾斜设备时,会产生动作(motion)事件,这些事件由加速度计、陀螺仪、磁力计等硬件检测。不需要监测设备方向时停止通知。比如用户进入一个只需要竖着显示的画面,及时把方向改变通知关掉。开启动作事件前设置一个比较大的更新间隔。
优化通知
尽量用本地通知(local notification),如果你的app不依赖外部数据,而是需要基于时间的通知,应该用本地通知,可以让设备的网络硬件休息一下。
远程推送有两个级别,一个是立即推送,另一个是针对功耗优化过的延时推送。如果不是真的需要即时推送,尽量使用延时推送。
优化蓝牙通信
1. 没有必要的时候不要扫描蓝牙外设。
2. 扫描外设时一般不要用CBCentralManagerScanOptionAllowDuplicatesKey。
3. 只查找你需要的外设服务。外设可能提供很多服务和特性(characteristic),查找外设的时候可以指定UUID。
4. 不要轮询设备特性值,用通知监测特征值的变化。
5. 特性值不再提供通知或者不再需要通信的时候就断开连接。
Apple Watch
Apple Watch有很多节能的特征,而且watchOS的API也非常高效。但是仍然需要坚持下面的指导方针:
1. 减少iPhone和手表之间的通信,分批通信,用NSURLSession的后台会话延迟联网。
2. 去掉不必要的内容刷新。
3. 尽量用暗色,亮色会显著增加功耗。除了省电,暗色还可以让屏幕边框和显示内容融合得更好
4. 缩小媒体数据大小。如果你的app需要从服务器下载图片,下载适合手表屏幕尺寸的图片,不要下载大图再缩放,这样网络和CPU功耗都更高。
5. 少做工作。如果app需要复杂或者大量的处理任务,考虑将其发送给iPhone处理。
监测功耗
测试或者debug你的app时,注意下列情况:
电池消耗过快
app应该闲置时却活动
响应慢,UI卡顿
主线程执行大量任务
动画使用过多
不透明视图过多
切换应用
内存慢,没有缓存(Memory stalls and cache misses)
内存警告
Lock contention
频繁地切换context
过度使用定时器
频繁绘制屏幕
频繁或者反复执行很小数据的I/O操作
很高的通信间接功耗,比如传输零散的小数据包和缓冲
设备不休眠
用Xcode测量功耗
开发app的过程中是诊断能耗最好的时机。在Xcode中选择View > Navigators > Show Debug Navigator,这里提供了很多仪表用于分析功耗。Energy impact可以查看正在运行的app的功耗,如图4。
Cost 和 overhead。蓝色的是CPU执行任务消耗的电量,红色的是执行你的app消耗的其他系统资源电能。
CPU。灰色方块表示你的app正在使用CPU执行任务。
Network。灰色方块表示你的app正在进行网络操作。
Location。灰色方块表示你的app正在使用位置服务。
GPU。灰色方块表示你的app正在使用GPU执行图像相关操作,比如绘图或者播放动画。
Background。灰色方块表示你的app处于后台状态,但是让系统仍然保持唤醒状态。
和用户交互时功耗应该比用户选择一个复杂的操作时低,不交互时不应该有功耗。
使用Instruments之前应该先考虑用Xcode中的仪表检查功耗问题。
用Instruments检测功耗
1. 启动Instruments,选择你的设备和要检测的app,打开Energy Log,如图5。推荐使用无线方式连接设备,这样可以完全模拟使用电池工作的真实场景。将设备和Mac用数据线连接好,在图5页面按住?选择设备,会出现带有Wireless后缀的设备。
2. 点击Record按钮或者按⌘+R,开始记录。
3. 在设备上正常使用app,这时会记录功耗数据。
4. 点击Stop按钮或按⌘+R,完成记录。
查看记录的数据有没有异常或者可以优化的地方,如图6。
提示:app能耗偶尔比较高不一定是app的问题,可能当时的操作本身就很耗电,比如说执行网络操作的时候使用GPS。你应该关注的是峰值、出乎意料的高功耗区域和其他可以优化的地方。
用iOS设备直接记录功耗
不用有线或无线方式连接Instruments,直接用iOS设备记录功耗可以获得更真实的数据。记录工作几乎不耗电,可以全天候使用,即使设备进入睡眠模式也会持续记录。但是如果设备关机后,数据可能会丢失。
在设备上进入设置 > 开发者 > Logging.
开启功耗记录,如图7。
点击Start Recording按钮。
正常使用设备。
设备记录完成后返回图6所示页面,点击Stop Recording.
在Instruments中选择好设备,进入Energy Log.
选择File > Import Logged Data from Device。
使用其他模板和仪器检测功耗
有很多因素会影响app的功耗,Engergy Log这个模板可以分析一部分因素,你还可以用其他的模板或工具检查app对功耗的影响。
Activity Monitor. 查看CPU、I/O、网络使用。
Core Animation. 测量图像性能和CPU使用量。
GPU Driver. 测量GPU驱动数据。
Location Energy Impact. 测量Core Location对能耗的影响。
Metal System Trace. 通过追踪app、驱动、GPU的数据,检测iOS Metal应用的性能。
Network. 分析TCP/IP 和UDP/IP 连接。
Time Profiler. 该工具检测app正在运行的线程,隔一段时间采样一次。每个采样都有完整的调用栈(backtrace),你可以找出你的代码中哪里耗费了大量时间。
自定义模板。上面的模板或仪器可以分析app的多个方面。如果你想查看特定的几个方面,可以向Instruments中添加单个的仪器。如果以后可能还要用相同的分析类型,可以把你配置的工具保存成模板。
测试性能
app的性能下降会导致功耗增加,可以用Xcode中的XCTest框架测试你的代码。代码会在性能测试的block中连续运行10次,并给出运行平均时间的标准差。
iOS--App功耗优化的更多相关文章
- iOS app性能优化的那些事
iPhone上面的应用一直都是以流畅的操作体验而著称,但是由于之前开发人员把注意力更多的放在开发功能上面,比较少去考虑性能的问题,可能这其中涉及到objective-c,c++跟lua,优化起来相对 ...
- iOS App 性能优化总结
今天简单总结一些clientapp 优化的方案和方向. 我相信开发一个app大部分团队都能够完毕,可是性能久不一样啦,和我们都写一个冒泡算法一样,我相信每一个人写的冒泡算法都不一样,这些区别就带来了性 ...
- Facebook iOS App如何优化启动时间
http://www.cocoachina.com/ios/20160105/14870.html 提高 Facebook 应用的性能已经成为 Facebook 持续关注的领域.因为我们相信一个高性能 ...
- iOS APP性能优化
:应用启动时间 应用启动时,只加载启动相关的资源和必须在启动时加载的资源. :本地图片加载方式 本地图片加载常用方法有两种: a. [UIImage imageNamed:@"xx.png& ...
- iOS App内存优化之 解决UIImagePickerController的图片对象占用RAM过高问题
这个坑会在特定的情况下特别明显: 类似朋友圈的添加多张本地选择\拍照 的图片 并在界面上做一个预览功能 由于没有特别的相机\相册需求,则直接使用系统自带的UIImagePickerController ...
- 马蜂窝 iOS App 启动治理:回归用户体验
增长.活跃.留存是移动 App 的常见核心指标,直接反映一款 App 甚至一个互联网公司运行的健康程度和发展动能.启动流程的体验决定了用户的第一印象,在一定程度上影响了用户活跃度和留存率.因此,确保启 ...
- iOS项目分析及优化
iOS项目分析及优化 来源:吴白的简书 从代码看一个程序员的笔力 从代码的整洁度上就可以看出一个程序员的实力,规范其实就是让你养成一种良好习惯的标杆,在此面前我们应该顺从.本篇我们以OC为例,统 ...
- iOS APP可执行文件的组成
iOS APP编译后,除了一些资源文件,剩下的就是一个可执行文件,有时候项目大了,引入的库多了,可执行文件很大,想知道这个可执行文件的构成是怎样,里面的内容都是些什么,哪些库占用空间较高,可以用以下方 ...
- fir.im Weekly - 如何进行 Android App 性能优化
关于 Android App 的优化,@anly-jun 用 3 个月完成了这一系列文章,从 性能分析工具 到 ANR .Layout .消除卡顿 到 内存优化.内存分析工具大概十五六篇,并对此做一个 ...
随机推荐
- SSH框架学习------struts2前后台传值(二)
struts2的Action类一般都会继承(extends)ActionSupport类(Action类,即实现action的类)1.前传后:jsp里<input type="text ...
- Diango之通过form表单向服务端发送数据
通过form表单向服务端发送数据 表单元素 表单:form></form>表单用于向服务器传输数据.另外一种向服务端传输数据的方式为ajax. form属性: action:提交表单 ...
- 现代C++之理解模板类型推断(template type deduction)
理解模板类型推断(template type deduction) 我们往往不能理解一个复杂的系统是如何运作的,但是却知道这个系统能够做什么.C++的模板类型推断便是如此,把参数传递到模板函数往往能让 ...
- Springboot集成ES启动报错
报错内容 None of the configured nodes are available elasticsearch.yml配置 cluster.name: fans node.name: no ...
- 项目部署相关命令(pm2)
普通方式启动后台服务: nohup npm start & 关闭服务,需要找到进程号: lsof -i :3000 kill -9 进程号 通过pm2启动项目,可实现关闭自启动: 安装pm2: ...
- Git 基本命令行操作
一.本地仓库操作 1.初始化 git init 2.添加版本控制文件 git add README.md3.本地提交 git commit -m “1st commit”4.配置远程 ...
- Django Simple Captcha插件
正文开始 先看官方描述 1.安装 打开控制台,输入如下: pip install django-simple-captcha 2.把APP添加到Django项目进入自己的Django项目,在setti ...
- RFID的winform程序心得2
RFID的winform程序心得1 webBrowser1.AllowWebBrowserDrop = false;//将 WebBrowser 控件的 AllowWebBrowserDrop 属性设 ...
- javascript 伪数组和转化为标准数组
1: 什么是伪数组 伪数组是一个含有length属性的json对象, 它是按照索引的方式存储数据, 它并不具有数组的一些方法,只能能通过Array.prototype.slice转换为真正的数组,并且 ...
- Eclipse纯净版安装web插件
打开 Help -> Install New Software. 在Install界面板中,点击Add按钮输入:然后在输入http://download.eclipse.org/releases ...