设计原则:
解耦,避免对接口依赖
使用invoke以及动态链接库实现对接口的解耦
BeeHive每个模块都是有生命周期事件的,用来与宿主环境进行必要的交互
事件分为三种类型:
系统事件
通用事件
业务自定义事件
1.1 系统事件
系统事件通常是Application生命周期事件,例如DidBecomeActive、WillEnterBackground等。
系统事件基本工作流如下:
1.2 通用事件
在系统事件的基础之上,扩展了应用的通用事件,例如modSetup、modInit等,可以用于编码实现各插件模块的设置与初始化。
扩展的通用事件如下:
1.3 业务自定义事件
如果觉得系统事件、通用事件不足以满足需要,可以通过继承 BHAppdelegate来扩展自己的事件
2. 模块注册
模块注册的方式有静态注册与动态注册两种。
2.1 静态注册
通过在BeeHive.plist文件中注册符合BHModuleProtocol协议模块类:
2.2 动态注册
2.2 动态注册
@implementation HomeModule
BH_EXPORT_MODULE() // 声明该类为模块入口
@end
在模块入口类实现中 使用BH_EXPORT_MODULE()宏声明该类为模块入口实现类。
2.3 异步加载
如果设置模块导出为BH_EXPORT_MODULE(YES),则会在启动之后第一屏内容展现之前异步执行模块的初始化,可以优化启动时时间消耗
3. 编程开发
BHModuleProtocol为各个模块提供了每个模块可以Hook的函数,用于实现插件逻辑以及代码实现。
3.1 设置环境变量
通过context.env可以判断我们的应用环境状态来决定我们如何配置我们的应用。
-(void)modSetup:(BHContext *)context
{
switch (context.env) {
case BHEnvironmentDev:
//....初始化开发环境
break;
case BHEnvironmentProd:
//....初始化生产环境
default:
break;
}
}
3.2 模块初始化
如果模块有需要启动时初始化的逻辑,可以在modInit里编写,例如模块注册一个外部模块可以访问的Service接口
-(void)modInit:(BHContext *)context
{
//注册模块的接口服务
[[BeeHive shareInstance] registerService:@protocol(UserTrackServiceProtocol) service:[BHUserTrackViewController class]];
}
3.3 处理系统事件
系统的事件会被传递给每个模块,让每个模块自己决定编写业务处理逻辑,比如3D-Touch功能
-(void)modQuickAction:(BHContext *)context
{
[self process:context.shortcutItem handler:context.scompletionHandler];
}
3.4 模间调用
通过处理Event编写各个业务模块可以实现插件化编程,各业务模块之间没有任何依赖,core与module之间通过event交互,实现了插件隔离。但有时候我们需要模块间的相互调用某些功能来协同完成功能。
通常会有三种形式的接口访问形式:
基于接口的实现Service访问方式(Java spring框架实现)
基于函数调用约定实现的Export Method(PHP的extension,ReactNative的扩展机制)
基于跨应用实现的URL Route模式(iPhone App之间的互访)
我们目前实现了第一种方式,后续会逐步实现后两种方式。
基于接口Service访问的优点是可以编译时检查发现接口的变更,从而及时修正接口问题。缺点是需要依赖接口定义的头文件,通过模块增加得越多,维护接口定义的也有一定工作量。
3.4.1 定义接口
以为HomeServiceProtocol
为例。
@protocol HomeServiceProtocol <NSObject, BHServiceProtocol>- (void)registerViewController:(UIViewController *)vc title:(NSString *)title iconName:(NSString *)iconName;
@end
注册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>
3.4.3 调用Service
#import "BHService.h"id< HomeServiceProtocol > homeVc = [[BeeHive shareInstance] createService:@protocol(HomeServiceProtocol)];
3.5 单例与多例
对于有些场景下,我们访问每个声明Service
的对象,希望对象能保留一些状态,那我们需要声明这个Service
对象是一个单例对象。
我们只需要在Service
对象中实现事件函数
声明
-(BOOL) singleton{
return YES;
}
通过createService
获取的对象则为单例对象,如果实现上面函数返回的是NO
,则createService
返回的是多例。
id< HomeServiceProtocol > homeVc = [[BeeHive shareInstance] createService:@protocol(HomeServiceProtocol)];
3.6 上下文环境Context
初始化设置应用的项目信息,并在各模块间共享整个应用程序的信息
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
[BHContext shareInstance].env = BHEnvironmentDev; //定义应用的运行开发环境
[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;
} [self.window makeKeyAndVisible]; } return YES;}