Coder Social home page Coder Social logo

alibaba / beehive Goto Github PK

View Code? Open in Web Editor NEW
4.3K 165.0 782.0 441 KB

:honeybee: BeeHive is a solution for iOS Application module programs, it absorbed the Spring Framework API service concept to avoid coupling between modules.

Home Page: https://github.com/alibaba/BeeHive/blob/master/README.md

License: GNU General Public License v2.0

Objective-C 98.32% C 0.85% Ruby 0.83%
beehive registered-services modular ios service module service-discovery service-registration lifecycle lifecycle-events

beehive's Introduction

BeeHive

Build Status Version Platform GitHub release
Gitter GitHub issues License

📖 English Documentation | 📖 中文文档


0. Abstract

BeeHive is a modular program of implementation in iOS , it absorbed the Spring Framework API service concept to avoid to directly coupling between modules.

0.1 The basic architecture

We can get to know the architecture of BeeHive from this picture.

0.2 Core concepts

  • Module: Modules are separated by different function, every module can communicate with other one through their own services.
  • Service: Services are the interface of the specifically module.

0.3 Achieved characteristics

  • Plug-in module development of the operating framework
  • Module implementation and interface calls Separation
  • manage module life loop, extend the application of system events

0.4 Design

BeeHive bases on Spring Service concept, although you can make and implement specific interfaces decoupling between modules , but can not avoid interface class dependencies.

Why not use invoke and dynamic link library technology for decoupling interface , similar to Apache's DSO way?

Mainly on account of the difficulty and cost of learning to achieve , and dynamic invocation interface parameters can not be able to check phase change problems at compile time , dynamic programming techniques require a higher threshold requirement.

0.5 Project name origin

BeeHive inspired by the honeycomb. Honeycomb is the world's highly modular engineering structures, hexagonal design can bring unlimited expansion possibilities. So we used to do for this project BeeHive named.

1. Module life-cycle event

BeeHive's Each module will provide life-cycle events for the host environment and Each module necessary information exchange to BeeHive, you can observer the change in life run loop.

Events are divided into three types:

  • System Event
  • Universal Event
  • Business Custom Event

1.1 System Event

System events are usually Application life-cycle events , such as DidBecomeActive, WillEnterBackground etc. System Event basic workflow is as follows:

1.2 Universal Event

On the basis of system events on the extended general application events , such modSetup, modInit , etc. , may be used to code each plug-in module initialization settings

Extended common events are as follows :

1.3 Business Custom Event

If you feel the system event , the event is not sufficient to meet the general needs , we will simplify the event packaged into BHAppdelgate, you can extend your own event by inheritance BHAppdelegate, while BHContext Lane modulesByName access each module entry class , to increase the trigger point through.

2. Module registration

Registration module divided into two types , static registration and dynamic registration

2.1 Static registration

2.2 Dynamic registration

Use BH_EXPORT_MODULE macro module entry in the class implementation declares the class for the implementation class entry module

@implementation HomeModule

BH_EXPORT_MODULE(YES)

-(void)modInit:(BHContext *)context;

@end

2.3 Asynchronous loading

If the module is set to export BH_EXPORT_MODULE (YES), it will initialize asynchronous execution module can be optimized before starting after the first screen shows the contents of the start time consuming

3. Programming

BHModuleProtocol provides various modules each module can hook functions , and logic for implementing the plug-in code, you can fine protocol in BHModuleProtocol.h.

3.1 Setting environment variables

By context.env we can judge our application environment state to decide how we configure our application

-(void)modSetup:(BHContext *)context
{
	switch (context.env) {
		case BHEnvironmentDev:
		break;
		case BHEnvironmentProd:
		default:
		break;
	}
}

3.2 Module Init

If the module there is need to start initialization logic can modInit in the preparation of , for example, the module can register an external module interface to access the Service

-(void)modInit:(BHContext *)context
{
	[[BeeHive shareInstance] registerService:@protocol(UserTrackServiceProtocol) service:[BHUserTrackViewController class]];
}

3.3 Event processing systems

Event system will be passed to each module, so that each module to decide to write business logic.

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

3.4 Inter-modal calls

Event prepared by treating the various business modules can plug-in programming , it has no dependencies between the various business modules , through the interaction between the core and the event module, to achieve a plug-in isolation . But sometimes we need to call each other between modules some collaborative features to completion.

Usually in the form of three types to access service:

  1. by interface(like Spring)
  2. by Export Method(like PHP/ReactNative extension)
  3. by URL Route pattern(like interaction between iPhone apps)

Interface type of service access can take the advantages of compile-time checking is found to change the interface , so that timely correction interface issues . The disadvantage is the need to rely on the interface definition header file by the module increases the more the maintenance interface definition there is a certain amount of work .

3.4.1 Declare service interface

Case thought HomeServiceProtocol:

@protocol HomeServiceProtocol <NSObject, BHServiceProtocol>

-(void)registerViewController:(UIViewController *)vc title:(NSString *)title iconName:(NSString *)iconName;

@end

3.4.2 Register Service

There are two ways to register ViewController Service.

API registration

[[BeeHive shareInstance] registerService:@protocol(HomeServiceProtocol) service:[BHViewController class]];

BHService.plist registration

<?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 invocation

#import "BHService.h"

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

// use homeVc do invocation

3.5 Singleton or several instance

For some scenes , we visit each declared as service objects , objects can hope to retain some of the state , then we need to declare this service object is a singleton object .

We only need to implement the function declaration in the event service objects

-(BOOL) singleton
{
	return YES;
}

The object was acquired by createService singleton object , if the function returns to achieve the above is NO, createService returns multiple cases

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

3.6 Global Context

Initial setup application project information , and share information across applications among modules

- (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";
	[BHContext shareInstance].serviceConfigName =  @"BeeHive.bundle/CustomServicePlist";

	[BHContext shareInstance].appkey  = xxxxxx;
	[BHContext shareInstance].Mtopkey  = xxxxx;


	[[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;
}

4. Integration

cocoapods

pod "BeeHive", '1.1.1'

5. Author

  • 一渡 shijie.qinsj<at>alibaba-inc<dot>com
  • 达兹 dazi.dp<at>alibaba-inc<dot>com

6. WeChat Group

Because the WeChat Group had reached to the max number of people , you can join us by search dolphinux in WeChat.

7. License

BeeHive is available under the GPL license. See the LICENSE file for more info.

beehive's People

Contributors

alibaba-oss avatar ddzcoeur avatar gitter-badger avatar irpchen avatar laizhenwei avatar luoqisheng avatar oldratlee avatar panshimin avatar satanwoo avatar soxeon avatar yaochenfeng avatar youqizdd avatar zhaoxiaobao avatar zhongwuzw avatar zominster avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

beehive's Issues

CocoaPods 1.0 support

{:exclusive=>true} is an unsupport option in CocoaPods 1.0 version.Please fix it.

在引入BeeHive的工程里,一些组件的配置应该放在那个地方呢?

比如我们目前的工程里,一些组件需要外部环境参数配置,目前是放在 didFinishLaunchingWithOptions 里,然后项目依赖这些组件。在引入BeeHive后,这些组件的合适位置应该是放在那里?是应该作为Module 一样,每个组件都创建一个Module 管理组件的生命周期,还是只建一个公共Module 统一管理这些组件?

另外,麻烦再问下,每个项目做成插件后,独立运行的基础是 项目代码依赖一个统一的工程配置吗?比如说各种组件的初始化配置,都放在一个工程壳子里,然后每个项目代码加上这个壳子就能独立编译运行

关于 BHServiceProtocol 单例的疑问

BHServiceProtocol 中定义了shareInstance这个方法,那么我通过 createService: 获取一个单例对象的时候,为什么单例对象不是通过我实现的方法创建?

Class implClass = [self serviceImplClass:service];
Method clzSingleMethod = class_getInstanceMethod(implClass, @selector(singleton));
Method insSingleMethod = class_getClassMethod(implClass, @selector(singleton));
if (clzSingleMethod == NULL &&
    insSingleMethod == NULL) {
    return [implClass new];
}

implInstance = [[implClass alloc] init];
NSString *serviceStr = NSStringFromProtocol(service);
[[BHContext shareInstance] addServiceWithImplInstance:implInstance serviceName:serviceStr];
return implInstance;

在上面 BHServiceManagercreateService: 实现中,只是判断了是否实现了 singleton 方法,然后是通过 [[implClass alloc] init] 创建的单例。

service调用为什么不用URL的形式

现在协议的方式,还是有一些耦合度。
用协议的实现方式也有你们自己的想法,
我想知道当时为什么没有用URL的调用方式?
还是现在正在策划中?

BH_EXPORT_MODULE中async永远返回YES

BHModuleProtocol.h中define BH_EXPORT_MODULE(isAsync)
+ (void)load { [BeeHive registerDynamicModule:[self class]]; } \
-(BOOL)async { return (BOOL)**#isAsync;**} 

这里的#isAsync表示加个引号,就算是BH_EXPORT_MODULE(NO) (BOOL) async {return (BOOL)"NO";}
返回永远为YES

通过BeeHiveService声明的Service找不到

  1. 首先,AppDelegate继承了BHAppDelegate,回调书写如Demo中一样
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    // Override point for customization after application launch.
    [BHContext shareInstance].application = application;
    [BHContext shareInstance].launchOptions = launchOptions;
    [BHContext shareInstance].moduleConfigName = @"PPDDemoHome.bundle/PPDDemoHomeModule";//可选,默认为BeeHive.bundle/BeeHive.plist
    [BHContext shareInstance].serviceConfigName = @"PPDDemoHome.bundle/PPDDemoHomeService";
    
    [BeeHive shareInstance].enableException = YES;
    [[BeeHive shareInstance] setContext:[BHContext shareInstance]];
    [[BHTimeProfiler sharedTimeProfiler] recordEventTime:@"BeeHive::super start launch"];
    
    [super application:application didFinishLaunchingWithOptions:launchOptions];
  1. 新建一个PPDUserViewController 实现PPDUserServiceProtocol,
#import <Foundation/Foundation.h>
#import <BeeHive/BeeHive.h>

@protocol PPDUserServiceProtocol <NSObject, BHServiceProtocol>

@end
#import "PPDUserViewController.h"
#import "PPDUserServiceProtocol.h"

BeeHiveService(PPDUserServiceProtocol, PPDUserViewController)
@interface PPDUserViewController ()<PPDUserServiceProtocol>

@end

@implementation PPDUserViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}
  1. 在BHReadConfiguration读取声明配置的时候memory为NULL,导致获取不到声明的Service
static NSArray<NSString *>* BHReadConfiguration(char *section)
{
    NSMutableArray *configs = [NSMutableArray array];
    
    Dl_info info;
    dladdr(BHReadConfiguration, &info);
    
#ifndef __LP64__
    //        const struct mach_header *mhp = _dyld_get_image_header(0); // both works as below line
    const struct mach_header *mhp = (struct mach_header*)info.dli_fbase;
    unsigned long size = 0;
    uint32_t *memory = (uint32_t*)getsectiondata(mhp, "__DATA", section, & size);
#else /* defined(__LP64__) */
    const struct mach_header_64 *mhp = (struct mach_header_64*)info.dli_fbase;
    unsigned long size = 0;
    uint64_t *memory = (uint64_t*)getsectiondata(mhp, "__DATA", section, & size);
#endif /* defined(__LP64__) */
    
    for(int idx = 0; idx < size/sizeof(void*); ++idx){
        char *string = (char*)memory[idx];
        
        NSString *str = [NSString stringWithUTF8String:string];
        if(!str)continue;
        
        BHLog(@"config = %@", str);
        if(str) [configs addObject:str];
    }
    
    return configs;
    
}
  1. 但是通过MachOView找到section地址,再在Hopper中能够找到数据

wx20170314-191155 2x

wx20170314-191222 2x

v1.2.0 关于BHContext的疑问

先前通过继承BHContext来定义了一个CustomContext来存放公共环境变量,例如服务器环境,服务器基址等信息。

问题

v1.2.0版本代码有些改动,BHModuleManager类以及BHServiceManager类内部对于plist静态模块加载plist静态服务加载模块生命周期事件触发均是引用[BHContext shareInstance]对象,然而BHAppDelegate中对于touchShortcutItemopenURLItemnotificationsItemuserActivityItem等属性的赋值却是针对于 [BeeHive shareInstance].context的。

结论

结论就是说我们在使用plist进行模块或者服务的静态注册是我们需要使用[BeeHive shareInstance]来配置plist的路径,而对于touchShortcutItemopenURLItemnotificationsItemuserActivityItem等属性的取值我们要使用CustomContext。这是否与BeeHive的设计初衷不一致?

2个文档说明的改进

ReadMe中@property(nonatomic, readonly) BHEnvironmentType env;这个属性
直接set了但是明明是个readonly,

另外,文档中[BHContext shareInstance].env = BHEnvironmentDev; 这行代码等号是个全角等号

BHReadConfiguration 提供 framework 支持

目前只能在静态链接下 work。

Podfile 中添加 use_frameworks!,以动态库的形式安装 pod 的话,dladdr(BHReadConfiguration, &info); 读取到的 image 就是 BeeHive.framework 了,而 compile 时的 BeeHiveService(HomeServiceProtocol,BHViewController) 则将 info 写在了代码所在 image 的 __DATA 中(可能是主 app 的 executable,也可能是其他的 framework)。

因此需要针对这种情况进行支持,BHReadConfiguration(char *section) 应该需要多接收一个 const void* addr,然后在前面想办法把 addr 传入\找出。

建议将BeeHive类的registerDynamicModule:方法改为私有

  1. 用户如果通过调用registerDynamicModule:方法实现模块注册的话,其调用时机必须在设置BHContext上下文之前,这样容易造成用户调用时机不对而导致模块注册失败。
  2. 官方文档中提到模块注册也只说了2种,静态注册、宏(BH_EXPORT_MODULE),宏BH_EXPORT_MODULE定义中调用了registerDynamicModule:方法,所以我建议将registerDynamicModule:私有,以免误操作。至于宏中调用的话,可以修改一下宏BH_EXPORT_MODULE的定义。

project.xcworkspace 文件

我注意到 BeeHive.xcodeproj 目录下的 project.xcworkspace 没有被包含进项目中,我想了解,不把project.xcworkspace 纳入版本控制的原因是什么?

Service 跟 Module 有什么区别

[BHContext shareInstance].moduleConfigName = @"BeeHive.bundle/BeeHive";//可选,默认为BeeHive.bundle/BeeHive.plist
[BHContext shareInstance].serviceConfigName = @"BeeHive.bundle/BHService";

代码中看到的,请问Service 跟 Module 有什么区别呢?谢谢

这英文写的太烂。。

如果真的是阿里员工写的话,多找几个英文好的读读帮改改。这语句主谓宾组织太写意。动词名词从句各种乱入。逻辑表达前后含混不清。。

关于registedAnnotationModules和registerAnnotationServices

想知道一下这两个注册模块和服务的方法,还有这这种实现的原理,

#define BeeHiveDATA(sectname) __attribute((used, section("__DATA,"#sectname" ")))



#define BeeHiveMod(name) \
char * k##name##_mod BeeHiveDATA(BeehiveMods) = ""#name"";

#define BeeHiveService(servicename,impl) \
char * k##servicename##_service BeeHiveDATA(BeehiveServices) = "{ \""#servicename"\" : \""#impl"\"}";
static NSArray<NSString *>* BHReadConfiguration(char *section)
{
    NSMutableArray *configs = [NSMutableArray array];
    
    Dl_info info;
    dladdr(BHReadConfiguration, &info);
    
#ifndef __LP64__
    //        const struct mach_header *mhp = _dyld_get_image_header(0); // both works as below line
    const struct mach_header *mhp = (struct mach_header*)info.dli_fbase;
    unsigned long size = 0;
    uint32_t *memory = (uint32_t*)getsectiondata(mhp, "__DATA", section, & size);
#else /* defined(__LP64__) */
    const struct mach_header_64 *mhp = (struct mach_header_64*)info.dli_fbase;
    unsigned long size = 0;
    uint64_t *memory = (uint64_t*)getsectiondata(mhp, "__DATA", section, & size);
#endif /* defined(__LP64__) */
    
    for(int idx = 0; idx < size/sizeof(void*); ++idx){
        char *string = (char*)memory[idx];
        
        NSString *str = [NSString stringWithUTF8String:string];
        if(!str)continue;
        
        NSLog(@"config = %@", str);
        if(str) [configs addObject:str];
    }
    
    return configs;
    
}

非单例service生命周期

service创建的时候会加入到servicesByName的dictionary中,但是service不再使用的时候并不能及时的dealloc,而是在下一个同样的service创建的时候进行的dealloc,这样会增加一些service本身的资源开销。

能否增加协议在模块出口处释放资源?

Service返回对象类型声明的建议

id<UserTrackServiceProtocol> v4 = [[BeeHive shareInstance] createService:@protocol(UserTrackServiceProtocol)];
if ([v4 isKindOfClass:[UIViewController class]]) {
    [self registerViewController:(UIViewController *)v4 title:@"埋点3" iconName:nil];
}

id的具体类型需要项目间约定,能否在Protocol的声明文件中就标注返回类型是什么?
比如做约定:

#import <Foundation/Foundation.h>
#import "BHServiceProtocol.h"

@class UIViewController;  //表示当前协议返回类型为UIViewController
@protocol UserTrackServiceProtocol <NSObject,BHServiceProtocol>

@end

毕竟Protocol只能绑定一种类型。

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.