轉載本文需註明出處:微信公衆號EAWorld,違者必究。前端
前言:react
一般來說iOS 應用啓動過程有兩種:一是冷啓動(後臺沒有運行的普通啓動過程)、二是熱啓動(後臺運行沒有被系統kill掉,從新打開能當即恢復到以前打開的狀態)。本文着重講普元Mobile8.0 冷啓動過程。程序員
目錄:web
1.集成跨平臺框架React Nativejson
2.React Native交互原理瀏覽器
3.組件的集成緩存
4.模塊化安全
1.集成跨平臺框架React Native微信
應用冷啓動後,先執行main函數,main內部會調用UIApplicationMain函數,此函數主要是建立了UIApplication對象和建立UIApplication的delegate對象AppDelegate。而應用啓動必要執行的代碼主要在此AppDelegate類的didFinishLaunchingWithOptions中調用,普通應用在此係統接口中只用初始化窗口、視圖控制器添加view,makeWindowVisible就能夠了,甚至利用StoryBoard開發頁面的這部分代碼也省去了。網絡
不過普元Mobile8.0平臺是支持多平臺的,一套前端代碼運行在iOS和安卓兩種系統的應用上,這就意味着咱們接入了跨平臺的明星框架React Native,如他們官方本身介紹的同樣他們最大的優勢‘learn once , write anywhere’。
不一樣於其餘熱門跨平臺框架 (Cordova、AppCan、Phonegap等),這些框架都是在iOS組件webview上進行渲染,或者說wkwebview(iOS 9以後),性能侷限於webview的性能,緩存過大時很容易卡頓,就像瀏覽器那樣。而RN就是利用JS控制iOS原生組件(JS橋接加Native橋接)渲染屏幕,和原生應用同樣具備先天優點。
既然接入了RN框架8.0的didFinishLaunchingWithOptions中主要涉及到下面三部分模塊。
-
安全通道
-
RN初始化
-
組件和工具類註冊,安裝
官方RN Demo應用的歡迎頁面:
2.React Native交互原理
1、安全通道經過處理調試或非調試模式下配置的server信息,獲取安全通道數據握手成功後進行本地存儲,便於RN接口調用進行調試。
2、初始化RN入口導航控制器(關於RN部分代碼普元Mobile8.0將其從主項目分離出主項目,與主項目進行模塊化組合,便於開發的靈活性同時下降代碼耦合度)。
navgationController = [[RNRoot shareInstance] registRnRootWithLaunchOptions:launchOptions jsCodeLocation:nil];
(左右滑動查看所有代碼)
RNRoot是組件化封裝的一個類,專門處理RN初始化的一些代碼。(須要注意的是React Native 與 Hybrid 徹底沒有關係,它只不過是以 JavaScript 的形式告訴 Objective-C 該執行什麼代碼)
-
上面提供了jsCodeLocation接口便於提供JSbudle調試地址
-
主bundle、微應用包拷貝、微應用包解壓
-
調試模式啓動熱部署服務
-
初始化RCTBridge、RCTRootView (RCTRootView將React Natvie視圖封裝到原生組件中。用戶能看到的一切內容都來源於這個RootView,全部的初始化工做也都在這個方法內完成)
- (instancetype)initWithBundleURL:(NSURL *)bundleURL moduleName:(NSString *)moduleName initialProperties:(NSDictionary *)initialProperties launchOptions:(NSDictionary *)launchOptions
(左右滑動查看全部代碼)
此接口內部會建立一個RCTBridge實例,這個實例就是實現OC與JS溝通的橋樑,具體實現要在RCTBatchedBridge 類中的 start方法內, start中執行了重要的初始化任務,基於大量的GCD實現了異步初始化組件框架的任務。
同時start方法裏開闢了一個基於JSThread線程而且開啓了線程的runloop(一直存在,不被內存回收),這個線程就是提供給JS調用OC用的。
接着initModulesWithDispatchGroup遍歷module除了內部module,另一部分普元Mobile8.0本身建立的不少接口類以及類中提供的很是豐富的API可供調用。
利用react提供的宏定義RCT_EXPORT_MODULE註冊:
RCT_EXPORT_MODULE(SecurityBridgeModule)。
宏定義中重寫了當前class的+load方法,因此module類被加載的時候RCTRegisterModule就調用被註冊到配置表。
這也是若是前端使用沒有被註冊的module類名會爆、報紅的緣由即配置表裏找不到這個類。JS也有本身的bridge,兩個bridge用的配置表是同樣的。不管是哪一方調用另外一方的方法,實際上傳遞的數據只有 ModuleId、MethodId 和 Arguments ,分別對應的是類名、方法名、參數。
利用runtime就可使用傳遞的三個參數完成接口的調用過程;OC調JS某些模塊的方法時,也是經過傳遞ModuleID和MethodID去調用的,都會走到-enqueueJSCall:args:方法把兩個ID和參數傳給JS的BatchedBridge.callFunctionReturnFlushedQueue,跟JS調OC原理差很少。
感興趣的話能夠研究下面的流程:
3.組件的集成
普元Mobile8.0 提供了一個組件集成的助手類PluginHelper,利用pod 'PluginHelper',:podspec =>」倉庫最新地址」便可集成。此類主要做用是在應用啓動時調用([PluginHelper didFinishLaunchingWithOptions:launchOptions];),會遍歷components.json中須要集成的組件類,並向這些組件類發消息完成初始化。目前提供的協議接口除了初始化組件的方法還有推送和支付相關方法。
組件類須要遵照協議實現協議方法,遍歷拿到類名後利用runtime向此類發消息和對應的協議function名。
利用PluginHelper能夠解除每引用一個新組件時要import對應類的頭文件步驟。只須要在應用啓動方法didFinishLaunchingWithOptions手動調用初始化方法。下降了主結構代碼冗餘度避免了代碼耦合,使組件代碼更獨立有利於整個項目的組件模塊化進程。
以普元Mobile8.0平臺推送組件舉例,集成組件後,只需在如下幾個方法調用PluginHelper便可。全部的消息處理代碼都在推送組件裏,加強了主項目代碼的可讀性。不用考慮複雜的iOS推送接收穫取過程。不只如此,推送組件還提供了獲取推送消息,獲取設備Token註冊Token,設備綁定等等相關的RN接口很是方便調用。
普通處理方法要考慮冗餘的推送邏輯和接口:
4.模塊化
程序員都知道的最基本的代碼設計原則:「Don’t repeat yourself!」。架構的重要體現就是可以更好的共享資源同時避免代碼和功能的複用,而架構偏偏就是圍繞模塊化作的。
組件模塊關係:
普元Mobile8.0平臺實現了組件模塊化開發,這些組件業務的代碼進行隔離(分裝)成獨立的模塊,能夠獨立運行。上面講到的RN相關部分初始化,熱部署,拷貝微應用獨立成了一個模塊而且上傳到了8.0的遠程倉庫,主項目能夠用pod集成的方式引用此模塊。
另外圖片、xib文件或者可能之後會增長的db是以bundle模塊的方式集成。其餘的模塊還有加解密、網絡數據安全請求、應用商店相關等等。而且普元Mobile8.0開發過程當中不斷提升了模塊穩定性,下降模塊間的依賴,使之更好的拆分組裝以便更好的維護。
關於做者:熱河,普元移動端開發工程師,互聯網技術愛好者,專一於iOS開發。目前參與Mobile 8.0項目的開發,主要接觸RN技術的應用,黏合前端代碼與iOS底層之間的交互。
關於EAWorld:微服務,DevOps,數據治理,移動架構原創技術分享。長按二維碼關注!