iOS 電量消耗改善:一招套路及相關姿勢

鄧輕舟發表於2018-11-27

工作流

解決電量問題的工作流:

先使用 Xcode Energy Gauge 分析出哪一塊耗電(網路和 motion , 還是定位 ... ), 用 Time Profiler 定位問題與解決 ( Instruments 模版 ), 得到使用者好的反饋。

三個原則:
  • 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 形象、直觀

Energy Debug Gauge

可看出,當前手機的耗電情況,耗電低、高、很高。蘋果的三個階段,有些不太細緻。(左上的 Utilization, Current Impact)

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

每一個時刻,耗電的是什麼。 CPU 、網路、檔案 I/O 、定位,哪些消耗了。( 中間的 Energy Impact )


Xcode Energy Gauge 可以快速定位問題,想要進一步的細緻分析,下面有各種選項,跳轉到對應的 Instrumens 模版。

比如:

分析 CPU 使用的 time profile, (能夠知道程式碼的執行情況了,根據函式的呼叫消耗。找出權重大的,幹掉不必要的。)

分析網路活動的 network profile, 分析定位活動的 location profile

跳


本文示例程式碼: 解決的兩個問題,給 CoreMotion 更新設定過濾,幹掉頻繁的日誌上傳

before

這裡電量消耗很高,很穩定

主要是 CPU 和網路請求在耗電。


使用 Instruments 的 Time Profiler 分析,

CPU 分析

可以先放大上面的 time line,再選擇一個時間段,在呼叫樹 call tree 中,進一步分析。

Time Profiler 的選項預設是按執行緒劃分的,再選一個隱藏系統呼叫函式。

(系統執行的函式,可以參考一下,到底發生了什麼。系統的改不了。可以改自己的原始碼 )

option

在呼叫樹的表格中,按權重展開 ( weight ),要幹掉的就是權重大的,耗時間的。

接著展開主執行緒 ( main thread 。看上圖,其他執行緒的耗時,相比主執行緒的,可忽略 ), 按住 Option 鍵,點選 main thread 左邊的小三角,可以一下子展開很多。

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

裡面呼叫了一個耗時的方法,CatPhotoTableViewCell.panImage , 上圖, 454 毫秒中,佔 419 毫秒。

hop

點選進入詳情,就看到程式碼了。

在 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.

最後這樣

after

會慢慢降下去,至於電量低消耗。 需要大約兩分鐘時間,一螢幕放不下。


Instruments 的 Energy Log 有問題,連著 Xcode 實時除錯的部分 gg 了

Instruments 的 Energy Log 模版用途不大

因為不能手機線上除錯。Energy 是空的, 或者提示 No Data,

這是蘋果的一個長期的 bug .(參見 Apple Forum )

Energy Log 模版的模組挺豐富的,可以看螢幕亮度、定位、藍芽、GPU 和網路等等的功耗情況,其中網路又包括 WiFi 和蜂窩網路。


想著一邊給手機充電,一邊除錯電量損失,不靠譜。

試了下,無線用 Instruments 的 Energy Log 模版除錯,結果一樣。

無線連線 Xcode 除錯耗電,也沒有資料。


無線用 Instruments 除錯,首先要設定 Xcode 無線 Debug ,

無線 debug 功能,隱藏在 Xcode 的 Window > Devices and Simulators 中。

Devices_and_Simulators

實際上是,使用共享的無線網路,取代了資料線的連線,與 Xcode 建立連線。

會有一個網路的 Icon . 上面還有提示語 ( connected , 連上了 )

如下圖:

connect

更多參見部落格 How to use Wireless Debugging on Xcode 9

然後就可以設定 Instruments 無線裝置除錯了,

更多參見蘋果文件 Energy Efficiency Guide for iOS Apps


instruments 的 Energy 模版,將電量消耗的程度劃分為 20 個級別。 0 代表不耗電,自然 app 沒做什麼 20 代表耗電嚴重

WWDC 中說,要看到,就匯入離線的 log。(幾個月以前,還能用)

在手機的設定中,開發者選項中的 Logging, 選中 Energy, 點選開始錄製:

開發者

之後,使用你的 app 一段時間,(可以重點測耗電功能) 開發者選項中的 Logging, 點選完成錄製, 匯入電量消耗 log 資料,到 Instruments 的 Energy Log 模版.

匯入

推測老版本的不行( 11.4 ), 沒資料。操作的時候,手機的設定 app ,還老是閃退。

手機升級到最新版(12.1 , 20181127),試了多次,也不行, 猜測目前是徹底掛了

(本文中,重啟過手機,升級過手機。沒試過重啟電腦)


溼一點,好消化

耗電是不好的。

寫入硬碟與網路請求,都是高耗電操作。

網路請求特別耗電,每一個網路請求,手機裝置需要使用他的蜂窩網路天線,傳送無線電波。

網路的質量與型別,對於耗電的影響也很大。 使用 Wi-Fi 比 3G , 4G 要省電得多。 使用 4G 比 3G 要省電,因為 4G 的訊號更強。

計時器,能不用就不用。( NSTimer )

一般情況下,app 都用 Timer 做了很多無用功。

比如, 一個列表螢幕, 上方 banner 計時器,往下滑到看不見 banner ,就可以暫停計時器。上滑,看得見 banner 了,又可以恢復 resume。

同樣的,進入子介面,可以選擇暫停 Timer,或者釋放,...

例子: 定時做重複的大量工作不好,可能每當系統休眠(系統要降低能級了),系統又被喚醒了,開始功耗。

定位

與網路請求類似,手機裝置定位通過 GPS 天線傳送訊號,也挺耗電的。

如果 app 經常去獲取手機裝置的精確定位,定位精度越高,能耗越嚴重。 建議使用策略,手機的負擔會小很多。

( ?,Deferred location updates, 位置更新延遲(直到移動了 x 米或者時間超過了 xx 秒 )、

significant location change, 定位變化比較大的時候,喚醒、

region monitoring, 監測使用者進入或離開特定地理區域)

Motion 物理引擎,動態效果更新狀態,挺耗電的。

使用羅盤、陀螺儀、加速計,都消耗不小。


相關程式碼: github.com/BoxDengJZ/I…

更多資料:

WWDC 2015 Debugging Energy Issues

視訊教程,practical-instruments


本文 Demo 使用的是 500 px 的 API .


後來發現, 有人都寫過了

好尷尬

想了一下,可以寫他沒交代的。蘋果更新太快,人是物非

相關文章