1. 开源库基本信息:
开源地址
2. 源码解析
BeeHive 整体结构
BeeHive 整个模块由上图几个模块构成:
BeeHive是BeeHive的核心接口类,它主要用于注册Module,注册Service,查找符合某个协议的Service,以及触发自定义事件。
它在setContext的时候会加载一系列的静态服务和模块
BHAppDelegate负责转发系统消息的代理,项目中的代理需要继承这个方法。
BHContext用于存放公共数据的上下文,某个服务的对应的实现类对象也会缓存到这个地方。
- BHRouter:
BHRouter是BeeHive的路由,支持查找服务,跳转页面,注册服务。是基于URL的格式:目前支持的协议如下://url - > com.alibaba.beehive://call.service.beehive/pathComponentKey.protocolName.selector/...?params={}(value url encode) //url - > com.alibaba.beehive://register.beehive/pathComponentKey.protocolName/...?params={}(value url encode) //url - > com.alibaba.beehive://jump.vc.beehive/pathComponentKey.protocolName.push(modal)/...?params={}(value url encode) //params -> {pathComponentKey:{paramName:paramValue,...},...}
|
- BHModuleManager:
BHModuleManager 主要负责管理模块和分发事件
BHModuleManager 负责注册,查找,定位,删除服务
不论是服务还是模块,BeeHive都提供了三种不同的注册形式:静态plist,动态注册,annotation。
个人觉得可以将事件从BHModuleManager中独立出来会显得比较清晰,并且将路由功能也通过BeeHive暴露接口,这样用户需要什么功能都可以直接调用BeeHive接口。
也就是说整个项目以BeeHive为中心,BHAppDelegate持有BeeHive,并向BeeHive注入系统事件,BHContext向BeeHive注入上下文,BeeHive作为对外的门面,向外界暴露模块,服务,事件,路由管理功能,而模块功能由BHModuleManager实际管理,服务功能由BHServiceManager具体管理,事件由BHEventManager管理,路由由BHRouter管理。大体如下图所示:
模块管理器 BHModuleManager
BHModuleManager 主要负责两大类任务:
1. 通过模块的静态加载,动态注册添加模块 2. 注册模块事件
|
模块添加移除
模块动态注册:
模块注册是通过registerDynamicModule函数注册的,参数是模块的Class。
- (void)registerDynamicModule:(Class)moduleClass { [self registerDynamicModule:moduleClass shouldTriggerInitEvent:NO]; }
|
- (void)registerDynamicModule:(Class)moduleClass shouldTriggerInitEvent:(BOOL)shouldTriggerInitEvent { [self addModuleFromObject:moduleClass shouldTriggerInitEvent:shouldTriggerInitEvent]; }
|
- (void)addModuleFromObject:(id)object shouldTriggerInitEvent:(BOOL)shouldTriggerInitEvent { Class class; NSString *moduleName = nil; if (!object) return; class = object; moduleName = NSStringFromClass(class); __block BOOL flag = YES; [self.BHModules enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { if ([obj isKindOfClass:class]) { flag = NO; *stop = YES; } }]; if (!flag) return; if ([class conformsToProtocol:@protocol(BHModuleProtocol)]) { NSMutableDictionary *moduleInfo = [NSMutableDictionary dictionary]; BOOL responseBasicLevel = [class instancesRespondToSelector:@selector(basicModuleLevel)]; int levelInt = 1; if (responseBasicLevel) { levelInt = 0; } [moduleInfo setObject:@(levelInt) forKey:kModuleInfoLevelKey]; if (moduleName) { [moduleInfo setObject:moduleName forKey:kModuleInfoNameKey]; } [self.BHModuleInfos addObject:moduleInfo]; id<BHModuleProtocol> moduleInstance = [[class alloc] init]; [self.BHModules addObject:moduleInstance]; [moduleInfo setObject:@(YES) forKey:kModuleInfoHasInstantiatedKey];
[self.BHModules sortUsingComparator:^NSComparisonResult(id<BHModuleProtocol> moduleInstance1, id<BHModuleProtocol> moduleInstance2) { NSNumber *module1Level = @(BHModuleNormal); NSNumber *module2Level = @(BHModuleNormal); if ([moduleInstance1 respondsToSelector:@selector(basicModuleLevel)]) { module1Level = @(BHModuleBasic); } if ([moduleInstance2 respondsToSelector:@selector(basicModuleLevel)]) { module2Level = @(BHModuleBasic); } if (module1Level.integerValue != module2Level.integerValue) { return module1Level.integerValue > module2Level.integerValue; } else { NSInteger module1Priority = 0; NSInteger module2Priority = 0; if ([moduleInstance1 respondsToSelector:@selector(modulePriority)]) { module1Priority = [moduleInstance1 modulePriority]; } if ([moduleInstance2 respondsToSelector:@selector(modulePriority)]) { module2Priority = [moduleInstance2 modulePriority]; } return module1Priority < module2Priority; } }]; [self registerEventsByModuleInstance:moduleInstance]; if (shouldTriggerInitEvent) { [self handleModuleEvent:BHMSetupEvent forTarget:moduleInstance withSeletorStr:nil andCustomParam:nil]; [self handleModulesInitEventForTarget:moduleInstance withCustomParam:nil]; dispatch_async(dispatch_get_main_queue(), ^{ [self handleModuleEvent:BHMSplashEvent forTarget:moduleInstance withSeletorStr:nil andCustomParam:nil]; }); } } }
|
模块注册涉及到两个数组BHModuleInfos 以及 BHModules一个用于存放模块的信息,一个用于存放模块,模块信息包括:模块名(kModuleInfoNameKey),模块等级(kModuleInfoLevelKey),模块是否有实例对象(kModuleInfoHasInstantiatedKey)。每个模块都必须遵循BHModuleProtocol协议。在每次添加的时候都会按照模块level以及模块优先级进行排序。
然后在通过registerEventsByModuleInstance来注册消息事件的监听,如果shouldTriggerInitEvent为YES那么就会触发BHMSetupEvent,BHMInitEvent,BHMSplashEvent事件。
模块移除:
- (void)unRegisterDynamicModule:(Class)moduleClass { if (!moduleClass) { return; } [self.BHModuleInfos filterUsingPredicate:[NSPredicate predicateWithFormat:@"%@!=%@", kModuleInfoNameKey, NSStringFromClass(moduleClass)]]; __block NSInteger index = -1; [self.BHModules enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { if ([obj isKindOfClass:moduleClass]) { index = idx; *stop = YES; } }]; if (index >= 0) { [self.BHModules removeObjectAtIndex:index]; } [self.BHModulesByEvent enumerateKeysAndObjectsUsingBlock:^(NSNumber * _Nonnull key, NSMutableArray<id<BHModuleProtocol>> * _Nonnull obj, BOOL * _Nonnull stop) { __block NSInteger index = -1; [obj enumerateObjectsUsingBlock:^(id<BHModuleProtocol> _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { if ([obj isKindOfClass:moduleClass]) { index = idx; *stop = NO; } }]; if (index >= 0) { [obj removeObjectAtIndex:index]; } }]; }
|
模块移除也遵循上面的步骤,首先是会从BHModules中移除,而后再从事件中移除,后者会放在后面介绍事件的时候进行详细介绍。
全部模块注册:
全部模块注册的任务是对模块信息中没有实例化的模块进行实例化后添加到self.BHModules,并对这些模块同一监听系统事件。
- (void)registedAllModules {
[self.BHModuleInfos sortUsingComparator:^NSComparisonResult(NSDictionary *module1, NSDictionary *module2) { NSNumber *module1Level = (NSNumber *)[module1 objectForKey:kModuleInfoLevelKey]; NSNumber *module2Level = (NSNumber *)[module2 objectForKey:kModuleInfoLevelKey]; if (module1Level.integerValue != module2Level.integerValue) { return module1Level.integerValue > module2Level.integerValue; } else { NSNumber *module1Priority = (NSNumber *)[module1 objectForKey:kModuleInfoPriorityKey]; NSNumber *module2Priority = (NSNumber *)[module2 objectForKey:kModuleInfoPriorityKey]; return module1Priority.integerValue < module2Priority.integerValue; } }]; NSMutableArray *tmpArray = [NSMutableArray array]; [self.BHModuleInfos enumerateObjectsUsingBlock:^(NSDictionary *module, NSUInteger idx, BOOL * _Nonnull stop) { NSString *classStr = [module objectForKey:kModuleInfoNameKey]; Class moduleClass = NSClassFromString(classStr); BOOL hasInstantiated = ((NSNumber *)[module objectForKey:kModuleInfoHasInstantiatedKey]).boolValue; if (NSStringFromClass(moduleClass) && !hasInstantiated) { id<BHModuleProtocol> moduleInstance = [[moduleClass alloc] init]; [tmpArray addObject:moduleInstance]; } }]; [self.BHModules addObjectsFromArray:tmpArray]; [self registerAllSystemEvents]; }
|
那么哪些模块是不会在注册的时候实例化呢?其实我们刚刚看到了,注册方法中有个Dynamic关键字表示动态注册,相对的BeeHive支持从plist文件中静态注册,这些静态注册的模块需要调用registedAllModules进行实例化,并注册事件。
模块静态注册:
- (void)loadLocalModules { NSString *plistPath = [[NSBundle mainBundle] pathForResource:[BHContext shareInstance].moduleConfigName ofType:@"plist"]; if (![[NSFileManager defaultManager] fileExistsAtPath:plistPath]) { return; } NSDictionary *moduleList = [[NSDictionary alloc] initWithContentsOfFile:plistPath]; NSArray<NSDictionary *> *modulesArray = [moduleList objectForKey:kModuleArrayKey]; NSMutableDictionary<NSString *, NSNumber *> *moduleInfoByClass = @{}.mutableCopy; [self.BHModuleInfos enumerateObjectsUsingBlock:^(NSDictionary * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { [moduleInfoByClass setObject:@1 forKey:[obj objectForKey:kModuleInfoNameKey]]; }]; [modulesArray enumerateObjectsUsingBlock:^(NSDictionary * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { if (!moduleInfoByClass[[obj objectForKey:kModuleInfoNameKey]]) { [self.BHModuleInfos addObject:obj]; } }]; }
|
模块事件
BeeHive的事件分成两类:系统事件以及自定义事件,自定义事件的值规定大于1000.
整个实现涉及到两个字典:BHSelectorByEvent,BHSelectorByEvent,两个字典的key都是EventType,可以通过EventType在BHSelectorByEvent找到响应selector,通过BHSelectorByEvent能够找到对应的模块。我们知道事件的三要素要明确:哪个实例? 监听哪个事件? 用哪个selector处理*,这些都可以通过这两个字典串起来。
事件注册:
系统事件是默认添加的,但是注册是需要手动注册的,在注册模块的时候可以选择默认注册BHMSetupEvent,BHMInitEvent,BHMSplashEvent事件。
- (NSMutableDictionary<NSNumber *, NSString *> *)BHSelectorByEvent { if (!_BHSelectorByEvent) { _BHSelectorByEvent = @{ @(BHMSetupEvent):kSetupSelector, @(BHMInitEvent):kInitSelector, @(BHMTearDownEvent):kTearDownSelector, @(BHMSplashEvent):kSplashSeletor, @(BHMWillResignActiveEvent):kWillResignActiveSelector, @(BHMDidEnterBackgroundEvent):kDidEnterBackgroundSelector, @(BHMWillEnterForegroundEvent):kWillEnterForegroundSelector, @(BHMDidBecomeActiveEvent):kDidBecomeActiveSelector, @(BHMWillTerminateEvent):kWillTerminateSelector, @(BHMUnmountEvent):kUnmountEventSelector, @(BHMOpenURLEvent):kOpenURLSelector, @(BHMDidReceiveMemoryWarningEvent):kDidReceiveMemoryWarningSelector, @(BHMDidReceiveRemoteNotificationEvent):kDidReceiveRemoteNotificationsSelector, @(BHMWillPresentNotificationEvent):kWillPresentNotificationSelector, @(BHMDidReceiveNotificationResponseEvent):kDidReceiveNotificationResponseSelector, @(BHMDidFailToRegisterForRemoteNotificationsEvent):kFailToRegisterForRemoteNotificationsSelector, @(BHMDidRegisterForRemoteNotificationsEvent):kDidRegisterForRemoteNotificationsSelector, @(BHMDidReceiveLocalNotificationEvent):kDidReceiveLocalNotificationsSelector, @(BHMWillContinueUserActivityEvent):kWillContinueUserActivitySelector, @(BHMContinueUserActivityEvent):kContinueUserActivitySelector, @(BHMDidFailToContinueUserActivityEvent):kFailToContinueUserActivitySelector, @(BHMDidUpdateUserActivityEvent):kDidUpdateContinueUserActivitySelector, @(BHMQuickActionEvent):kQuickActionSelector, @(BHMHandleWatchKitExtensionRequestEvent):kHandleWatchKitExtensionRequestSelector, @(BHMDidCustomEvent):kAppCustomSelector, }.mutableCopy; } return _BHSelectorByEvent; }
|
我们先来看下事件的注册方法:
首先会做一些预先判断:要注册的实例是否能够响应指定的selector,如果不能就不注册了,如果可以响应那么将eventType为key,selectorStr为value添加到BHSelectorByEvent,然后在查看BHModulesByEvent对应的eventType下面是否添加了当前的实例。添加后再按照modelLevel以及priority对实例进行排序,保证BHModulesByEvent中每个事件的实例列表是按照优先级排序的,优先级高的优先收到事件。
- (void)registerEvent:(NSInteger)eventType withModuleInstance:(id)moduleInstance andSelectorStr:(NSString *)selectorStr { SEL selector = NSSelectorFromString(selectorStr); if (!selector || ![moduleInstance respondsToSelector:selector]) return; NSNumber *eventTypeNumber = @(eventType); if (!self.BHSelectorByEvent[eventTypeNumber]) { [self.BHSelectorByEvent setObject:selectorStr forKey:eventTypeNumber]; } if (!self.BHModulesByEvent[eventTypeNumber]) { [self.BHModulesByEvent setObject:@[].mutableCopy forKey:eventTypeNumber]; } NSMutableArray *eventModules = [self.BHModulesByEvent objectForKey:eventTypeNumber]; if (![eventModules containsObject:moduleInstance]) { [eventModules addObject:moduleInstance]; [eventModules sortUsingComparator:^NSComparisonResult(id<BHModuleProtocol> moduleInstance1, id<BHModuleProtocol> moduleInstance2) { NSNumber *module1Level = @(BHModuleNormal); NSNumber *module2Level = @(BHModuleNormal); if ([moduleInstance1 respondsToSelector:@selector(basicModuleLevel)]) { module1Level = @(BHModuleBasic); } if ([moduleInstance2 respondsToSelector:@selector(basicModuleLevel)]) { module2Level = @(BHModuleBasic); } if (module1Level.integerValue != module2Level.integerValue) { return module1Level.integerValue > module2Level.integerValue; } else { NSInteger module1Priority = 0; NSInteger module2Priority = 0; if ([moduleInstance1 respondsToSelector:@selector(modulePriority)]) { module1Priority = [moduleInstance1 modulePriority]; } if ([moduleInstance2 respondsToSelector:@selector(modulePriority)]) { module2Priority = [moduleInstance2 modulePriority]; } return module1Priority < module2Priority; } }]; } }
|
事件触发
- (void)triggerEvent:(NSInteger)eventType withCustomParam:(NSDictionary *)customParam { [self handleModuleEvent:eventType forTarget:nil withCustomParam:customParam]; }
|
- (void)handleModuleEvent:(NSInteger)eventType forTarget:(id<BHModuleProtocol>)target withSeletorStr:(NSString *)selectorStr andCustomParam:(NSDictionary *)customParam { BHContext *context = [BHContext shareInstance].copy; context.customParam = customParam; context.customEvent = eventType; if (!selectorStr.length) { selectorStr = [self.BHSelectorByEvent objectForKey:@(eventType)]; } SEL seletor = NSSelectorFromString(selectorStr); if (!seletor) { selectorStr = [self.BHSelectorByEvent objectForKey:@(eventType)]; seletor = NSSelectorFromString(selectorStr); } NSArray<id<BHModuleProtocol>> *moduleInstances; if (target) { moduleInstances = @[target]; } else { moduleInstances = [self.BHModulesByEvent objectForKey:@(eventType)]; } [moduleInstances enumerateObjectsUsingBlock:^(id<BHModuleProtocol> moduleInstance, NSUInteger idx, BOOL * _Nonnull stop) { if ([moduleInstance respondsToSelector:seletor]) { #pragma clang diagnostic push #pragma clang diagnostic ignored "-Warc-performSelector-leaks" [moduleInstance performSelector:seletor withObject:context]; #pragma clang diagnostic pop [[BHTimeProfiler sharedTimeProfiler] recordEventTime:[NSString stringWithFormat:@"%@ --- %@", [moduleInstance class], NSStringFromSelector(seletor)]]; } }]; }
|
事件触发实际上是通过performSelector来完成的,它需要知道要触发哪个实例的哪个事件,介绍了上面的注册流程后就可以很清楚得了解到整个事件的组织结构,那么事件的触发就是通过上面介绍的两个字典,找到事件的响应方法,以及需要触发哪些实例的对应方法了。BeeHive将模块初始化以及模块销毁独立开来是因为这两个事件有特殊之处,模块初始化有些模块是支持异步的,有些则是同步的,模块销毁的特别之处在于要按照优先级从低到高销毁。
服务管理器 BHServiceManager
在BeeHive中另一个比较重要的就是Servic了,它类似于一个提供某个处理的接口,BHServiceManager负责服务的注册,服务的移除,服务的搜索,同样BHServiceManager也提供了动态和静态注册服务的两种方式,BeeHive的服务实际上是Protocal - Class(Instance) 模式,Protocal提供了服务能够提供哪些服务的外在接口协议,而Class(Instance) 实际上则是这些服务的真正提供实例。
服务添加,移除,定位
服务动态注册:
这没啥好说的一看就懂:
- (void)registerService:(Protocol *)service implClass:(Class)implClass { NSParameterAssert(service != nil); NSParameterAssert(implClass != nil); if (![implClass conformsToProtocol:service]) { if (self.enableException) { @throw [NSException exceptionWithName:NSInternalInconsistencyException reason:[NSString stringWithFormat:@"%@ module does not comply with %@ protocol", NSStringFromClass(implClass), NSStringFromProtocol(service)] userInfo:nil]; } return; } if ([self checkValidService:service]) { if (self.enableException) { @throw [NSException exceptionWithName:NSInternalInconsistencyException reason:[NSString stringWithFormat:@"%@ protocol has been registed", NSStringFromProtocol(service)] userInfo:nil]; } return; } NSString *key = NSStringFromProtocol(service); NSString *value = NSStringFromClass(implClass); if (key.length > 0 && value.length > 0) { [self.lock lock]; [self.allServicesDict addEntriesFromDictionary:@{key:value}]; [self.lock unlock]; } }
|
服务静态注册:
还是不说哼哼哈哈^V^
- (void)registerLocalServices { NSString *serviceConfigName = [BHContext shareInstance].serviceConfigName; NSString *plistPath = [[NSBundle mainBundle] pathForResource:serviceConfigName ofType:@"plist"]; if (!plistPath) return; NSArray *serviceList = [[NSArray alloc] initWithContentsOfFile:plistPath]; [self.lock lock]; for (NSDictionary *dict in serviceList) { NSString *protocolKey = [dict objectForKey:@"service"]; NSString *protocolImplClass = [dict objectForKey:@"impl"]; if (protocolKey.length > 0 && protocolImplClass.length > 0) { [self.allServicesDict addEntriesFromDictionary:@{protocolKey:protocolImplClass}]; } } [self.lock unlock]; }
|
服务定位:
- (id)createService:(Protocol *)service withServiceName:(NSString *)serviceName shouldCache:(BOOL)shouldCache { if (!serviceName.length) { serviceName = NSStringFromProtocol(service); } id implInstance = nil; if (![self checkValidService:service]) { if (self.enableException) { @throw [NSException exceptionWithName:NSInternalInconsistencyException reason:[NSString stringWithFormat:@"%@ protocol does not been registed", NSStringFromProtocol(service)] userInfo:nil]; } } NSString *serviceStr = serviceName; if (shouldCache) { id protocolImpl = [[BHContext shareInstance] getServiceInstanceFromServiceName:serviceStr]; if (protocolImpl) { return protocolImpl; } } Class implClass = [self serviceImplClass:service]; if ([[implClass class] respondsToSelector:@selector(singleton)]) { if ([[implClass class] singleton]) { if ([[implClass class] respondsToSelector:@selector(shareInstance)]) implInstance = [[implClass class] shareInstance]; else implInstance = [[implClass alloc] init]; if (shouldCache) { [[BHContext shareInstance] addServiceWithImplInstance:implInstance serviceName:serviceStr]; return implInstance; } else { return implInstance; } } } return [[implClass alloc] init]; }
|
关于createService这个方法名起得个人觉得不是很好,刚看到这个方法名的时候我的第一印象是:服务不是通过regist方法注册了吗,为什么需要create,实际上这只是通过服务协议来找到服务提供对象而已,个人建议可以叫做:
- (id)serviceConfirmToProtocol:(Protocol *)service withServiceName:(NSString *)serviceName shouldCache:(BOOL)shouldCache;
|
这里有一个需要注意的是我们这里返回的是提供服务的实例,而我们注册的提供服务的Class,为了避免每次都根据Class创建实例 ,BHContext 中有提供对应的缓存存储在[BHContext shareInstance].servicesByName中,而我们注册的服务存储在serviceImplClass中,所以每次我们要做的就是通过Protocal从先从[BHContext shareInstance].servicesByName中找,如果有之前已经缓存的实例的话就不需要重新创建了,直接返回就可以了,如果没有那么从serviceImplClass中找到对应的class,然后初始化出实例,然后添加到[BHContext shareInstance].servicesByName中缓存。
3.Annotation 注解
这是我看BeeHive眼前一亮的一块代码,本来想将这块内容放到服务和模块注册地方来介绍的,因为BeeHive注解主要用于注册模块和服务,之所以单独成一块来介绍主要是它有一定的通用性。
我们就开始看这块内容:
注册模块的时候使用的宏定义
#define BeeHiveMod(name) \ class BeeHive; char * k##name##_mod BeeHiveDATA(BeehiveMods) = ""#name"";
|
注册服务时候使用的宏定义:
#define BeeHiveService(servicename,impl) \ class BeeHive; char * k##servicename##_service BeeHiveDATA(BeehiveServices) = "{ \""#servicename"\" : \""#impl"\"}";
|
在项目中可以这样使用:
@BeeHiveMod(ShopModule) @interface ShopModule() <BHModuleProtocol> @end
|
@BeeHiveService(HomeServiceProtocol,BHViewController) @interface BHViewController ()<HomeServiceProtocol>
@end
|
我们专注来看BeeHiveMod:
#define BeeHiveMod(name) \ class BeeHive; char * k##name##_mod BeeHiveDATA(BeehiveMods) = ""#name"";
|
@BeeHiveMod(ShopModule) 替换后会变成:
class BeeHive; char * kShopModule_mod BeeHiveDATA(BeehiveMods) = ""ShopModule"";
|
再来看下:BeeHiveDATA
#define BeeHiveDATA(sectname) __attribute((used, section("__DATA,"#sectname" ")))
|
替换后变成:
@class BeeHive; char * kShopModule_mod __attribute((used, section("__DATA,""BeehiveMods"" "))) = """ShopModule""";
|
去掉__attribute的属性,相当于:
@class BeeHive; char * kShopModule_mod = """ShopModule""";
|
这里最重要的关键字是__attribute,由于kShopModule_mod字符串没有使用到,在Release包的时候会被优化掉所以需要使用used来避免被编译器优化,section用于指定kShopModule_mod存放的位置,section(“__DATA,””BeehiveMods”” “)表示,将kShopModule_mod存储在__DATA数据段里面的”BeehiveMods”section中。
那如何读取到这些字段呢?我们看下BHAnnotation类,我们先看下initProphet,
__attribute__((constructor)) void initProphet()
|
它用编译标记__attribute__((constructor))进行标记,****attribute((constructor))**** 的用法大家可以看下:
attribute((constructor))是在main函数之前,执行一个函数,也就是initProphet会在编译之前执行,_dyld_register_func_for_add_image(dyld_callback);回来镜像加载后调用dyld_callback。在这里面可以对加载完的镜像文件进行处理,读取出我们写到指定Session中的数据。
NSArray<NSString *>* BHReadConfiguration(char *sectionName,const struct mach_header *mhp) { NSMutableArray *configs = [NSMutableArray array]; unsigned long size = 0; #ifndef __LP64__ uintptr_t *memory = (uintptr_t*)getsectiondata(mhp, SEG_DATA, sectionName, &size); #else const struct mach_header_64 *mhp64 = (const struct mach_header_64 *)mhp; uintptr_t *memory = (uintptr_t*)getsectiondata(mhp64, SEG_DATA, sectionName, &size); #endif unsigned long counter = size/sizeof(void*); for(int idx = 0; idx < counter; ++idx){ char *string = (char*)memory[idx]; NSString *str = [NSString stringWithUTF8String:string]; if(!str)continue; BHLog(@"config = %@", str); if(str) [configs addObject:str]; } return configs; }
|
BHReadConfiguration 用于从__DATA中读取指定session下的数据。
static void dyld_callback(const struct mach_header *mhp, intptr_t vmaddr_slide) { NSArray *mods = BHReadConfiguration(BeehiveModSectName, mhp); for (NSString *modName in mods) { Class cls; if (modName) { cls = NSClassFromString(modName); if (cls) { [[BHModuleManager sharedManager] registerDynamicModule:cls]; } } } NSArray<NSString *> *services = BHReadConfiguration(BeehiveServiceSectName,mhp); for (NSString *map in services) { NSData *jsonData = [map dataUsingEncoding:NSUTF8StringEncoding]; NSError *error = nil; id json = [NSJSONSerialization JSONObjectWithData:jsonData options:0 error:&error]; if (!error) { if ([json isKindOfClass:[NSDictionary class]] && [json allKeys].count) { NSString *protocol = [json allKeys][0]; NSString *clsName = [json allValues][0]; if (protocol && clsName) { [[BHServiceManager sharedManager] registerService:NSProtocolFromString(protocol) implClass:NSClassFromString(clsName)]; } } } } }
|
也就是在镜像文件加载完毕后,通过BHReadConfiguration将上面注解方式添加的字符串读取出来,并使用这些数据进行注册服务和模块。
4.较好的文章推荐