github下載地址:
https://github.com/alibaba/BeeHive
BeeHive 詳細介紹
BeeHive是用于iOS的app模塊化編程的框架實現(xiàn)方案,吸收了Spring框架service的理念來實現(xiàn)模塊間的API耦合厘熟〈卧保基本原理如下:
實現(xiàn)以下特性
- 插件化的模塊開發(fā)運行框架
- 模塊具體實現(xiàn)與接口調(diào)用分離
- 模塊生命周期管理,擴展了應用的系統(tǒng)事件
因為基于Spring的Service理念秧秉,雖然可以使模塊間的具體實現(xiàn)與接口解耦污桦,但無法避免對接口類的依賴關系空盼。
為什么不使用invoke以及動態(tài)鏈接庫技術實現(xiàn)對接口實現(xiàn)的解耦书幕,類似Apache的DSO的方式。
主要是考慮學習成本難度以及動態(tài)調(diào)用實現(xiàn)無法在編譯檢查階段檢測接口參數(shù)變更等問題揽趾,動態(tài)技術需要更高的編程門檻要求
BeeHive靈感來源于蜂窩台汇。蜂窩是世界上高度模塊化的工程結構,六邊形的設計能帶來無限擴張的可能篱瞎。所以我們用了BeeHive來做為這個項目的命名苟呐。
生命周期的變化
事件
BeeHive會給每個模塊提供生命周期事件,用于與BeeHive宿主環(huán)境進行必要信息交互 事件分為三種類型:
- 系統(tǒng)事件
- 通用事件
- 業(yè)務自定義事件
系統(tǒng)事件
系統(tǒng)事件通常是Application生命周期事件俐筋,例如DidBecomeActive牵素、WillEnterBackground等系統(tǒng)事件基本工作流如下:
通用事件
在系統(tǒng)事件的基礎之上,擴展了應用的通用事件澄者,例如modSetup笆呆、modInit等,可以用于編碼實現(xiàn)各插件模塊的設置與初始化
擴展的通用事件如下:
業(yè)務自定義事件
如果覺得系統(tǒng)事件粱挡、通用事件不足以滿足需要赠幕,我們還將事件封裝簡化成BHAppdelgate,你可以通過繼承BHAppdelegate來擴展自己的事件询筏。
注冊
模塊注冊的方式有靜態(tài)注冊與動態(tài)注冊兩種
-
靜態(tài)注冊
通過在BeeHive.plist文件中注冊符合BHModuleProtocol協(xié)議模塊類
靜態(tài)注冊.png - 動態(tài)注冊
@implementation HomeModule
BH_EXPORT_MODULE() //聲明該類為模塊入口
在模塊入口類實現(xiàn)中 使用BH_EXPORT_MODULE()宏聲明該類為模塊入口實現(xiàn)類
異步加載
如果設置模塊導出為BH_EXPORT_MODULE(YES)榕堰,則會在啟動之后第一屏內(nèi)容展現(xiàn)之前異步執(zhí)行模塊的初始化,可以優(yōu)化啟動時時間消耗
編程開發(fā)
BHModuleProtocol為各個模塊提供了每個模塊可以hook的函數(shù)嫌套,用于實現(xiàn)插件邏輯以及代碼實現(xiàn)
- 設置環(huán)境變量
通過context.env可以判斷我們的應用環(huán)境狀態(tài)來決定我們?nèi)绾闻渲梦覀兊膽?/li>
-(void)modSetup:(BHContext *)context
{
switch (context.env) {
case BHEnvironmentDev:
//....初始化開發(fā)環(huán)境
break;
case BHEnvironmentProd:
//....初始化生產(chǎn)環(huán)境
default:
break;
}
}
- 模塊初始化
如果模塊有需要啟動時初始化的邏輯局冰,可以在modInit里編寫,例如模塊注冊一個外部模塊可以訪問的Service接口
-(void)modInit:(BHContext *)context
{
//注冊模塊的接口服務
[[BeeHive shareInstance] registerService:@protocol(UserTrackServiceProtocol) service:[BHUserTrackViewController class]];
}
- 處理系統(tǒng)事件
系統(tǒng)的事件會被傳遞給每個模塊灌危,讓每個模塊自己決定編寫業(yè)務處理邏輯,比如3D-Touch功能
-(void)modQuickAction:(BHContext *)context
{
[self process:context.shortcutItem handler:context.scompletionHandler];
}
模間調(diào)用
通過處理Event編寫各個業(yè)務模塊可以實現(xiàn)插件化編程碳胳,各業(yè)務模塊之間沒有任何依賴勇蝙,core與module之間通過event交互,實現(xiàn)了插件隔離挨约。但有時候我們需要模塊間的相互調(diào)用某些功能來協(xié)同完成功能味混。 通常會有三種形式的接口訪問形式
- 基于接口的實現(xiàn)Service訪問方式(java spring框架實現(xiàn))
- 基于函數(shù)調(diào)用約定實現(xiàn)的Export Method(PHP的extension产雹,ReactNatve的擴展機制)
- 基于跨應用實現(xiàn)的Url route模式(iphone app之間的互訪)
我們目前實現(xiàn)了第一種方式,后續(xù)會逐步實現(xiàn)后兩種方式
Servcie訪問
Service訪問的優(yōu)點是可以編譯時檢查發(fā)現(xiàn)接口的變更翁锡,從而及時修正接口問題蔓挖。缺點是需要依賴接口定義的頭文件,通過模塊增加得越多馆衔,維護接口定義的也有一定工作量瘟判。以為HomeServiceProtocol為例
- 定義HomeServiceProtocol暴露模塊對外訪問的接口
@protocol HomeServiceProtocol <NSObject, BHServiceProtocol>
-(void)registerViewController:(UIViewController *)vc title:(NSString *)title iconName:(NSString *)iconName;
@end
- 注冊Service有三種方式
- 聲明式注冊
@implementation HomeService
BH_EXPORT_SERVICE()
- API注冊
[[BeeHive shareInstance] registerService:@protocol(HomeServiceProtocol) service:[BHViewController class]];
- BHService.plist注冊
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>HomeServiceProtocol</key>
<string>BHViewController</string>
</dict>
</plist>
- 調(diào)用
#import "BHService.h"
id< HomeServiceProtocol > homeVc = [[BeeHive shareInstance] createService:@protocol(HomeServiceProtocol)];
單例與多例
對于有些場景下,我們訪問每個聲明為service的對象角溃,希望對象能保留一些狀態(tài)拷获,那我們需要聲明這個service對象是一個單例對象。
我們只需要在service對象中實現(xiàn)事件函數(shù)
聲明
-(BOOL) singleton
{
return YES;
}
通過createService獲取的對象則為單例對象减细,如果實現(xiàn)上面函數(shù)返回的是NO匆瓜,則createService返回的是多例
id< HomeServiceProtocol > homeVc = [[BeeHive shareInstance] createService:@protocol(HomeServiceProtocol)];
上下文環(huán)境Context
- 初始化設置應用的項目信息,并在各模塊間共享整個應用程序的信息
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
[BHContext shareInstance].env = BHEnvironmentDev; //定義應用的運行開發(fā)環(huán)境
[BHContext shareInstance].application = application;
[BHContext shareInstance].launchOptions = launchOptions;
[BHContext shareInstance].moduleConfigName = @"BeeHive.bundle/CustomModulePlist";//可選未蝌,默認為BeeHive.bundle/BeeHive.plist
[BHContext shareInstance].serviceConfigName = @"BeeHive.bundle/CustomServicePlist";//可選驮吱,默認為BeeHive.bundle/BHService.plist
[[BeeHive shareInstance] setContext:[BHContext shareInstance]];
[super application:application didFinishLaunchingWithOptions:launchOptions];
id<HomeServiceProtocol> homeVc = [[BeeHive shareInstance] createService:@protocol(HomeServiceProtocol)];
if ([homeVc isKindOfClass:[UIViewController class]]) {
UINavigationController *navCtrl = [[UINavigationController alloc] initWithRootViewController:(UIViewController*)homeVc];
self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
self.window.rootViewController = navCtrl;
[self.window makeKeyAndVisible];
}
return YES;
}
更多細節(jié)可以參考Example用例
- 集成方式
use cocoapods
pod "BeeHive", '1.0.0'