由本章節開始,咱們將從支付寶客戶端的架構設計方案入手,細分拆解客戶端在「容器化框架設計」、「網絡優化」、「性能啓動優化」、「自動化日誌收集」、「RPC 組件設計」、「移動應用監控、診斷、定位」等具體實現,帶領你們進一步瞭解支付寶在客戶端架構上的迭代與優化歷程。數組
本節將介紹支付寶 iOS 容器化框架設計的基本思路。bash
在 mPaaS 開篇介紹中已經和你們分享過《模塊化與解耦式開發在螞蟻金服 mPaaS 中的實踐》:經過容器化開發框架將業務隔離成相對獨立的模塊,並着力追求模塊與模塊之間高內聚、低耦合,所以咱們實現了靈活的插件式開發,並得以將業務劃分爲上千個獨立工程。網絡
mPaaS iOS 框架源自於支付寶客戶端,爲了實現這種上千個工程之間的低耦合和相關依賴調用,mPaaS 框架直接接管了 App 的生命週期,負責整個 App 啓動託管、App 生命週期管理、處理與分發 UIApplication
的代理事件。 mPaaS 框架提供了容器化環境,業務開發人員在這個容器化環境中使用 微應用
和 服務
進行具體的業務需求開發。架構
微應用
和 服務
是 mPaaS 框架內定義的概念,主要是用來進行業務模塊間的劃分。按照是否有 UI 界面做爲標準,mPaaS 框架將不一樣的業務模塊劃分爲 微應用
和 服務
。微應用
是 APP 運行期間帶有用戶界面的業務模塊;服務
是 App 運行期由業務提供的輕量級抽象服務。在 mPaaS 框架中,經過 框架上下文Context
進行 微應用
與 服務
的生命週期管理。app
經過修改 main.m 函數的實現,mPaaS 框架使用本身的 ClientDelegate
類接管了 UIApplicationDelegate
中各類 App 生命週期。mPaaS 框架接入以後,ClientDelegate
徹底替代了通常工程中的 AppDelegate
的角色,從而實現了整個應用的生命週期都是由框架進行管理。框架
int main(int argc, char * argv[]) {
@autoreleasepool {
// Now use mPaaS framework
return UIApplicationMain(argc, argv, @"Application", @"ClientDelegate");
}
}
複製代碼
爲了方便用戶獲取 App 生命週期來開發自定義功能,mPaaS 框架提供了 DTFrameworkInterface
類裏面實現了 UIApplicationDelegate
中全部代理方法的等價接入方式,只須要在 DTFrameworkInterface
的 Category 中覆蓋對應的方法便可。模塊化
例以下面常見的 UIApplicationDelegate
代理方法:函數
@protocol UIApplicationDelegate<NSObject>
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions;
- (void)applicationDidBecomeActive:(UIApplication *)application;
- (void)applicationWillResignActive:(UIApplication *)application;
- (BOOL)application:(UIApplication *)application
openURL:(NSURL *)url
sourceApplication:(NSString *)sourceApplication
annotation:(id)annotation;
@end
複製代碼
在 DTFrameworkInterface
中都提供了對應的方法:post
typedef NS_ENUM(NSInteger, DTFrameworkCallbackResult)
{
DTFrameworkCallbackResultContinue = 0, // 繼續執行
DTFrameworkCallbackResultReturn = 1, // 中斷執行
DTFrameworkCallbackResultReturnYES = 2, // 中斷以後的邏輯,並返回 YES
DTFrameworkCallbackResultReturnNO = 3, // 中斷以後的邏輯,並返回 NO
};
@interface DTFrameworkInterface : NSObject
#pragma mark - 應用配置,微應用配置、服務配置、Scheme 處理器配置,可用 Category 覆蓋
- (void)application:(UIApplication *)application beforeDidFinishLaunchingWithOptions:(NSDictionary *)launchOptions;
- (DTFrameworkCallbackResult)application:(UIApplication *)application handleDidFinishLaunchingWithOptions:(NSDictionary *)launchOptions;
- (void)application:(UIApplication *)application afterDidFinishLaunchingWithOptions:(NSDictionary *)launchOptions;
- (DTFrameworkCallbackResult)applicationDidBecomeActive:(UIApplication *)application;
- (DTFrameworkCallbackResult)applicationWillResignActive:(UIApplication *)application;
- (DTFrameworkCallbackResult)application:(UIApplication *)application
openURL:(NSURL *)url
newURL:(NSURL **)newURL
sourceApplication:(NSString *)sourceApplication
annotation:(id)annotation;
@end
複製代碼
因爲 mPaaS 框架有一些本身的初始化邏輯須要實現,在 DTFrameworkInterface
中額外提供了 beforeDidFinishLaunchingWithOptions
和 afterDidFinishLaunchingWithOptions
方法,方便用戶在 App 啓動時肯定的時間執行本身的初始化代碼。性能
DTFrameworkInterface
在 afterDidFinishLaunchingWithOptions
以前會啓動 BootLoader
,執行 mPaaS 框架的初始化邏輯。在嵌入式操做系統中,BootLoader
的做用是初始化硬件設備,以便爲最終調用操做系統內核準備好正確的環境。相似的在 mPaaS 框架中,BootLoader
用來初始化整個 mPaaS 框架環境,默認實現爲依次執行下面的流程:
這樣就完成了 mPaaS 框架的初始化和首頁的顯示。
後面將詳細介紹其中關鍵的3個概念:微應用
、服務
、框架上下文 Context
。
微應用就是帶 UI 界面的獨立業務模塊,其中最特殊的一個微應用是 Launcher
微應用,Launcher
做爲 App 啓動以後第一個打開的微應用,通常用來建立 App 首頁。在 mPaaS 框架中,各個微應用之間是高度獨立、不相互依賴的。
微應用
經過 plist
文件配置來進行註冊。配置微應用時須要指定 delegate
對應的類名、微應用的描述 description
以及打開微應用時使用的 name
。這樣 框架上下文 Context
經過微應用的 name
就能夠打開指定的微應用。
爲了方便業務開發,每一個 微應用
也存在生命週期。微應用的生命週期,是模仿 iOS App 的生命週期來作的。每一個微應用須要實現本身的 DTMicroApplicationDelegate
代理,這個相似於 iOS App 中實現的 Appdelege
類。
對於具體業務開發而言 微應用
的開發和一個完整的 App 同樣,每一個 微應用
負責控制本身應用內的頁面堆棧,並根據 微應用
的生命週期執行相應的操做。在 mPaaS 框架中,全部的 微應用
都是運行在 mPaaS 框架提供的容器中,其不須要關注 App 的生命週期。對於一些特殊的業務場景,mPaaS 支持建立微應用的多個實例。
服務
與 微應用
不一樣地方在於其沒有 UI 界面,是在後臺執行。一旦服務啓動後,其在整個客戶端的生命週期中一直存在,所以服務通常用於給微應用提供通用服務,好比執行某個功能或者獲取數據等。
一個常見的服務是用戶登錄狀態服務,每一個微應用能夠經過這個服務來獲取到用戶的登陸狀態和用戶信息。
服務
也是經過 plist
文件配置來進行註冊。服務註冊時須要提供服務的惟一標識 name
和對應的實現類 class
類名。框架在建立 服務
時會利用 Objective-C
語言的運行時機制建立 服務
實現類的實例。lazyLoading
用來控制是否延遲加載該類。若是是延遲加載,在框架啓動時該 服務
並不會實例化,只有在用到該 服務
時纔會實例化並啓動。若是是非延遲加載,則在框架啓動時會啓動該服務。
因爲服務的特殊性,在 mPaaS 中同時提供了 ServicesMap
來批量註冊類,ServicesMap
中的 [AUTOSTART]
用來講明哪些組的服務
須要在 App 啓動的時候最早啓動。
這種分級啓動服務的特色能夠有效控制 App 的啓動時間,提供很好的用戶體驗。
每一個服務都須要實現 服務
接口:
@required
/**
* 啓動一個服務。
* 注意:
* 框架在完成初始化操做後,會調用該方法。
* 若是一個服務要啓動一個應用,必須在該方法被調用以後,才能啓動其它的應用。
*/
- (void)start;
@optional
/**
* 建立服務完成。
*/
- (void)didCreate;
/**
* 服務將要銷燬。
*/
- (void)willDestroy;
複製代碼
在增長了 服務
以後,整個 App 的結構以下圖所示。後臺的服務成爲各個 微應用
之間溝通的橋樑。
經過前面的介紹,你們已經對 微應用
和 服務
有了深刻的瞭解。在 mPaaS 框架中,框架上下文Context
承擔了一個調度員的角色,負責各個 微應用
和 服務
的調度、通訊管理,這樣就實現了每一個 微應用
的打開、頁面推棧以及關閉不會影響 App 其餘 微應用
模塊。
經過 mPaaS 框架提供的 DTContext * DTContextGet()
函數能夠獲取到框架上下文Context
對象。一個簡化的 Context
類實現以下:
@interface Context : NSObject
@property(nonatomic, strong) UIWindow *window;
@property(nonatomic, strong) UINavigationController *navigationController;
// 根據指定的名稱啓動一個微應用
- (BOOL)startApplication:(NSString *)name params:(NSDictionary *)params animated:(BOOL)animated;
// 逆向遍歷微應用棧,返回最新的微應用對象。
- (DTMicroApplication *)findApplicationByName:(NSString *)name;
// 根據指定的名稱查到一個服務
- (id)findServiceByName:(NSString *)name;
// 註冊一個服務
- (BOOL)registerService:(id)service forName:(NSString *)name;
// 反註冊一個已存在的服務
- (void)unregisterServiceForName:(NSString *)name;
@end
複製代碼
對於業務開發人員,能夠經過 框架上下文 Context
獲取到主 window、啓動指定的 微應用
、獲取一個 服務
、動態註冊與反註冊 服務
,從而實現業務之間的鏈接。
經過本節內容,咱們初步瞭解了 mPaaS 在 iOS 端容器化框架的設計思路,經過 微應用
和 服務
的方式完成業務模塊之間的解耦和調用。框架上下文 Context
做爲一個迷你的容器操做系統,爲 微應用
和 服務
的運行提供了所需的容器化環境,保證了獨立的業務開發流程和流暢的用戶體驗。
歡迎你們體驗 mPaaS 容器化開發框架,期待你們的反饋與交流。
往期閱讀
《開篇 | 模塊化與解耦式開發在螞蟻金服 mPaaS 深度實踐探討》