ezbuy iOS APP啟動時間優化
來源: APP研發(上海) 團隊 - 許贇
摘要
(App總啟動時間)T = (main()之前的載入時間)T1 + (main()之後的載入時間)T2
T1 = 系統dylib(動態連結庫)和自身App可執行檔案的載入;
T2 = main方法執行之後到AppDelegate類中的- (BOOL)Application:(UIApplication *)Application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions方法執行結束前這段時間,主要是構建第一個介面,並完成渲染展示。
注: 以下測試時間如無特殊說明,均在
macOS Mojave10.14.3
,Xcode10.2.1
,iPhone6 plus
,iOS12.3.1
,ezbuy-UAT
的環境下!!!
一. T1(main函式之前的載入時間)
T1可以通過在EditScheme中新增 DYLD_PRINT_STATISTICS
這個環境變數來檢視.
Bulid Configration
改成Release
,並且連線真機而不是模擬器來檢視.
ezbuy-UAT pre-main時間圖:
pre-main階段如何優化
在preMain階段因為涉及到底層,目前能做的工作不多.最多是刪除一些Pod中不再用到的庫. 如果後續有人對這部分的優化比較感興趣可以移步
二. (main()之後的載入時間)T2
這段時間的衡量在專案中列印即可,因為swift把main函式和appDelegate合併成了一個檔案,所以專案中找不到main函式的入口,但我們可以自己建立一個:
1 建立一個名為main.swift的檔案,在檔案中寫入以下程式碼(swift5):
import Foundation
import UIKit
var START_TIME:CFAbsoluteTime = CFAbsoluteTimeGetCurrent()
UIApplicationMain(CommandLine.argc,CommandLine.unsafeArgv,nil,NSStringFromClass(AppDelegate.self))
複製程式碼
2 到APPDelegate檔案中,註釋掉 @UIApplicationMain
3 在 didFinishLaunchingWithOptions
方法 return true
前面加上以下程式碼
func application(_ application: UIApplication,didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
/*...*/
NSLog("*** App Launched in: %f sec",CFAbsoluteTimeGetCurrent() - START_TIME)
return true
}
複製程式碼
目前執行專案得到的結果是
main()階段如何優化
這一階段的優化主要是減少 didFinishLaunchingWithOptions
方法裡的工作,在 didFinishLaunchingWithOptions
方法裡,我們會建立應用的window
,指定其rootViewController
,呼叫window
的makeKeyAndVisible
方法讓其可見。由於業務需要,我們會初始化各個二方/三方庫,設定系統UI風格,檢查是否需要顯示引導頁、是否需要登入、是否有新版本等,由於歷史原因,這裡的程式碼容易變得比較龐大,啟動耗時難以控制。
所以,滿足業務需要的前提下,didFinishLaunchingWithOptions
在主執行緒裡做的事情越少越好。在這一步,我們可以做的優化有:
- 梳理各個二方/三方庫,找到可以延遲載入的庫,做延遲載入處理,比如放到首頁控制器的
viewDidAppear
方法裡。 - 梳理業務邏輯,把可以延遲執行的邏輯,做延遲執行處理。比如檢查新版本、註冊推送通知等邏輯。
- 避免複雜/多餘的計算。
- 避免在首頁控制器的
viewDidLoad
和viewWillAppear
做太多事情,這2個方法執行完,首頁控制器才能顯示,部分可以延遲建立的檢視應做延遲建立/懶載入處理。 - 採用效能更好的API。
- 首頁控制器用純程式碼方式來構建。
三. ezbuyApp啟動時間優化做的工作
1) pre-main()階段
從podfile
中刪掉MenuItemKit,因為MenuItemKit時間本身載入就只有30ms左右(見上面pre-main時間圖),已經預料到時間應該並無顯著差異
優化前pre-main十次平均時間 1.29s
,優化後 1.33s
2) main()方法之後
1 把didFinishLaunchingWithOptions
中能放到非同步執行緒執行的程式碼都放到非同步執行緒中.
2 把app啟動動畫時間從0.5s縮短到0.2s
- main函式執行時到
didFinishLaunchingWithOptions
結束,執行10次的平均時間: 優化前3.56
,優化後1.08
- main函式執行時到ShopHomeDefaultViewController
viewDidAppear
方法結束時,執行10次的平均時間: 優化前4.85
,優化後2.07
補充: 下午因為刪掉MenuItemKit重新運行了十次,優化後的平均資料分別為 和
2.36`,可能是手機本身由於下午資源佔用比較多,所以時間較上午長
參考文章: iOS App Launch time analysis and optimizations Slow App Startup Times 今日頭條iOS客戶端啟動速度優化 阿里資料iOS端啟動速度優化的一些經驗 Get your app launch time with Swift How to subclass UIApplication using UIApplicationMain