×

BeeHive iOS模块化编程框架

消耗积分:2 | 格式:zip | 大小:0.29 MB | 2022-06-24

分享资料个

授权协议 GPL
开发语言 Objective-C
操作系统 iOS
软件类型 开源软件
所属分类 iOS代码库

软件简介

BeeHive是用于ios的app模块化编程的框架实现方案,吸收了Spring框架service的理念来实现模块间的API耦合。基本原理如下:

pYYBAGKrCX2AD0gvAABTwfS5_OY744.jpg

实现以下特性

  • 插件化的模块开发运行框架

  • 模块具体实现与接口调用分离

  • 模块生命周期管理,扩展了应用的系统事件

因为基于Spring的Service理念,虽然可以使模块间的具体实现与接口解耦,但无法避免对接口类的依赖关系。

为什么不使用invoke以及动态链接库技术实现对接口实现的解耦,类似Apache的DSO的方式。

主要是考虑学习成本难度以及动态调用实现无法在编译检查阶段检测接口参数变更等问题,动态技术需要更高的编程门槛要求

BeeHive灵感来源于蜂窝。蜂窝是世界上高度模块化的工程结构,六边形的设计能带来无限扩张的可能。所以我们用了BeeHive来做为这个项目的命名。

生命周期的变化

事件

BeeHive会给每个模块提供生命周期事件,用于与BeeHive宿主环境进行必要信息交互 事件分为三种类型:

  • 系统事件

  • 通用事件

  • 业务自定义事件

系统事件

系统事件通常是Application生命周期事件,例如DidBecomeActive、WillEnterBackground等 系统事件基本工作流如下:

poYBAGKrCX-AHIaBAACnKX05rbo986.jpg

通用事件

在系统事件的基础之上,扩展了应用的通用事件,例如modSetup、modInit等,可以用于编码实现各插件模块的设置与初始化

扩展的通用事件如下:

pYYBAGKrCYGAcNFoAADSk_QeXLw314.jpg

业务自定义事件

如果觉得系统事件、通用事件不足以满足需要,我们还将事件封装简化成BHAppdelgate,你可以通过继承BHAppdelegate来扩展自己的事件。

注册

模块注册的方式有静态注册与动态注册两种

  • 静态注册

通过在BeeHive.plist文件中注册符合BHModuleProtocol协议模块类

poYBAGKrCYOAF-W2AAA6G49Ausw974.png

  • 动态注册

@implementation HomeModule
BH_EXPORT_MODULE()  //声明该类为模块入口

在模块入口类实现中 使用BH_EXPORT_MODULE()宏声明该类为模块入口实现类

异步加载

如果设置模块导出为BH_EXPORT_MODULE(YES),则会在启动之后第一屏内容展现之前异步执行模块的初始化,可以优化启动时时间消耗

编程开发

BHModuleProtocol为各个模块提供了每个模块可以hook的函数,用于实现插件逻辑以及代码实现

  • 设置环境变量

通过context.env可以判断我们的应用环境状态来决定我们如何配置我们的应用

-(void)modSetup:(BHContext *)context
{
switch (context.env) {
case BHEnvironmentDev:
//....初始化开发环境
break;
case BHEnvironmentProd:
//....初始化生产环境
default:
break;
}
}
  • 模块初始化

如果模块有需要启动时初始化的逻辑,可以在modInit里编写,例如模块注册一个外部模块可以访问的Service接口

-(void)modInit:(BHContext *)context
{
//注册模块的接口服务
[[BeeHive shareInstance] registerService:@protocol(UserTrackServiceProtocol) service:[BHUserTrackViewController class]];
}
  • 处理系统事件

系统的事件会被传递给每个模块,让每个模块自己决定编写业务处理逻辑,比如3D-Touch功能

-(void)modQuickAction:(BHContext *)context
{
[self process:context.shortcutItem handler:context.scompletionHandler];
}

模间调用

通过处理Event编写各个业务模块可以实现插件化编程,各业务模块之间没有任何依赖,core与module之间通过event交互,实现了插件隔离。但有时候我们需要模块间的相互调用某些功能来协同完成功能。 通常会有三种形式的接口访问形式

  • 基于接口的实现Service访问方式(java spring框架实现)

  • 基于函数调用约定实现的Export Method(PHP的extension,ReactNatve的扩展机制)

  • 基于跨应用实现的Url route模式(iphone app之间的互访)

我们目前实现了第一种方式,后续会逐步实现后两种方式

Servcie访问

Service访问的优点是可以编译时检查发现接口的变更,从而及时修正接口问题。缺点是需要依赖接口定义的头文件,通过模块增加得越多,维护接口定义的也有一定工作量。以为HomeServiceProtocol为例

  • 定义HomeServiceProtocol暴露模块对外访问的接口

@protocol HomeServiceProtocol 
-(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注册





HomeServiceProtocol
BHViewController

  • 调用

#import "BHService.h"
id< HomeServiceProtocol > homeVc = [[BeeHive shareInstance] createService:@protocol(HomeServiceProtocol)];

单例与多例

对于有些场景下,我们访问每个声明为service的对象,希望对象能保留一些状态,那我们需要声明这个service对象是一个单例对象。

我们只需要在service对象中实现事件函数

声明

-(BOOL) singleton
{
return YES;
}

通过createService获取的对象则为单例对象,如果实现上面函数返回的是NO,则createService返回的是多例

id< HomeServiceProtocol > homeVc = [[BeeHive shareInstance] createService:@protocol(HomeServiceProtocol)];

上下文环境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 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;
}

更多细节可以参考Example用例

集成方式

  • use cocoapods

pod "BeeHive", '1.0.0'

作者

一渡, shijie.qinsj@alibaba-inc.com

达兹, dazi.dp@alibaba-inc.com

 

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

评论(0)
发评论

下载排行榜

全部0条评论

快来发表一下你的评论吧 !

'+ '

'+ '

'+ ''+ '
'+ ''+ ''+ '
'+ ''+ '' ); $.get('/article/vipdownload/aid/'+webid,function(data){ if(data.code ==5){ $(pop_this).attr('href',"/login/index.html"); return false } if(data.code == 2){ //跳转到VIP升级页面 window.location.href="//m.obk20.com/vip/index?aid=" + webid return false } //是会员 if (data.code > 0) { $('body').append(htmlSetNormalDownload); var getWidth=$("#poplayer").width(); $("#poplayer").css("margin-left","-"+getWidth/2+"px"); $('#tips').html(data.msg) $('.download_confirm').click(function(){ $('#dialog').remove(); }) } else { var down_url = $('#vipdownload').attr('data-url'); isBindAnalysisForm(pop_this, down_url, 1) } }); }); //是否开通VIP $.get('/article/vipdownload/aid/'+webid,function(data){ if(data.code == 2 || data.code ==5){ //跳转到VIP升级页面 $('#vipdownload>span').text("开通VIP 免费下载") return false }else{ // 待续费 if(data.code == 3) { vipExpiredInfo.ifVipExpired = true vipExpiredInfo.vipExpiredDate = data.data.endoftime } $('#vipdownload .icon-vip-tips').remove() $('#vipdownload>span').text("VIP免积分下载") } }); }).on("click",".download_cancel",function(){ $('#dialog').remove(); }) var setWeixinShare={};//定义默认的微信分享信息,页面如果要自定义分享,直接更改此变量即可 if(window.navigator.userAgent.toLowerCase().match(/MicroMessenger/i) == 'micromessenger'){ var d={ title:'BeeHive iOS模块化编程框架',//标题 desc:$('[name=description]').attr("content"), //描述 imgUrl:'https://'+location.host+'/static/images/ele-logo.png',// 分享图标,默认是logo link:'',//链接 type:'',// 分享类型,music、video或link,不填默认为link dataUrl:'',//如果type是music或video,则要提供数据链接,默认为空 success:'', // 用户确认分享后执行的回调函数 cancel:''// 用户取消分享后执行的回调函数 } setWeixinShare=$.extend(d,setWeixinShare); $.ajax({ url:"//www.obk20.com/app/wechat/index.php?s=Home/ShareConfig/index", data:"share_url="+encodeURIComponent(location.href)+"&format=jsonp&domain=m", type:'get', dataType:'jsonp', success:function(res){ if(res.status!="successed"){ return false; } $.getScript('https://res.wx.qq.com/open/js/jweixin-1.0.0.js',function(result,status){ if(status!="success"){ return false; } var getWxCfg=res.data; wx.config({ //debug: true, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。 appId:getWxCfg.appId, // 必填,公众号的唯一标识 timestamp:getWxCfg.timestamp, // 必填,生成签名的时间戳 nonceStr:getWxCfg.nonceStr, // 必填,生成签名的随机串 signature:getWxCfg.signature,// 必填,签名,见附录1 jsApiList:['onMenuShareTimeline','onMenuShareAppMessage','onMenuShareQQ','onMenuShareWeibo','onMenuShareQZone'] // 必填,需要使用的JS接口列表,所有JS接口列表见附录2 }); wx.ready(function(){ //获取“分享到朋友圈”按钮点击状态及自定义分享内容接口 wx.onMenuShareTimeline({ title: setWeixinShare.title, // 分享标题 link: setWeixinShare.link, // 分享链接 imgUrl: setWeixinShare.imgUrl, // 分享图标 success: function () { setWeixinShare.success; // 用户确认分享后执行的回调函数 }, cancel: function () { setWeixinShare.cancel; // 用户取消分享后执行的回调函数 } }); //获取“分享给朋友”按钮点击状态及自定义分享内容接口 wx.onMenuShareAppMessage({ title: setWeixinShare.title, // 分享标题 desc: setWeixinShare.desc, // 分享描述 link: setWeixinShare.link, // 分享链接 imgUrl: setWeixinShare.imgUrl, // 分享图标 type: setWeixinShare.type, // 分享类型,music、video或link,不填默认为link dataUrl: setWeixinShare.dataUrl, // 如果type是music或video,则要提供数据链接,默认为空 success: function () { setWeixinShare.success; // 用户确认分享后执行的回调函数 }, cancel: function () { setWeixinShare.cancel; // 用户取消分享后执行的回调函数 } }); //获取“分享到QQ”按钮点击状态及自定义分享内容接口 wx.onMenuShareQQ({ title: setWeixinShare.title, // 分享标题 desc: setWeixinShare.desc, // 分享描述 link: setWeixinShare.link, // 分享链接 imgUrl: setWeixinShare.imgUrl, // 分享图标 success: function () { setWeixinShare.success; // 用户确认分享后执行的回调函数 }, cancel: function () { setWeixinShare.cancel; // 用户取消分享后执行的回调函数 } }); //获取“分享到腾讯微博”按钮点击状态及自定义分享内容接口 wx.onMenuShareWeibo({ title: setWeixinShare.title, // 分享标题 desc: setWeixinShare.desc, // 分享描述 link: setWeixinShare.link, // 分享链接 imgUrl: setWeixinShare.imgUrl, // 分享图标 success: function () { setWeixinShare.success; // 用户确认分享后执行的回调函数 }, cancel: function () { setWeixinShare.cancel; // 用户取消分享后执行的回调函数 } }); //获取“分享到QQ空间”按钮点击状态及自定义分享内容接口 wx.onMenuShareQZone({ title: setWeixinShare.title, // 分享标题 desc: setWeixinShare.desc, // 分享描述 link: setWeixinShare.link, // 分享链接 imgUrl: setWeixinShare.imgUrl, // 分享图标 success: function () { setWeixinShare.success; // 用户确认分享后执行的回调函数 }, cancel: function () { setWeixinShare.cancel; // 用户取消分享后执行的回调函数 } }); }); }); } }); } function openX_ad(posterid, htmlid, width, height) { if ($(htmlid).length > 0) { var randomnumber = Math.random(); var now_url = encodeURIComponent(window.location.href); var ga = document.createElement('iframe'); ga.src = 'https://www1.elecfans.com/www/delivery/myafr.php?target=_blank&cb=' + randomnumber + '&zoneid=' + posterid+'&prefer='+now_url; ga.width = width; ga.height = height; ga.frameBorder = 0; ga.scrolling = 'no'; var s = $(htmlid).append(ga); } } openX_ad(828, '#berry-300', 300, 250);