iOS 电量消耗改善:一招套路及相关姿势

640?wx_fmt=gif

640?wx_fmt=png

程序君个人微信 和我聊聊编程和创业的事 加好友


作者丨邓轻舟

https://juejin.im/post/5bfce9305188255362443ac5


640?wx_fmt=jpeg


640?wx_fmt=gif解决电量问题的工作流:


先使用 Xcode Energy Gauge 分析出哪一块耗电(网络和 motion , 还是定位 ... ), 用 Time Profiler 定位问题与解决 ( Instruments 模版 ), 得到用户好的反馈。


640?wx_fmt=gif三个原则:


  • Do it never/do it less (能不做,就不做。少做的,好)

    比如: 网络请求,先压缩数据

  • Do it at a better time (合适的时机处理 )

    网络请求,使用缓存机制,设置内容验证( 需要的数据是否更新了 ),或者缓存的失效时间

  • Do it efficiently ( 有效处理 )

    合并网络请求。一次请求大量数据,比多次请求少量数据省电

    (类比 CPU,线程开多了不好。开线程,就会有消耗)


套路很简单,将手机放在桌子上,Xcode 里面启动 app, 并检测,啥也不干。如果电量消耗较高,很不合适了


WWDC 推荐使用 Xcode Debug 栏的 Energy Debug Gauge。


(调性能,都是用真机。机器老一点,效果更好)


Energy Debug Gauge 形象、直观


640?wx_fmt=jpeg



可看出,当前手机的耗电情况,耗电低、高、很高。苹果的三个阶段,有些不太细致。(左上的 Utilization, Current Impact)


app 的平均能耗,一目了然 ( 右上的 Average ) 。


每一个时刻,耗电的是什么。 CPU 、网络、文件 I/O 、定位,哪些消耗了。( 中间的 Energy Impact )


Xcode Energy Gauge 可以快速定位问题,想要进一步的细致分析,下面有各种选项,跳转到对应的 Instrumens 模版。


比如:


分析 CPU 使用的 time profile, (能够知道代码的执行情况了,根据函数的调用消耗。找出权重大的,干掉不必要的。)


分析网络活动的 network profile, 分析定位活动的 location profile


640?wx_fmt=jpeg


本文示例代码: 解决的两个问题,给 CoreMotion 更新设置过滤,干掉频繁的日志上传


640?wx_fmt=jpeg


这里电量消耗很高,很稳定


主要是 CPU 和网络请求在耗电。


使用 Instruments 的 Time Profiler 分析,


640?wx_fmt=png


可以先放大上面的 time line,再选择一个时间段,在调用树 call tree 中,进一步分析。


Time Profiler 的选项默认是按线程划分的,再选一个隐藏系统调用函数。


(系统执行的函数,可以参考一下,到底发生了什么。系统的改不了。可以改自己的源代码 )


640?wx_fmt=jpeg


在调用树的表格中,按权重展开 ( weight ),要干掉的就是权重大的,耗时间的。


接着展开主线程 ( main thread 。看上图,其他线程的耗时,相比主线程的,可忽略 ), 按住 Option 键,点击 main thread 左边的小三角,可以一下子展开很多。


可清晰看出,耗时严重的是 450 毫秒左右的那一行 thunk for ... CMDeviceMotion? ...


里面调用了一个耗时的方法,CatPhotoTableViewCell.panImage , 上图, 454 毫秒中,占 419 毫秒。


640?wx_fmt=jpeg


点击进入详情,就看到代码了。


在 CatFeedViewController 的 viewDidLoad 方法中,有一个倾斜的设置


motionManager.startDeviceMotionUpdates(to: .main, withHandler:{ deviceMotion, error in
            guard let deviceMotion = deviceMotion else { return }
            let xRotationRate = CGFloat(deviceMotion.rotationRate.x)
            let yRotationRate = CGFloat(deviceMotion.rotationRate.y)
            let zRotationRate = CGFloat(deviceMotion.rotationRate.z)
            //  y > z, 这个动作是翘起来
            //  y > x + z, 这个动作是斜着翘起来
              if abs(yRotationRate) > (abs(xRotationRate) + abs(zRotationRate)) {
                for cell in self.tableView.visibleCells as! [CatPhotoTableViewCell] {
                    cell.panImage(with: yRotationRate)
                }
              }
  })


现在的代码显示栏 ( 原来的 Call Tree 表格 ), 右上角有一个 Xcode 的小图标,点击返回 Xcode 调试代码。


手机没动,老是调用 cell.panImage(with: yRotationRate), 根本就没效果。


设置一下,调用 cell.panImage 的时候,要超过最小的手机幅度。幅度小,根本就没效果。 添加一个属性记录 lastY 来设置,过滤掉手机小的抖动。


private var lastY = 0.0
override func viewDidLoad() {
        super.viewDidLoad()
        ......
        motionManager.startDeviceMotionUpdates(to: .main, withHandler:{ deviceMotion, error in
            guard let deviceMotion = deviceMotion else { return }

            // 添加了这两行
           guard abs(self.lastY - deviceMotion.rotationRate.y) > 0.1 else return }
            self.lastY = deviceMotion.rotationRate.y

            let xRotationRate = CGFloat(deviceMotion.rotationRate.x)
            let yRotationRate = CGFloat(deviceMotion.rotationRate.y)
            let zRotationRate = CGFloat(deviceMotion.rotationRate.z)
              if abs(yRotationRate) > (abs(xRotationRate) + abs(zRotationRate)) {
                for cell in self.tableView.visibleCells as! [CatPhotoTableViewCell] {
                    cell.panImage(with: yRotationRate)
                }
              }
        })
    }


还有一个使用 Timer 定时发送日志的问题,CPU 根本没有空闲的时间,开销很大。


具体见文末的 Demo Code.


最后这样


640?wx_fmt=jpeg


会慢慢降下去,至于电量低消耗。 需要大约两分钟时间,一屏幕放不下。


Instruments 的 Energy Log 有问题,连着 Xcode 实时调试的部分 gg 了


Instruments 的 Energy Log 模版用途不大


因为不能手机在线调试。Energy 是空的, 或者提示 No Data,


这是苹果的一个长期的 bug .参见

https://forums.developer.apple.com/thread/70540


Energy Log 模版的模块挺丰富的,可以看屏幕亮度、定位、蓝牙、GPU 和网络等等的功耗情况,其中网络又包括 WiFi 和蜂窝网络。


想着一边给手机充电,一边调试电量损失,不靠谱。


试了下,无线用 Instruments 的 Energy Log 模版调试,结果一样。


无线连接 Xcode 调试耗电,也没有数据。


640?wx_fmt=gif无线用 Instruments 调试,首先要设置 Xcode 无线 Debug 


无线 debug 功能,隐藏在 Xcode 的 Window > Devices and Simulators 中。


640?wx_fmt=jpeg


实际上是,使用共享的无线网络,取代了数据线的连接,与 Xcode 建立连接。


会有一个网络的 Icon . 上面还有提示语 ( connected , 连上了 )


如下图:


640?wx_fmt=jpeg


然后就可以设置 Instruments 无线设备调试了,


更多参见苹果文档

https://developer.apple.com/library/archive/documentation/Performance/Conceptual/EnergyGuide-iOS/MonitorEnergyWithInstruments.html


instruments 的 Energy 模版,将电量消耗的程度划分为 20 个级别。 0 代表不耗电,自然 app 没做什么 20 代表耗电严重


WWDC 中说,要看到,就导入离线的 log。(几个月以前,还能用)


在手机的设置中,开发者选项中的 Logging, 选中 Energy, 点击开始录制:


640?wx_fmt=jpeg


之后,使用你的 app 一段时间,(可以重点测耗电功能) 开发者选项中的 Logging, 点击完成录制, 导入电量消耗 log 数据,到 Instruments 的 Energy Log 模版.


640?wx_fmt=jpeg


推测老版本的不行( 11.4 ), 没数据。操作的时候,手机的设置 app ,还老是闪退。


手机升级到最新版(12.1 , 20181127),试了多次,也不行, 猜测目前是彻底挂了


(本文中,重启过手机,升级过手机。没试过重启电脑)


640?wx_fmt=gif湿一点,好消化


耗电是不好的。


写入硬盘与网络请求,都是高耗电操作。


网络请求特别耗电,每一个网络请求,手机设备需要使用他的蜂窝网络天线,发送无线电波。


网络的质量与类型,对于耗电的影响也很大。 使用 Wi-Fi 比 3G , 4G 要省电得多。 使用 4G 比 3G 要省电,因为 4G 的信号更强。


640?wx_fmt=gif计时器,能不用就不用。( NSTimer )


一般情况下,app 都用 Timer 做了很多无用功。


比如, 一个列表屏幕, 上方 banner 计时器,往下滑到看不见 banner ,就可以暂停计时器。上滑,看得见 banner 了,又可以恢复 resume。


同样的,进入子界面,可以选择暂停 Timer,或者释放,...


例子: 定时做重复的大量工作不好,可能每当系统休眠(系统要降低能级了),系统又被唤醒了,开始功耗。


640?wx_fmt=gif定位


与网络请求类似,手机设备定位通过 GPS 天线发送信号,也挺耗电的。


如果 app 经常去获取手机设备的精确定位,定位精度越高,能耗越严重。 建议使用策略,手机的负担会小很多。


( ?,Deferred location updates, 位置更新延迟(直到移动了 x 米或者时间超过了 xx 秒 )、


significant location change, 定位变化比较大的时候,唤醒、


region monitoring, 监测用户进入或离开特定地理区域)


Motion 物理引擎,动态效果更新状态,挺耗电的。


使用罗盘、陀螺仪、加速计,都消耗不小。


相关代码

https://github.com/BoxDengJZ/Instruments_Wen


 推荐↓↓↓ 

640?wx_fmt=png

?16个技术公众号】都在这里!

涵盖:程序员大咖、源码共读、程序员共读、数据结构与算法、黑客技术和网络安全、大数据科技、编程前端、Java、Python、Web编程开发、Android、iOS开发、Linux、数据库研发、幽默程序员等。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值