解決電量問題的工作流:
先使用 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 形象、直觀
可看出,當前手機的耗電情況,耗電低、高、很高。蘋果的三個階段,有些不太細緻。(左上的 Utilization, Current Impact)
app 的平均能耗,一目瞭然 ( 右上的 Average ) 。
每一個時刻,耗電的是什麼。 CPU 、網路、檔案 I/O 、定位,哪些消耗了。( 中間的 Energy Impact )
Xcode Energy Gauge 可以快速定位問題,想要進一步的細緻分析,下面有各種選項,跳轉到對應的 Instrumens 模版。
比如:
分析 CPU 使用的 time profile, (能夠知道程式碼的執行情況了,根據函式的呼叫消耗。找出權重大的,幹掉不必要的。)
分析網路活動的 network profile, 分析定位活動的 location profile
本文示例程式碼: 解決的兩個問題,給 CoreMotion 更新設定過濾,幹掉頻繁的日誌上傳
這裡電量消耗很高,很穩定
主要是 CPU 和網路請求在耗電。
使用 Instruments 的 Time Profiler 分析,
可以先放大上面的 time line,再選擇一個時間段,在呼叫樹 call tree 中,進一步分析。
Time Profiler 的選項預設是按執行緒劃分的,再選一個隱藏系統呼叫函式。
(系統執行的函式,可以參考一下,到底發生了什麼。系統的改不了。可以改自己的原始碼 )
在呼叫樹的表格中,按權重展開 ( weight ),要幹掉的就是權重大的,耗時間的。
接著展開主執行緒 ( main thread 。看上圖,其他執行緒的耗時,相比主執行緒的,可忽略 ), 按住 Option 鍵,點選 main thread 左邊的小三角,可以一下子展開很多。
可清晰看出,耗時嚴重的是 450 毫秒左右的那一行 thunk for ... CMDeviceMotion? ...
裡面呼叫了一個耗時的方法,CatPhotoTableViewCell.panImage
, 上圖, 454 毫秒中,佔 419 毫秒。
點選進入詳情,就看到程式碼了。
在 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.
最後這樣
會慢慢降下去,至於電量低消耗。 需要大約兩分鐘時間,一螢幕放不下。
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 中。
實際上是,使用共享的無線網路,取代了資料線的連線,與 Xcode 建立連線。
會有一個網路的 Icon . 上面還有提示語 ( connected , 連上了 )
如下圖:
更多參見部落格 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
本文 Demo 使用的是 500 px 的 API .
後來發現, 有人都寫過了,
好尷尬
想了一下,可以寫他沒交代的。蘋果更新太快,人是物非