Ta android + ios
This commit is contained in:
@@ -0,0 +1,38 @@
|
||||
//
|
||||
// TAAnnotation.h
|
||||
// Pods
|
||||
//
|
||||
// Created by wwango on 2022/10/8.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
#ifndef ThinkingModSectName
|
||||
|
||||
#define ThinkingModSectName "ThinkingMods"
|
||||
|
||||
#endif
|
||||
|
||||
#ifndef ThinkingServiceSectName
|
||||
|
||||
#define ThinkingServiceSectName "ThinkingServices"
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#define ThinkingDATA(sectname) __attribute((used, section("__DATA,"#sectname" ")))
|
||||
|
||||
|
||||
#define ThinkingMod(name) \
|
||||
char * k##name##_mod ThinkingDATA(ThinkingMods) = ""#name"";
|
||||
|
||||
#define ThinkingService(servicename,impl) \
|
||||
char * k##servicename##_service ThinkingDATA(ThinkingServices) = "{ \""#servicename"\" : \""#impl"\"}";
|
||||
|
||||
@interface TAAnnotation : NSObject
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,33 @@
|
||||
fileFormatVersion: 2
|
||||
guid: dd856a2ac2f52bb458e7378fa95980a3
|
||||
PluginImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
iconMap: {}
|
||||
executionOrder: {}
|
||||
defineConstraints: []
|
||||
isPreloaded: 0
|
||||
isOverridable: 0
|
||||
isExplicitlyReferenced: 0
|
||||
validateReferences: 1
|
||||
platformData:
|
||||
- first:
|
||||
Any:
|
||||
second:
|
||||
enabled: 0
|
||||
settings: {}
|
||||
- first:
|
||||
Editor: Editor
|
||||
second:
|
||||
enabled: 0
|
||||
settings:
|
||||
DefaultValueInitialized: true
|
||||
- first:
|
||||
iPhone: iOS
|
||||
second:
|
||||
enabled: 1
|
||||
settings:
|
||||
AddToEmbeddedBinaries: false
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,89 @@
|
||||
//
|
||||
// TAAnnotation.m
|
||||
// Pods
|
||||
//
|
||||
// Created by wwango on 2022/10/8.
|
||||
//
|
||||
|
||||
#import "TAAnnotation.h"
|
||||
#include <mach-o/getsect.h>
|
||||
#include <mach-o/loader.h>
|
||||
#include <mach-o/dyld.h>
|
||||
#include <dlfcn.h>
|
||||
#import <objc/runtime.h>
|
||||
#import <objc/message.h>
|
||||
#include <mach-o/ldsyms.h>
|
||||
#import "TAModuleManager.h"
|
||||
#import "TAServiceManager.h"
|
||||
|
||||
NSArray<NSString *>* _TAReadConfiguration(char *sectionName,const struct mach_header *mhp);
|
||||
static void dyld_callback(const struct mach_header *mhp, intptr_t vmaddr_slide)
|
||||
{
|
||||
//register mods
|
||||
NSArray *mods = _TAReadConfiguration(ThinkingModSectName, mhp);
|
||||
for (NSString *modName in mods) {
|
||||
Class cls;
|
||||
if (modName) {
|
||||
cls = NSClassFromString(modName);
|
||||
|
||||
if (cls) {
|
||||
[[TAModuleManager sharedManager] registerDynamicModule:cls];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//register services
|
||||
NSArray<NSString *> *services = _TAReadConfiguration(ThinkingServiceSectName,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) {
|
||||
[[TAServiceManager sharedManager] registerService:NSProtocolFromString(protocol) implClass:NSClassFromString(clsName)];
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
NSArray<NSString *>* _TAReadConfiguration(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;
|
||||
|
||||
NSLog(@"config = %@", str);
|
||||
if(str) [configs addObject:str];
|
||||
}
|
||||
|
||||
return configs;
|
||||
}
|
||||
|
||||
__attribute__((constructor)) void __ta_init_dyld_addImage() {
|
||||
_dyld_register_func_for_add_image(dyld_callback);
|
||||
}
|
||||
|
||||
@implementation TAAnnotation
|
||||
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 39fa38ed3ad5f7c4abdcec17e484f316
|
||||
PluginImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
iconMap: {}
|
||||
executionOrder: {}
|
||||
defineConstraints: []
|
||||
isPreloaded: 0
|
||||
isOverridable: 0
|
||||
isExplicitlyReferenced: 0
|
||||
validateReferences: 1
|
||||
platformData:
|
||||
- first:
|
||||
Any:
|
||||
second:
|
||||
enabled: 0
|
||||
settings: {}
|
||||
- first:
|
||||
Editor: Editor
|
||||
second:
|
||||
enabled: 0
|
||||
settings:
|
||||
DefaultValueInitialized: true
|
||||
- first:
|
||||
iPhone: iOS
|
||||
second:
|
||||
enabled: 1
|
||||
settings:
|
||||
AddToEmbeddedBinaries: false
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,28 @@
|
||||
//
|
||||
// TAContext.h
|
||||
// ThinkingSDK.default-Base-Core-Extension-Router-Util-iOS
|
||||
//
|
||||
// Created by wwango on 2022/10/7.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface TAContext : NSObject
|
||||
|
||||
@property(nonatomic, strong) UIApplication *application;
|
||||
|
||||
@property(nonatomic, strong) NSDictionary *launchOptions;
|
||||
|
||||
+ (instancetype)shareInstance;
|
||||
|
||||
- (void)addServiceWithImplInstance:(id)implInstance serviceName:(NSString *)serviceName;
|
||||
|
||||
- (void)removeServiceWithServiceName:(NSString *)serviceName;
|
||||
|
||||
- (id)getServiceInstanceFromServiceName:(NSString *)serviceName;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,33 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3fb65c7bc426bea408d42a6fa8d08306
|
||||
PluginImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
iconMap: {}
|
||||
executionOrder: {}
|
||||
defineConstraints: []
|
||||
isPreloaded: 0
|
||||
isOverridable: 0
|
||||
isExplicitlyReferenced: 0
|
||||
validateReferences: 1
|
||||
platformData:
|
||||
- first:
|
||||
Any:
|
||||
second:
|
||||
enabled: 0
|
||||
settings: {}
|
||||
- first:
|
||||
Editor: Editor
|
||||
second:
|
||||
enabled: 0
|
||||
settings:
|
||||
DefaultValueInitialized: true
|
||||
- first:
|
||||
iPhone: iOS
|
||||
second:
|
||||
enabled: 1
|
||||
settings:
|
||||
AddToEmbeddedBinaries: false
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,68 @@
|
||||
//
|
||||
// TAContext.m
|
||||
// ThinkingSDK.default-Base-Core-Extension-Router-Util-iOS
|
||||
//
|
||||
// Created by wwango on 2022/10/7.
|
||||
//
|
||||
|
||||
#import "TAContext.h"
|
||||
|
||||
@interface TAContext()
|
||||
|
||||
@property(nonatomic, strong) NSMutableDictionary *modulesByName;
|
||||
|
||||
@property(nonatomic, strong) NSMutableDictionary *servicesByName;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@implementation TAContext
|
||||
|
||||
+ (instancetype)shareInstance
|
||||
{
|
||||
static dispatch_once_t p;
|
||||
static id instance = nil;
|
||||
|
||||
dispatch_once(&p, ^{
|
||||
instance = [[[self class] alloc] init];
|
||||
});
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
- (void)addServiceWithImplInstance:(id)implInstance serviceName:(NSString *)serviceName
|
||||
{
|
||||
[[TAContext shareInstance].servicesByName setObject:implInstance forKey:serviceName];
|
||||
}
|
||||
|
||||
- (void)removeServiceWithServiceName:(NSString *)serviceName
|
||||
{
|
||||
[[TAContext shareInstance].servicesByName removeObjectForKey:serviceName];
|
||||
}
|
||||
|
||||
- (id)getServiceInstanceFromServiceName:(NSString *)serviceName
|
||||
{
|
||||
return [[TAContext shareInstance].servicesByName objectForKey:serviceName];
|
||||
}
|
||||
|
||||
- (instancetype)init
|
||||
{
|
||||
self = [super init];
|
||||
if (self) {
|
||||
self.modulesByName = [[NSMutableDictionary alloc] initWithCapacity:1];
|
||||
self.servicesByName = [[NSMutableDictionary alloc] initWithCapacity:1];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (instancetype)copyWithZone:(NSZone *)zone {
|
||||
TAContext *context = [[self.class allocWithZone:zone] init];
|
||||
|
||||
context.application = self.application;
|
||||
context.launchOptions = self.launchOptions;
|
||||
|
||||
return context;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,33 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9e069046b6f695e47a2b4a21fd77e3c1
|
||||
PluginImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
iconMap: {}
|
||||
executionOrder: {}
|
||||
defineConstraints: []
|
||||
isPreloaded: 0
|
||||
isOverridable: 0
|
||||
isExplicitlyReferenced: 0
|
||||
validateReferences: 1
|
||||
platformData:
|
||||
- first:
|
||||
Any:
|
||||
second:
|
||||
enabled: 0
|
||||
settings: {}
|
||||
- first:
|
||||
Editor: Editor
|
||||
second:
|
||||
enabled: 0
|
||||
settings:
|
||||
DefaultValueInitialized: true
|
||||
- first:
|
||||
iPhone: iOS
|
||||
second:
|
||||
enabled: 1
|
||||
settings:
|
||||
AddToEmbeddedBinaries: false
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,72 @@
|
||||
//
|
||||
// TAModuleManager.h
|
||||
// Pods
|
||||
//
|
||||
// Created by wwango on 2022/10/8.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
typedef NS_ENUM(NSUInteger, TAModuleLevel)
|
||||
{
|
||||
TAModuleBasic = 0,
|
||||
TAModuleNormal = 1
|
||||
};
|
||||
|
||||
typedef NS_ENUM(NSInteger, TAModuleEventType)
|
||||
{
|
||||
TAMSetupEvent = 0,
|
||||
TAMInitEvent,
|
||||
TAMTearDownEvent,
|
||||
TAMSplashEvent,
|
||||
TAMQuickActionEvent,
|
||||
TAMWillResignActiveEvent,
|
||||
TAMDidEnterBackgroundEvent,
|
||||
TAMWillEnterForegroundEvent,
|
||||
TAMDidBecomeActiveEvent,
|
||||
TAMWillTerminateEvent,
|
||||
TAMUnmountEvent,
|
||||
TAMOpenURLEvent,
|
||||
TAMDidReceiveMemoryWarningEvent,
|
||||
TAMDidFailToRegisterForRemoteNotificationsEvent,
|
||||
TAMDidRegisterForRemoteNotificationsEvent,
|
||||
TAMDidReceiveRemoteNotificationEvent,
|
||||
TAMDidReceiveLocalNotificationEvent,
|
||||
TAMWillPresentNotificationEvent,
|
||||
TAMDidReceiveNotificationResponseEvent,
|
||||
TAMWillContinueUserActivityEvent,
|
||||
TAMContinueUserActivityEvent,
|
||||
TAMDidFailToContinueUserActivityEvent,
|
||||
TAMDidUpdateUserActivityEvent,
|
||||
TAMDidCustomEvent = 1000
|
||||
|
||||
};
|
||||
|
||||
@interface TAModuleManager : NSObject
|
||||
|
||||
+ (instancetype)sharedManager;
|
||||
|
||||
// If you do not comply with set Level protocol, the default Normal
|
||||
- (void)registerDynamicModule:(Class)moduleClass;
|
||||
|
||||
- (void)unRegisterDynamicModule:(Class)moduleClass;
|
||||
|
||||
- (void)loadLocalModules;
|
||||
|
||||
- (void)registedAllModules;
|
||||
|
||||
- (void)registerCustomEvent:(NSInteger)eventType
|
||||
withModuleInstance:(id)moduleInstance
|
||||
andSelectorStr:(NSString *)selectorStr;
|
||||
|
||||
- (void)triggerEvent:(NSInteger)eventType;
|
||||
|
||||
- (void)triggerEvent:(NSInteger)eventType
|
||||
withCustomParam:(NSDictionary *)customParam;
|
||||
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,33 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4fc15d6474918924c9a46257e5ae21f0
|
||||
PluginImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
iconMap: {}
|
||||
executionOrder: {}
|
||||
defineConstraints: []
|
||||
isPreloaded: 0
|
||||
isOverridable: 0
|
||||
isExplicitlyReferenced: 0
|
||||
validateReferences: 1
|
||||
platformData:
|
||||
- first:
|
||||
Any:
|
||||
second:
|
||||
enabled: 0
|
||||
settings: {}
|
||||
- first:
|
||||
Editor: Editor
|
||||
second:
|
||||
enabled: 0
|
||||
settings:
|
||||
DefaultValueInitialized: true
|
||||
- first:
|
||||
iPhone: iOS
|
||||
second:
|
||||
enabled: 1
|
||||
settings:
|
||||
AddToEmbeddedBinaries: false
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,509 @@
|
||||
//
|
||||
// TAModuleManager.m
|
||||
// Pods
|
||||
//
|
||||
// Created by wwango on 2022/10/8.
|
||||
//
|
||||
|
||||
#import "TAModuleManager.h"
|
||||
#import "TAModuleProtocol.h"
|
||||
#import "TAContext.h"
|
||||
|
||||
#define kTAModuleArrayKey @"moduleClasses"
|
||||
#define kTAModuleInfoNameKey @"moduleClass"
|
||||
#define kTAModuleInfoLevelKey @"moduleLevel"
|
||||
#define kTAModuleInfoPriorityKey @"modulePriority"
|
||||
#define kTAModuleInfoHasInstantiatedKey @"moduleHasInstantiated"
|
||||
|
||||
static NSString *kTASetupSelector = @"modSetUp:";
|
||||
static NSString *kTAInitSelector = @"modInit:";
|
||||
static NSString *kTASplashSeletor = @"modSplash:";
|
||||
static NSString *kTATearDownSelector = @"modTearDown:";
|
||||
static NSString *kTAWillResignActiveSelector = @"modWillResignActive:";
|
||||
static NSString *kTADidEnterBackgroundSelector = @"modDidEnterBackground:";
|
||||
static NSString *kTAWillEnterForegroundSelector = @"modWillEnterForeground:";
|
||||
static NSString *kTADidBecomeActiveSelector = @"modDidBecomeActive:";
|
||||
static NSString *kTAWillTerminateSelector = @"modWillTerminate:";
|
||||
static NSString *kTAUnmountEventSelector = @"modUnmount:";
|
||||
static NSString *kTAQuickActionSelector = @"modQuickAction:";
|
||||
static NSString *kTAOpenURLSelector = @"modOpenURL:";
|
||||
static NSString *kTADidReceiveMemoryWarningSelector = @"modDidReceiveMemoryWaring:";
|
||||
static NSString *kTAFailToRegisterForRemoteNotificationsSelector = @"modDidFailToRegisterForRemoteNotifications:";
|
||||
static NSString *kTADidRegisterForRemoteNotificationsSelector = @"modDidRegisterForRemoteNotifications:";
|
||||
static NSString *kTADidReceiveRemoteNotificationsSelector = @"modDidReceiveRemoteNotification:";
|
||||
static NSString *kTADidReceiveLocalNotificationsSelector = @"modDidReceiveLocalNotification:";
|
||||
static NSString *kTAWillPresentNotificationSelector = @"modWillPresentNotification:";
|
||||
static NSString *kTADidReceiveNotificationResponseSelector = @"modDidReceiveNotificationResponse:";
|
||||
static NSString *kTAWillContinueUserActivitySelector = @"modWillContinueUserActivity:";
|
||||
static NSString *kTAContinueUserActivitySelector = @"modContinueUserActivity:";
|
||||
static NSString *kTADidUpdateContinueUserActivitySelector = @"modDidUpdateContinueUserActivity:";
|
||||
static NSString *kTAFailToContinueUserActivitySelector = @"modDidFailToContinueUserActivity:";
|
||||
static NSString *kTAHandleWatchKitExtensionRequestSelector = @"modHandleWatchKitExtensionRequest:";
|
||||
static NSString *kTAAppCustomSelector = @"modDidCustomEvent:";
|
||||
|
||||
|
||||
@interface TAModuleManager ()
|
||||
|
||||
@property(nonatomic, strong) NSMutableArray *TAModuleDynamicClasses;
|
||||
|
||||
@property(nonatomic, strong) NSMutableArray<NSDictionary *> *TAModuleInfos;
|
||||
@property(nonatomic, strong) NSMutableArray *TAModules;
|
||||
|
||||
@property(nonatomic, strong) NSMutableDictionary<NSNumber *, NSMutableArray<id<TAModuleProtocol>> *> *TAModulesByEvent;
|
||||
@property(nonatomic, strong) NSMutableDictionary<NSNumber *, NSString *> *TASelectorByEvent;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@implementation TAModuleManager
|
||||
|
||||
|
||||
+ (instancetype)sharedManager
|
||||
{
|
||||
static id sharedManager = nil;
|
||||
static dispatch_once_t onceToken = 0;
|
||||
dispatch_once(&onceToken, ^{
|
||||
sharedManager = [[TAModuleManager alloc] init];
|
||||
});
|
||||
return sharedManager;
|
||||
}
|
||||
|
||||
- (void)loadLocalModules
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
- (void)registerDynamicModule:(Class)moduleClass
|
||||
{
|
||||
[self addModuleFromObject:moduleClass];
|
||||
}
|
||||
|
||||
- (void)unRegisterDynamicModule:(Class)moduleClass {
|
||||
if (!moduleClass) {
|
||||
return;
|
||||
}
|
||||
[self.TAModuleInfos filterUsingPredicate:[NSPredicate predicateWithFormat:@"%@!=%@", kTAModuleInfoNameKey, NSStringFromClass(moduleClass)]];
|
||||
__block NSInteger index = -1;
|
||||
[self.TAModules enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
|
||||
if ([obj isKindOfClass:moduleClass]) {
|
||||
index = idx;
|
||||
*stop = YES;
|
||||
}
|
||||
}];
|
||||
if (index >= 0) {
|
||||
[self.TAModules removeObjectAtIndex:index];
|
||||
}
|
||||
[self.TAModulesByEvent enumerateKeysAndObjectsUsingBlock:^(NSNumber * _Nonnull key, NSMutableArray<id<TAModuleProtocol>> * _Nonnull obj, BOOL * _Nonnull stop) {
|
||||
__block NSInteger index = -1;
|
||||
[obj enumerateObjectsUsingBlock:^(id<TAModuleProtocol> _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
|
||||
if ([obj isKindOfClass:moduleClass]) {
|
||||
index = idx;
|
||||
*stop = NO;
|
||||
}
|
||||
}];
|
||||
if (index >= 0) {
|
||||
[obj removeObjectAtIndex:index];
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)registedAllModules
|
||||
{
|
||||
[self.TAModuleInfos sortUsingComparator:^NSComparisonResult(NSDictionary *module1, NSDictionary *module2) {
|
||||
NSNumber *module1Level = (NSNumber *)[module1 objectForKey:kTAModuleInfoLevelKey];
|
||||
NSNumber *module2Level = (NSNumber *)[module2 objectForKey:kTAModuleInfoLevelKey];
|
||||
if (module1Level.integerValue != module2Level.integerValue) {
|
||||
return module1Level.integerValue > module2Level.integerValue;
|
||||
} else {
|
||||
NSNumber *module1Priority = (NSNumber *)[module1 objectForKey:kTAModuleInfoPriorityKey];
|
||||
NSNumber *module2Priority = (NSNumber *)[module2 objectForKey:kTAModuleInfoPriorityKey];
|
||||
return module1Priority.integerValue < module2Priority.integerValue;
|
||||
}
|
||||
}];
|
||||
|
||||
NSMutableArray *tmpArray = [NSMutableArray array];
|
||||
|
||||
//module init
|
||||
[self.TAModuleInfos enumerateObjectsUsingBlock:^(NSDictionary *module, NSUInteger idx, BOOL * _Nonnull stop) {
|
||||
|
||||
NSString *classStr = [module objectForKey:kTAModuleInfoNameKey];
|
||||
|
||||
Class moduleClass = NSClassFromString(classStr);
|
||||
BOOL hasInstantiated = ((NSNumber *)[module objectForKey:kTAModuleInfoHasInstantiatedKey]).boolValue;
|
||||
if (NSStringFromClass(moduleClass) && !hasInstantiated) {
|
||||
id<TAModuleProtocol> moduleInstance = [[moduleClass alloc] init];
|
||||
[tmpArray addObject:moduleInstance];
|
||||
}
|
||||
|
||||
}];
|
||||
|
||||
// [self.BHModules removeAllObjects];
|
||||
|
||||
[self.TAModules addObjectsFromArray:tmpArray];
|
||||
|
||||
[self registerAllSystemEvents];
|
||||
}
|
||||
|
||||
- (void)registerCustomEvent:(NSInteger)eventType
|
||||
withModuleInstance:(id)moduleInstance
|
||||
andSelectorStr:(NSString *)selectorStr {
|
||||
if (eventType < 1000) {
|
||||
return;
|
||||
}
|
||||
[self registerEvent:eventType withModuleInstance:moduleInstance andSelectorStr:selectorStr];
|
||||
}
|
||||
|
||||
- (void)triggerEvent:(NSInteger)eventType
|
||||
{
|
||||
[self triggerEvent:eventType withCustomParam:nil];
|
||||
}
|
||||
|
||||
- (void)triggerEvent:(NSInteger)eventType
|
||||
withCustomParam:(NSDictionary *)customParam {
|
||||
[self handleModuleEvent:eventType forTarget:nil withCustomParam:customParam];
|
||||
}
|
||||
|
||||
#pragma mark - life loop
|
||||
|
||||
- (instancetype)init
|
||||
{
|
||||
self = [super init];
|
||||
if (self) {
|
||||
self.TAModuleDynamicClasses = [NSMutableArray array];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
|
||||
#pragma mark - private
|
||||
|
||||
- (TAModuleLevel)checkModuleLevel:(NSUInteger)level
|
||||
{
|
||||
switch (level) {
|
||||
case 0:
|
||||
return TAModuleBasic;
|
||||
break;
|
||||
case 1:
|
||||
return TAModuleNormal;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
//default normal
|
||||
return TAModuleNormal;
|
||||
}
|
||||
|
||||
|
||||
- (void)addModuleFromObject:(id)object
|
||||
{
|
||||
Class class;
|
||||
NSString *moduleName = nil;
|
||||
|
||||
if (object) {
|
||||
class = object;
|
||||
moduleName = NSStringFromClass(class);
|
||||
} else {
|
||||
return ;
|
||||
}
|
||||
|
||||
__block BOOL flag = YES;
|
||||
[self.TAModules enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
|
||||
if ([obj isKindOfClass:class]) {
|
||||
flag = NO;
|
||||
*stop = YES;
|
||||
}
|
||||
}];
|
||||
if (!flag) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ([class conformsToProtocol:@protocol(TAModuleProtocol)]) {
|
||||
NSMutableDictionary *moduleInfo = [NSMutableDictionary dictionary];
|
||||
|
||||
BOOL responseBasicLevel = [class instancesRespondToSelector:@selector(basicModuleLevel)];
|
||||
|
||||
int levelInt = 1;
|
||||
|
||||
if (responseBasicLevel) {
|
||||
levelInt = 0;
|
||||
}
|
||||
|
||||
[moduleInfo setObject:@(levelInt) forKey:kTAModuleInfoLevelKey];
|
||||
if (moduleName) {
|
||||
[moduleInfo setObject:moduleName forKey:kTAModuleInfoNameKey];
|
||||
}
|
||||
|
||||
[self.TAModuleInfos addObject:moduleInfo];
|
||||
|
||||
id<TAModuleProtocol> moduleInstance = [[class alloc] init];
|
||||
[self.TAModules addObject:moduleInstance];
|
||||
[moduleInfo setObject:@(YES) forKey:kTAModuleInfoHasInstantiatedKey];
|
||||
[self.TAModules sortUsingComparator:^NSComparisonResult(id<TAModuleProtocol> moduleInstance1, id<TAModuleProtocol> moduleInstance2) {
|
||||
NSNumber *module1Level = @(TAModuleNormal);
|
||||
NSNumber *module2Level = @(TAModuleNormal);
|
||||
if ([moduleInstance1 respondsToSelector:@selector(basicModuleLevel)]) {
|
||||
module1Level = @(TAModuleBasic);
|
||||
}
|
||||
if ([moduleInstance2 respondsToSelector:@selector(basicModuleLevel)]) {
|
||||
module2Level = @(TAModuleBasic);
|
||||
}
|
||||
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];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)registerAllSystemEvents
|
||||
{
|
||||
[self.TAModules enumerateObjectsUsingBlock:^(id<TAModuleProtocol> moduleInstance, NSUInteger idx, BOOL * _Nonnull stop) {
|
||||
[self registerEventsByModuleInstance:moduleInstance];
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)registerEventsByModuleInstance:(id<TAModuleProtocol>)moduleInstance
|
||||
{
|
||||
NSArray<NSNumber *> *events = self.TASelectorByEvent.allKeys;
|
||||
[events enumerateObjectsUsingBlock:^(NSNumber * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
|
||||
[self registerEvent:obj.integerValue withModuleInstance:moduleInstance andSelectorStr:self.TASelectorByEvent[obj]];
|
||||
}];
|
||||
}
|
||||
|
||||
- (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.TASelectorByEvent[eventTypeNumber]) {
|
||||
[self.TASelectorByEvent setObject:selectorStr forKey:eventTypeNumber];
|
||||
}
|
||||
if (!self.TAModulesByEvent[eventTypeNumber]) {
|
||||
[self.TAModulesByEvent setObject:@[].mutableCopy forKey:eventTypeNumber];
|
||||
}
|
||||
NSMutableArray *eventModules = [self.TAModulesByEvent objectForKey:eventTypeNumber];
|
||||
if (![eventModules containsObject:moduleInstance]) {
|
||||
[eventModules addObject:moduleInstance];
|
||||
[eventModules sortUsingComparator:^NSComparisonResult(id<TAModuleProtocol> moduleInstance1, id<TAModuleProtocol> moduleInstance2) {
|
||||
NSNumber *module1Level = @(TAModuleNormal);
|
||||
NSNumber *module2Level = @(TAModuleNormal);
|
||||
if ([moduleInstance1 respondsToSelector:@selector(basicModuleLevel)]) {
|
||||
module1Level = @(TAModuleBasic);
|
||||
}
|
||||
if ([moduleInstance2 respondsToSelector:@selector(basicModuleLevel)]) {
|
||||
module2Level = @(TAModuleBasic);
|
||||
}
|
||||
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;
|
||||
}
|
||||
}];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#pragma mark - property setter or getter
|
||||
- (NSMutableArray<NSDictionary *> *)TAModuleInfos {
|
||||
if (!_TAModuleInfos) {
|
||||
_TAModuleInfos = @[].mutableCopy;
|
||||
}
|
||||
return _TAModuleInfos;
|
||||
}
|
||||
|
||||
- (NSMutableArray *)TAModules
|
||||
{
|
||||
if (!_TAModules) {
|
||||
_TAModules = [NSMutableArray array];
|
||||
}
|
||||
return _TAModules;
|
||||
}
|
||||
|
||||
- (NSMutableDictionary<NSNumber *, NSMutableArray<id<TAModuleProtocol>> *> *)TAModulesByEvent
|
||||
{
|
||||
if (!_TAModulesByEvent) {
|
||||
_TAModulesByEvent = @{}.mutableCopy;
|
||||
}
|
||||
return _TAModulesByEvent;
|
||||
}
|
||||
|
||||
- (NSMutableDictionary<NSNumber *, NSString *> *)TASelectorByEvent
|
||||
{
|
||||
if (!_TASelectorByEvent) {
|
||||
_TASelectorByEvent = @{
|
||||
@(TAMSetupEvent):kTASetupSelector,
|
||||
@(TAMInitEvent):kTAInitSelector,
|
||||
@(TAMTearDownEvent):kTATearDownSelector,
|
||||
@(TAMSplashEvent):kTASplashSeletor,
|
||||
@(TAMWillResignActiveEvent):kTAWillResignActiveSelector,
|
||||
@(TAMDidEnterBackgroundEvent):kTADidEnterBackgroundSelector,
|
||||
@(TAMWillEnterForegroundEvent):kTAWillEnterForegroundSelector,
|
||||
@(TAMDidBecomeActiveEvent):kTADidBecomeActiveSelector,
|
||||
@(TAMWillTerminateEvent):kTAWillTerminateSelector,
|
||||
@(TAMUnmountEvent):kTAUnmountEventSelector,
|
||||
@(TAMOpenURLEvent):kTAOpenURLSelector,
|
||||
@(TAMDidReceiveMemoryWarningEvent):kTADidReceiveMemoryWarningSelector,
|
||||
|
||||
@(TAMDidReceiveRemoteNotificationEvent):kTADidReceiveRemoteNotificationsSelector,
|
||||
@(TAMWillPresentNotificationEvent):kTAWillPresentNotificationSelector,
|
||||
@(TAMDidReceiveNotificationResponseEvent):kTADidReceiveNotificationResponseSelector,
|
||||
|
||||
@(TAMDidFailToRegisterForRemoteNotificationsEvent):kTAFailToRegisterForRemoteNotificationsSelector,
|
||||
@(TAMDidRegisterForRemoteNotificationsEvent):kTADidRegisterForRemoteNotificationsSelector,
|
||||
|
||||
@(TAMDidReceiveLocalNotificationEvent):kTADidReceiveLocalNotificationsSelector,
|
||||
|
||||
@(TAMWillContinueUserActivityEvent):kTAWillContinueUserActivitySelector,
|
||||
|
||||
@(TAMContinueUserActivityEvent):kTAContinueUserActivitySelector,
|
||||
|
||||
@(TAMDidFailToContinueUserActivityEvent):kTAFailToContinueUserActivitySelector,
|
||||
|
||||
@(TAMDidUpdateUserActivityEvent):kTADidUpdateContinueUserActivitySelector,
|
||||
|
||||
@(TAMQuickActionEvent):kTAQuickActionSelector,
|
||||
@(TAMDidCustomEvent):kTAAppCustomSelector,
|
||||
}.mutableCopy;
|
||||
}
|
||||
return _TASelectorByEvent;
|
||||
}
|
||||
|
||||
#pragma mark - module protocol
|
||||
- (void)handleModuleEvent:(NSInteger)eventType
|
||||
forTarget:(id<TAModuleProtocol>)target
|
||||
withCustomParam:(NSDictionary *)customParam
|
||||
{
|
||||
switch (eventType) {
|
||||
case TAMInitEvent:
|
||||
//special
|
||||
[self handleModulesInitEventForTarget:nil withCustomParam :customParam];
|
||||
break;
|
||||
case TAMTearDownEvent:
|
||||
//special
|
||||
[self handleModulesTearDownEventForTarget:nil withCustomParam:customParam];
|
||||
break;
|
||||
default: {
|
||||
NSString *selectorStr = [self.TASelectorByEvent objectForKey:@(eventType)];
|
||||
[self handleModuleEvent:eventType forTarget:nil withSeletorStr:selectorStr andCustomParam:customParam];
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
- (void)handleModulesInitEventForTarget:(id<TAModuleProtocol>)target
|
||||
withCustomParam:(NSDictionary *)customParam
|
||||
{
|
||||
TAContext *context = [TAContext shareInstance].copy;
|
||||
|
||||
NSArray<id<TAModuleProtocol>> *moduleInstances;
|
||||
if (target) {
|
||||
moduleInstances = @[target];
|
||||
} else {
|
||||
moduleInstances = [self.TAModulesByEvent objectForKey:@(TAMInitEvent)];
|
||||
}
|
||||
|
||||
[moduleInstances enumerateObjectsUsingBlock:^(id<TAModuleProtocol> moduleInstance, NSUInteger idx, BOOL * _Nonnull stop) {
|
||||
__weak __typeof(&*self) wself = self;
|
||||
void ( ^ bk )(void);
|
||||
bk = ^(){
|
||||
__strong __typeof(&*self) sself = wself;
|
||||
if (sself) {
|
||||
if ([moduleInstance respondsToSelector:@selector(modInit:)]) {
|
||||
[moduleInstance modInit:context];
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if ([moduleInstance respondsToSelector:@selector(async)]) {
|
||||
BOOL async = [moduleInstance async];
|
||||
|
||||
if (async) {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
bk();
|
||||
});
|
||||
|
||||
} else {
|
||||
bk();
|
||||
}
|
||||
} else {
|
||||
bk();
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)handleModulesTearDownEventForTarget:(id<TAModuleProtocol>)target
|
||||
withCustomParam:(NSDictionary *)customParam
|
||||
{
|
||||
TAContext *context = [TAContext shareInstance].copy;
|
||||
|
||||
NSArray<id<TAModuleProtocol>> *moduleInstances;
|
||||
if (target) {
|
||||
moduleInstances = @[target];
|
||||
} else {
|
||||
moduleInstances = [self.TAModulesByEvent objectForKey:@(TAMTearDownEvent)];
|
||||
}
|
||||
|
||||
//Reverse Order to unload
|
||||
for (int i = (int)moduleInstances.count - 1; i >= 0; i--) {
|
||||
id<TAModuleProtocol> moduleInstance = [moduleInstances objectAtIndex:i];
|
||||
if (moduleInstance && [moduleInstance respondsToSelector:@selector(modTearDown:)]) {
|
||||
[moduleInstance modTearDown:context];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
- (void)handleModuleEvent:(NSInteger)eventType
|
||||
forTarget:(id<TAModuleProtocol>)target
|
||||
withSeletorStr:(NSString *)selectorStr
|
||||
andCustomParam:(NSDictionary *)customParam
|
||||
{
|
||||
TAContext *context = [TAContext shareInstance].copy;
|
||||
if (!selectorStr.length) {
|
||||
selectorStr = [self.TASelectorByEvent objectForKey:@(eventType)];
|
||||
}
|
||||
SEL seletor = NSSelectorFromString(selectorStr);
|
||||
if (!seletor) {
|
||||
selectorStr = [self.TASelectorByEvent objectForKey:@(eventType)];
|
||||
seletor = NSSelectorFromString(selectorStr);
|
||||
}
|
||||
NSArray<id<TAModuleProtocol>> *moduleInstances;
|
||||
if (target) {
|
||||
moduleInstances = @[target];
|
||||
} else {
|
||||
moduleInstances = [self.TAModulesByEvent objectForKey:@(eventType)];
|
||||
}
|
||||
[moduleInstances enumerateObjectsUsingBlock:^(id<TAModuleProtocol> 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
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,33 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5780a9102f98b034ca5013e5ccdd638d
|
||||
PluginImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
iconMap: {}
|
||||
executionOrder: {}
|
||||
defineConstraints: []
|
||||
isPreloaded: 0
|
||||
isOverridable: 0
|
||||
isExplicitlyReferenced: 0
|
||||
validateReferences: 1
|
||||
platformData:
|
||||
- first:
|
||||
Any:
|
||||
second:
|
||||
enabled: 0
|
||||
settings: {}
|
||||
- first:
|
||||
Editor: Editor
|
||||
second:
|
||||
enabled: 0
|
||||
settings:
|
||||
DefaultValueInitialized: true
|
||||
- first:
|
||||
iPhone: iOS
|
||||
second:
|
||||
enabled: 1
|
||||
settings:
|
||||
AddToEmbeddedBinaries: false
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,81 @@
|
||||
//
|
||||
// TAModuleProtocol.h
|
||||
// ThinkingSDK.default-Base-Core-Extension-Router-Util-iOS
|
||||
//
|
||||
// Created by wwango on 2022/10/7.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#define TA_EXPORT_MODULE(isAsync) \
|
||||
+ (void)load { [[TAModuleManager sharedManager] registerDynamicModule:[self class]]; } \
|
||||
-(BOOL)async { return [[NSString stringWithUTF8String:#isAsync] boolValue];}
|
||||
|
||||
@class TAContext;
|
||||
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@protocol TAModuleProtocol <NSObject>
|
||||
|
||||
@optional
|
||||
|
||||
- (void)basicModuleLevel;
|
||||
|
||||
- (NSInteger)modulePriority;
|
||||
|
||||
- (BOOL)async;
|
||||
|
||||
- (void)modSetUp:(TAContext *)context;
|
||||
|
||||
- (void)modInit:(TAContext *)context;
|
||||
|
||||
- (void)modSplash:(TAContext *)context;
|
||||
|
||||
- (void)modQuickAction:(TAContext *)context;
|
||||
|
||||
- (void)modTearDown:(TAContext *)context;
|
||||
|
||||
- (void)modWillResignActive:(TAContext *)context;
|
||||
|
||||
- (void)modDidEnterBackground:(TAContext *)context;
|
||||
|
||||
- (void)modWillEnterForeground:(TAContext *)context;
|
||||
|
||||
- (void)modDidBecomeActive:(TAContext *)context;
|
||||
|
||||
- (void)modWillTerminate:(TAContext *)context;
|
||||
|
||||
- (void)modUnmount:(TAContext *)context;
|
||||
|
||||
- (void)modOpenURL:(TAContext *)context;
|
||||
|
||||
- (void)modDidReceiveMemoryWaring:(TAContext *)context;
|
||||
|
||||
- (void)modDidFailToRegisterForRemoteNotifications:(TAContext *)context;
|
||||
|
||||
- (void)modDidRegisterForRemoteNotifications:(TAContext *)context;
|
||||
|
||||
- (void)modDidReceiveRemoteNotification:(TAContext *)context;
|
||||
|
||||
- (void)modDidReceiveLocalNotification:(TAContext *)context;
|
||||
|
||||
- (void)modWillPresentNotification:(TAContext *)context;
|
||||
|
||||
- (void)modDidReceiveNotificationResponse:(TAContext *)context;
|
||||
|
||||
- (void)modWillContinueUserActivity:(TAContext *)context;
|
||||
|
||||
- (void)modContinueUserActivity:(TAContext *)context;
|
||||
|
||||
- (void)modDidFailToContinueUserActivity:(TAContext *)context;
|
||||
|
||||
- (void)modDidUpdateContinueUserActivity:(TAContext *)context;
|
||||
|
||||
- (void)modHandleWatchKitExtensionRequest:(TAContext *)context;
|
||||
|
||||
- (void)modDidCustomEvent:(TAContext *)context;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,33 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 808489b244a0e334894811c9401825ef
|
||||
PluginImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
iconMap: {}
|
||||
executionOrder: {}
|
||||
defineConstraints: []
|
||||
isPreloaded: 0
|
||||
isOverridable: 0
|
||||
isExplicitlyReferenced: 0
|
||||
validateReferences: 1
|
||||
platformData:
|
||||
- first:
|
||||
Any:
|
||||
second:
|
||||
enabled: 0
|
||||
settings: {}
|
||||
- first:
|
||||
Editor: Editor
|
||||
second:
|
||||
enabled: 0
|
||||
settings:
|
||||
DefaultValueInitialized: true
|
||||
- first:
|
||||
iPhone: iOS
|
||||
second:
|
||||
enabled: 1
|
||||
settings:
|
||||
AddToEmbeddedBinaries: false
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,38 @@
|
||||
//
|
||||
// TARouter.h
|
||||
// Pods
|
||||
//
|
||||
// Created by wwango on 2022/10/8.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
static NSString *const TARURLSchemeGlobalKey = @"URLGlobalScheme";
|
||||
static NSString *const TARURLHostCallService = @"call.service.thinkingdata";
|
||||
static NSString *const TARURLHostRegister = @"register.thinking";
|
||||
static NSString *const TARURLSubPathSplitPattern = @".";
|
||||
static NSString *const TARURLQueryParamsKey = @"params";
|
||||
|
||||
typedef void(^TARPathComponentCustomHandler)(NSDictionary<NSString *, id> *params);
|
||||
|
||||
@interface TARouter : NSObject
|
||||
|
||||
- (instancetype)init NS_UNAVAILABLE;
|
||||
+ (instancetype)new NS_UNAVAILABLE;
|
||||
|
||||
+ (instancetype)globalRouter;
|
||||
+ (instancetype)routerForScheme:(NSString *)scheme;
|
||||
|
||||
//url - > com.thinkingdata://call.service/pathComponentKey.protocolName.selector/...?params={}(value url encode)
|
||||
+ (BOOL)canOpenURL:(NSURL *)URL;
|
||||
+ (BOOL)openURL:(NSURL *)URL;
|
||||
+ (BOOL)openURL:(NSURL *)URL
|
||||
withParams:(NSDictionary<NSString *, NSDictionary<NSString *, id> *> *)params;
|
||||
+ (BOOL)openURL:(NSURL *)URL
|
||||
withParams:(NSDictionary<NSString *, NSDictionary<NSString *, id> *> *)params
|
||||
andThen:(void(^)(NSString *pathComponentKey, id obj, id returnValue))then;
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,33 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1f7c9241ac875a84193c88e3627c3b40
|
||||
PluginImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
iconMap: {}
|
||||
executionOrder: {}
|
||||
defineConstraints: []
|
||||
isPreloaded: 0
|
||||
isOverridable: 0
|
||||
isExplicitlyReferenced: 0
|
||||
validateReferences: 1
|
||||
platformData:
|
||||
- first:
|
||||
Any:
|
||||
second:
|
||||
enabled: 0
|
||||
settings: {}
|
||||
- first:
|
||||
Editor: Editor
|
||||
second:
|
||||
enabled: 0
|
||||
settings:
|
||||
DefaultValueInitialized: true
|
||||
- first:
|
||||
iPhone: iOS
|
||||
second:
|
||||
enabled: 1
|
||||
settings:
|
||||
AddToEmbeddedBinaries: false
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,491 @@
|
||||
//
|
||||
// TARouter.m
|
||||
// Pods
|
||||
//
|
||||
// Created by wwango on 2022/10/8.
|
||||
//
|
||||
|
||||
#import "TARouter.h"
|
||||
#import "TAServiceProtocol.h"
|
||||
#import "TAServiceManager.h"
|
||||
#import <objc/runtime.h>
|
||||
|
||||
@interface NSObject (TARetType)
|
||||
|
||||
+ (id)bh_getReturnFromInv:(NSInvocation *)inv withSig:(NSMethodSignature *)sig;
|
||||
|
||||
@end
|
||||
|
||||
@implementation NSObject (TARetType)
|
||||
|
||||
+ (id)bh_getReturnFromInv:(NSInvocation *)inv withSig:(NSMethodSignature *)sig {
|
||||
NSUInteger length = [sig methodReturnLength];
|
||||
if (length == 0) return nil;
|
||||
|
||||
char *type = (char *)[sig methodReturnType];
|
||||
while (*type == 'r' || // const
|
||||
*type == 'n' || // in
|
||||
*type == 'N' || // inout
|
||||
*type == 'o' || // out
|
||||
*type == 'O' || // bycopy
|
||||
*type == 'R' || // byref
|
||||
*type == 'V') { // oneway
|
||||
type++; // cutoff useless prefix
|
||||
}
|
||||
|
||||
#define ta_return_with_number(_type_) \
|
||||
do { \
|
||||
_type_ ret; \
|
||||
[inv getReturnValue:&ret]; \
|
||||
return @(ret); \
|
||||
} while (0)
|
||||
|
||||
switch (*type) {
|
||||
case 'v': return nil; // void
|
||||
case 'B': ta_return_with_number(bool);
|
||||
case 'c': ta_return_with_number(char);
|
||||
case 'C': ta_return_with_number(unsigned char);
|
||||
case 's': ta_return_with_number(short);
|
||||
case 'S': ta_return_with_number(unsigned short);
|
||||
case 'i': ta_return_with_number(int);
|
||||
case 'I': ta_return_with_number(unsigned int);
|
||||
case 'l': ta_return_with_number(int);
|
||||
case 'L': ta_return_with_number(unsigned int);
|
||||
case 'q': ta_return_with_number(long long);
|
||||
case 'Q': ta_return_with_number(unsigned long long);
|
||||
case 'f': ta_return_with_number(float);
|
||||
case 'd': ta_return_with_number(double);
|
||||
case 'D': { // long double
|
||||
long double ret;
|
||||
[inv getReturnValue:&ret];
|
||||
return [NSNumber numberWithDouble:ret];
|
||||
};
|
||||
|
||||
case '@': { // id
|
||||
id ret = nil;
|
||||
[inv getReturnValue:&ret];
|
||||
return ret;
|
||||
};
|
||||
|
||||
case '#': { // Class
|
||||
Class ret = nil;
|
||||
[inv getReturnValue:&ret];
|
||||
return ret;
|
||||
};
|
||||
|
||||
default: { // struct / union / SEL / void* / unknown
|
||||
const char *objCType = [sig methodReturnType];
|
||||
char *buf = calloc(1, length);
|
||||
if (!buf) return nil;
|
||||
[inv getReturnValue:buf];
|
||||
NSValue *value = [NSValue valueWithBytes:buf objCType:objCType];
|
||||
free(buf);
|
||||
return value;
|
||||
};
|
||||
}
|
||||
#undef ta_return_with_number
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
static NSString *const TARClassRegex = @"(?<=T@\")(.*)(?=\",)";
|
||||
|
||||
|
||||
typedef NS_ENUM(NSUInteger, TARUsage) {
|
||||
TARUsageUnknown,
|
||||
TARUsageCallService,
|
||||
};
|
||||
|
||||
|
||||
static NSMutableDictionary<NSString *, TARouter *> *routerByScheme = nil;
|
||||
|
||||
|
||||
@interface TARPathComponent : NSObject
|
||||
|
||||
@property (nonatomic, copy) NSString *key;
|
||||
@property (nonatomic, strong) Class mClass;
|
||||
@property (nonatomic, copy) NSDictionary<NSString *, id> *params;
|
||||
@property (nonatomic, copy) TARPathComponentCustomHandler handler;
|
||||
|
||||
@end
|
||||
|
||||
@implementation TARPathComponent
|
||||
|
||||
@end
|
||||
|
||||
static NSString *TARURLGlobalScheme = nil;
|
||||
|
||||
@interface TARouter ()
|
||||
|
||||
@property (nonatomic, strong) NSMutableDictionary<NSString *, TARPathComponent *> *pathComponentByKey;
|
||||
@property (nonatomic, copy) NSString *scheme;
|
||||
|
||||
@end
|
||||
|
||||
@implementation TARouter
|
||||
|
||||
#pragma mark - property init
|
||||
- (NSMutableDictionary<NSString *, TARPathComponent *> *)pathComponentByKey {
|
||||
if (!_pathComponentByKey) {
|
||||
_pathComponentByKey = @{}.mutableCopy;
|
||||
}
|
||||
return _pathComponentByKey;
|
||||
}
|
||||
|
||||
#pragma mark - router init
|
||||
|
||||
+ (instancetype)globalRouter
|
||||
{
|
||||
if (!TARURLGlobalScheme) {
|
||||
TARURLGlobalScheme = @"com.thinkingdata";
|
||||
}
|
||||
return [self routerForScheme:TARURLGlobalScheme];
|
||||
}
|
||||
+ (instancetype)routerForScheme:(NSString *)scheme
|
||||
{
|
||||
if (!scheme.length) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
TARouter *router = nil;
|
||||
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
routerByScheme = @{}.mutableCopy;
|
||||
});
|
||||
|
||||
if (!routerByScheme[scheme]) {
|
||||
router = [[self alloc] init];
|
||||
router.scheme = scheme;
|
||||
[routerByScheme setObject:router forKey:scheme];
|
||||
} else {
|
||||
router = [routerByScheme objectForKey:scheme];
|
||||
}
|
||||
|
||||
return router;
|
||||
}
|
||||
|
||||
+ (void)unRegisterRouterForScheme:(NSString *)scheme
|
||||
{
|
||||
if (!scheme.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
[routerByScheme removeObjectForKey:scheme];
|
||||
}
|
||||
+ (void)unRegisterAllRouters
|
||||
{
|
||||
[routerByScheme removeAllObjects];
|
||||
}
|
||||
|
||||
- (void)addPathComponent:(NSString *)pathComponentKey
|
||||
forClass:(Class)mClass
|
||||
{
|
||||
[self addPathComponent:pathComponentKey forClass:mClass handler:nil];
|
||||
}
|
||||
//handler is a custom module or service init function
|
||||
- (void)addPathComponent:(NSString *)pathComponentKey
|
||||
forClass:(Class)mClass
|
||||
handler:(TARPathComponentCustomHandler)handler
|
||||
{
|
||||
TARPathComponent *pathComponent = [[TARPathComponent alloc] init];
|
||||
pathComponent.key = pathComponentKey;
|
||||
pathComponent.mClass = mClass;
|
||||
pathComponent.handler = handler;
|
||||
[self.pathComponentByKey setObject:pathComponent forKey:pathComponentKey];
|
||||
}
|
||||
- (void)removePathComponent:(NSString *)pathComponentKey
|
||||
{
|
||||
[self.pathComponentByKey removeObjectForKey:pathComponentKey];
|
||||
}
|
||||
|
||||
+ (BOOL)canOpenURL:(NSURL *)URL
|
||||
{
|
||||
if (!URL) {
|
||||
return NO;
|
||||
}
|
||||
NSString *scheme = URL.scheme;
|
||||
if (!scheme.length) {
|
||||
return NO;
|
||||
}
|
||||
|
||||
NSString *host = URL.host;
|
||||
TARUsage usage = [self usage:host];
|
||||
if (usage == TARUsageUnknown) {
|
||||
return NO;
|
||||
}
|
||||
|
||||
TARouter *router = [self routerForScheme:scheme];
|
||||
|
||||
NSArray<NSString *> *pathComponents = URL.pathComponents;
|
||||
|
||||
__block BOOL flag = YES;
|
||||
|
||||
[pathComponents enumerateObjectsUsingBlock:^(NSString * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
|
||||
NSArray<NSString *> * subPaths = [obj componentsSeparatedByString:TARURLSubPathSplitPattern];
|
||||
|
||||
if ([subPaths.firstObject isEqualToString:@"/"]) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!subPaths.count) {
|
||||
flag = NO;
|
||||
*stop = NO;
|
||||
return;
|
||||
}
|
||||
NSString *pathComponentKey = subPaths.firstObject;
|
||||
|
||||
|
||||
if (router.pathComponentByKey[pathComponentKey]) {
|
||||
return;
|
||||
}
|
||||
Class mClass = NSClassFromString(pathComponentKey);
|
||||
if (!mClass) {
|
||||
flag = NO;
|
||||
*stop = NO;
|
||||
return;
|
||||
}
|
||||
switch (usage) {
|
||||
case TARUsageCallService: {
|
||||
if (subPaths.count < 3) {
|
||||
flag = NO;
|
||||
*stop = NO;
|
||||
return;
|
||||
}
|
||||
NSString *protocolStr = subPaths[1];
|
||||
NSString *selectorStr = subPaths[2];
|
||||
Protocol *protocol = NSProtocolFromString(protocolStr);
|
||||
SEL selector = NSSelectorFromString(selectorStr);
|
||||
if (!protocol ||
|
||||
!selector ||
|
||||
![mClass conformsToProtocol:protocol] ||
|
||||
![mClass instancesRespondToSelector:selector]) {
|
||||
flag = NO;
|
||||
*stop = NO;
|
||||
return;
|
||||
}
|
||||
} break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}];
|
||||
|
||||
return flag;
|
||||
}
|
||||
|
||||
|
||||
+ (BOOL)openURL:(NSURL *)URL
|
||||
{
|
||||
return [self openURL:URL withParams:nil andThen:nil];
|
||||
}
|
||||
+ (BOOL)openURL:(NSURL *)URL
|
||||
withParams:(NSDictionary<NSString *, NSDictionary<NSString *, id> *> *)params
|
||||
{
|
||||
return [self openURL:URL withParams:params andThen:nil];
|
||||
}
|
||||
+ (BOOL)openURL:(NSURL *)URL
|
||||
withParams:(NSDictionary<NSString *, NSDictionary<NSString *, id> *> *)params
|
||||
andThen:(void(^)(NSString *pathComponentKey, id obj, id returnValue))then
|
||||
{
|
||||
if (![self canOpenURL:URL]) {
|
||||
return NO;
|
||||
}
|
||||
|
||||
NSString *scheme = URL.scheme;
|
||||
TARouter *router = [self routerForScheme:scheme];
|
||||
|
||||
NSString *host = URL.host;
|
||||
TARUsage usage = [self usage:host];
|
||||
|
||||
NSDictionary<NSString *, NSString *> *queryDic = [self queryDicFromURL:URL];
|
||||
NSString *paramsJson = [queryDic objectForKey:TARURLQueryParamsKey];
|
||||
NSDictionary<NSString *, NSDictionary<NSString *, id> *> *allURLParams = [self paramsFromJson:paramsJson];
|
||||
|
||||
NSArray<NSString *> *pathComponents = URL.pathComponents;
|
||||
|
||||
[pathComponents enumerateObjectsUsingBlock:^(NSString * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
|
||||
if (![obj isEqualToString:@"/"]) {
|
||||
|
||||
NSArray<NSString *> * subPaths = [obj componentsSeparatedByString:TARURLSubPathSplitPattern];
|
||||
NSString *pathComponentKey = subPaths.firstObject;
|
||||
|
||||
Class mClass;
|
||||
TARPathComponentCustomHandler handler;
|
||||
TARPathComponent *pathComponent = [router.pathComponentByKey objectForKey:pathComponentKey];
|
||||
if (pathComponent) {
|
||||
mClass = pathComponent.mClass;
|
||||
handler = pathComponent.handler;
|
||||
} else {
|
||||
mClass = NSClassFromString(pathComponentKey);
|
||||
}
|
||||
|
||||
NSDictionary<NSString *, id> *URLParams = [allURLParams objectForKey:pathComponentKey];
|
||||
NSDictionary<NSString *, id> *funcParams = [params objectForKey:pathComponentKey];
|
||||
NSDictionary<NSString *, id> *finalParams = [self solveURLParams:URLParams withFuncParams:funcParams forClass:usage == TARUsageCallService ? nil : mClass];
|
||||
|
||||
if (handler) {
|
||||
handler(finalParams);
|
||||
return;
|
||||
}
|
||||
|
||||
NSString *protocolStr;
|
||||
Protocol *protocol;
|
||||
if (subPaths.count >= 2) {
|
||||
protocolStr = subPaths[1];
|
||||
protocol = NSProtocolFromString(protocolStr);
|
||||
}
|
||||
|
||||
id obj;
|
||||
id returnValue;
|
||||
|
||||
switch (usage) {
|
||||
case TARUsageCallService: {
|
||||
NSString *selectorStr = subPaths[2];
|
||||
SEL selector = NSSelectorFromString(selectorStr);
|
||||
obj = [[TAServiceManager sharedManager] createService:protocol];
|
||||
returnValue = [self safePerformAction:selector forTarget:obj withParams:finalParams];
|
||||
} break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
!then?:then(pathComponentKey, obj, returnValue);
|
||||
}
|
||||
}];
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
|
||||
#pragma mark - private
|
||||
+ (TARUsage)usage:(NSString *)usagePattern
|
||||
{
|
||||
usagePattern = usagePattern.lowercaseString;
|
||||
if ([usagePattern isEqualToString:TARURLHostCallService]) {
|
||||
return TARUsageCallService;
|
||||
}
|
||||
return TARUsageUnknown;
|
||||
}
|
||||
|
||||
+ (NSDictionary<NSString *, id> *)queryDicFromURL:(NSURL *)URL
|
||||
{
|
||||
if (!URL) {
|
||||
return nil;
|
||||
}
|
||||
if ([UIDevice currentDevice].systemVersion.floatValue < 8) {
|
||||
NSMutableDictionary *dic = @{}.mutableCopy;
|
||||
NSString *query = URL.query;
|
||||
NSArray<NSString *> *queryStrs = [query componentsSeparatedByString:@"&"];
|
||||
[queryStrs enumerateObjectsUsingBlock:^(NSString * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
|
||||
NSArray *keyValue = [obj componentsSeparatedByString:@"="];
|
||||
if (keyValue.count >= 2) {
|
||||
NSString *key = keyValue[0];
|
||||
NSString *value = keyValue[1];
|
||||
[dic setObject:value forKey:key];
|
||||
}
|
||||
}];
|
||||
return dic;
|
||||
} else {
|
||||
NSURLComponents *URLComponents = [NSURLComponents componentsWithURL:URL
|
||||
resolvingAgainstBaseURL:NO];
|
||||
NSArray *queryItems = URLComponents.queryItems;
|
||||
NSMutableDictionary *dic = @{}.mutableCopy;
|
||||
for (NSURLQueryItem *item in queryItems) {
|
||||
if (item.name && item.value) {
|
||||
[dic setObject:item.value forKey:item.name];
|
||||
}
|
||||
}
|
||||
return dic;
|
||||
}
|
||||
}
|
||||
|
||||
+ (NSDictionary<NSString *, NSDictionary<NSString *, id> *> *)paramsFromJson:(NSString *)json
|
||||
{
|
||||
if (!json.length) {
|
||||
return nil;
|
||||
}
|
||||
NSError *error;
|
||||
NSDictionary *dic = [NSJSONSerialization JSONObjectWithData:[json dataUsingEncoding:NSUTF8StringEncoding] options:0 error:&error];
|
||||
if (error) {
|
||||
NSLog(@"TARouter [Error] Wrong URL Query Format: \n%@", error.description);
|
||||
}
|
||||
return dic;
|
||||
}
|
||||
|
||||
|
||||
+ (NSDictionary<NSString *, id> *)solveURLParams:(NSDictionary<NSString *, id> *)URLParams
|
||||
withFuncParams:(NSDictionary<NSString *, id> *)funcParams
|
||||
forClass:(Class)mClass
|
||||
{
|
||||
if (!URLParams) {
|
||||
URLParams = @{};
|
||||
}
|
||||
NSMutableDictionary<NSString *, id> *params = URLParams.mutableCopy;
|
||||
NSArray<NSString *> *funcParamKeys = funcParams.allKeys;
|
||||
[funcParamKeys enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
|
||||
[params setObject:funcParams[obj] forKey:obj];
|
||||
}];
|
||||
if (mClass) {
|
||||
NSArray<NSString *> *paramKeys = params.allKeys;
|
||||
[paramKeys enumerateObjectsUsingBlock:^(NSString * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
|
||||
objc_property_t prop = class_getProperty(mClass, obj.UTF8String);
|
||||
if (!prop) {
|
||||
[params removeObjectForKey:obj];
|
||||
} else {
|
||||
NSString *propAttr = [[NSString alloc] initWithCString:property_getAttributes(prop) encoding:NSUTF8StringEncoding];
|
||||
NSRange range = [propAttr rangeOfString:TARClassRegex options:NSRegularExpressionSearch];
|
||||
if (range.length != 0) {
|
||||
NSString *propClassName = [propAttr substringWithRange:range];
|
||||
Class propClass = objc_getClass([propClassName UTF8String]);
|
||||
if ([propClass isSubclassOfClass:[NSString class]] && [params[obj] isKindOfClass:[NSNumber class]]) {
|
||||
[params setObject:[NSString stringWithFormat:@"%@", params[obj]] forKey:obj];
|
||||
} else if ([propClass isSubclassOfClass:[NSNumber class]] && [params[obj] isKindOfClass:[NSString class]]) {
|
||||
[params setObject:@(((NSString *)params[obj]).doubleValue) forKey:obj];
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}];
|
||||
}
|
||||
return params;
|
||||
}
|
||||
|
||||
+ (void)setObject:(id)object
|
||||
withPropertys:(NSDictionary<NSString *, id> *)propertys
|
||||
{
|
||||
if (!object) {
|
||||
return;
|
||||
}
|
||||
[propertys enumerateKeysAndObjectsUsingBlock:^(NSString * _Nonnull key, id _Nonnull obj, BOOL * _Nonnull stop) {
|
||||
[object setValue:obj forKey:key];
|
||||
}];
|
||||
}
|
||||
|
||||
+ (id)safePerformAction:(SEL)action
|
||||
forTarget:(NSObject *)target
|
||||
withParams:(NSDictionary *)params
|
||||
{
|
||||
NSMethodSignature * sig = [target methodSignatureForSelector:action];
|
||||
if (!sig) { return nil; }
|
||||
NSInvocation *inv = [NSInvocation invocationWithMethodSignature:sig];
|
||||
if (!inv) { return nil; }
|
||||
[inv setTarget:target];
|
||||
[inv setSelector:action];
|
||||
NSArray<NSString *> *keys = params.allKeys;
|
||||
keys = [keys sortedArrayUsingComparator:^NSComparisonResult(NSString * _Nonnull obj1, NSString * _Nonnull obj2) {
|
||||
if (obj1.integerValue < obj2.integerValue) {
|
||||
return NSOrderedAscending;
|
||||
} else if (obj1.integerValue == obj2.integerValue) {
|
||||
return NSOrderedSame;
|
||||
} else {
|
||||
return NSOrderedDescending;
|
||||
}
|
||||
}];
|
||||
[keys enumerateObjectsUsingBlock:^(NSString * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
|
||||
id value = params[obj];
|
||||
[inv setArgument:&value atIndex:idx+2];
|
||||
}];
|
||||
[inv invoke];
|
||||
return [NSObject bh_getReturnFromInv:inv withSig:sig];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,33 @@
|
||||
fileFormatVersion: 2
|
||||
guid: bd6b92a05025faa42917f6e8f81a35e0
|
||||
PluginImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
iconMap: {}
|
||||
executionOrder: {}
|
||||
defineConstraints: []
|
||||
isPreloaded: 0
|
||||
isOverridable: 0
|
||||
isExplicitlyReferenced: 0
|
||||
validateReferences: 1
|
||||
platformData:
|
||||
- first:
|
||||
Any:
|
||||
second:
|
||||
enabled: 0
|
||||
settings: {}
|
||||
- first:
|
||||
Editor: Editor
|
||||
second:
|
||||
enabled: 0
|
||||
settings:
|
||||
DefaultValueInitialized: true
|
||||
- first:
|
||||
iPhone: iOS
|
||||
second:
|
||||
enabled: 1
|
||||
settings:
|
||||
AddToEmbeddedBinaries: false
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,28 @@
|
||||
//
|
||||
// TAServiceManager.h
|
||||
// ThinkingSDK.default-Base-Core-Extension-Router-Util-iOS
|
||||
//
|
||||
// Created by wwango on 2022/10/7.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface TAServiceManager : NSObject
|
||||
|
||||
@property (nonatomic, assign) BOOL enableException;
|
||||
|
||||
+ (instancetype)sharedManager;
|
||||
|
||||
- (void)registerLocalServices;
|
||||
|
||||
- (void)registerService:(Protocol *)service implClass:(Class)implClass;
|
||||
|
||||
- (id)createService:(Protocol *)service;
|
||||
- (id)createService:(Protocol *)service withServiceName:(NSString *)serviceName;
|
||||
- (id)createService:(Protocol *)service withServiceName:(NSString *)serviceName shouldCache:(BOOL)shouldCache;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,33 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a16ee9fce88ef584eb22111f2a88a66d
|
||||
PluginImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
iconMap: {}
|
||||
executionOrder: {}
|
||||
defineConstraints: []
|
||||
isPreloaded: 0
|
||||
isOverridable: 0
|
||||
isExplicitlyReferenced: 0
|
||||
validateReferences: 1
|
||||
platformData:
|
||||
- first:
|
||||
Any:
|
||||
second:
|
||||
enabled: 0
|
||||
settings: {}
|
||||
- first:
|
||||
Editor: Editor
|
||||
second:
|
||||
enabled: 0
|
||||
settings:
|
||||
DefaultValueInitialized: true
|
||||
- first:
|
||||
iPhone: iOS
|
||||
second:
|
||||
enabled: 1
|
||||
settings:
|
||||
AddToEmbeddedBinaries: false
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,163 @@
|
||||
//
|
||||
// TAServiceManager.m
|
||||
// ThinkingSDK.default-Base-Core-Extension-Router-Util-iOS
|
||||
//
|
||||
// Created by wwango on 2022/10/7.
|
||||
//
|
||||
|
||||
#import "TAServiceManager.h"
|
||||
#import "TAContext.h"
|
||||
#import "TAAnnotation.h"
|
||||
#import <objc/runtime.h>
|
||||
|
||||
static const NSString *kTAService = @"service";
|
||||
static const NSString *kTAImpl = @"impl";
|
||||
|
||||
@interface TAServiceManager()
|
||||
|
||||
@property (nonatomic, strong) NSMutableDictionary *allServicesDict;
|
||||
@property (nonatomic, strong) NSRecursiveLock *lock;
|
||||
|
||||
@end
|
||||
|
||||
@implementation TAServiceManager
|
||||
|
||||
+ (instancetype)sharedManager
|
||||
{
|
||||
static id sharedManager = nil;
|
||||
static dispatch_once_t onceToken = 0;
|
||||
dispatch_once(&onceToken, ^{
|
||||
sharedManager = [[self alloc] init];
|
||||
});
|
||||
return sharedManager;
|
||||
}
|
||||
|
||||
- (void)registerLocalServices
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
- (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];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
- (id)createService:(Protocol *)service
|
||||
{
|
||||
return [self createService:service withServiceName:nil];
|
||||
}
|
||||
|
||||
- (id)createService:(Protocol *)service withServiceName:(NSString *)serviceName {
|
||||
return [self createService:service withServiceName:serviceName shouldCache:YES];
|
||||
}
|
||||
|
||||
- (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 = [[TAContext shareInstance] getServiceInstanceFromServiceName:serviceStr];
|
||||
if (protocolImpl) {
|
||||
return protocolImpl;
|
||||
}
|
||||
}
|
||||
|
||||
Class implClass = [self serviceImplClass:service];
|
||||
if ([[implClass class] respondsToSelector:@selector(singleton)]) {
|
||||
if ([[implClass class] performSelector:@selector(singleton)]) {
|
||||
if ([[implClass class] respondsToSelector:@selector(shareInstance)])
|
||||
implInstance = [[implClass class] shareInstance];
|
||||
else
|
||||
implInstance = [[implClass alloc] init];
|
||||
if (shouldCache) {
|
||||
[[TAContext shareInstance] addServiceWithImplInstance:implInstance serviceName:serviceStr];
|
||||
return implInstance;
|
||||
} else {
|
||||
return implInstance;
|
||||
}
|
||||
}
|
||||
}
|
||||
return [[implClass alloc] init];
|
||||
}
|
||||
|
||||
#pragma mark - private
|
||||
- (Class)serviceImplClass:(Protocol *)service
|
||||
{
|
||||
NSString *serviceImpl = [[self servicesDict] objectForKey:NSStringFromProtocol(service)];
|
||||
if (serviceImpl.length > 0) {
|
||||
return NSClassFromString(serviceImpl);
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (BOOL)checkValidService:(Protocol *)service
|
||||
{
|
||||
NSString *serviceImpl = [[self servicesDict] objectForKey:NSStringFromProtocol(service)];
|
||||
if (serviceImpl.length > 0) {
|
||||
return YES;
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (NSMutableDictionary *)allServicesDict
|
||||
{
|
||||
if (!_allServicesDict) {
|
||||
_allServicesDict = [NSMutableDictionary dictionary];
|
||||
}
|
||||
return _allServicesDict;
|
||||
}
|
||||
|
||||
- (NSRecursiveLock *)lock
|
||||
{
|
||||
if (!_lock) {
|
||||
_lock = [[NSRecursiveLock alloc] init];
|
||||
}
|
||||
return _lock;
|
||||
}
|
||||
|
||||
- (NSDictionary *)servicesDict
|
||||
{
|
||||
[self.lock lock];
|
||||
NSDictionary *dict = [self.allServicesDict copy];
|
||||
[self.lock unlock];
|
||||
return dict;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,33 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0ee92fe9f02d19d4fb1a1d800801befd
|
||||
PluginImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
iconMap: {}
|
||||
executionOrder: {}
|
||||
defineConstraints: []
|
||||
isPreloaded: 0
|
||||
isOverridable: 0
|
||||
isExplicitlyReferenced: 0
|
||||
validateReferences: 1
|
||||
platformData:
|
||||
- first:
|
||||
Any:
|
||||
second:
|
||||
enabled: 0
|
||||
settings: {}
|
||||
- first:
|
||||
Editor: Editor
|
||||
second:
|
||||
enabled: 0
|
||||
settings:
|
||||
DefaultValueInitialized: true
|
||||
- first:
|
||||
iPhone: iOS
|
||||
second:
|
||||
enabled: 1
|
||||
settings:
|
||||
AddToEmbeddedBinaries: false
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,22 @@
|
||||
//
|
||||
// TAServiceProtocol.h
|
||||
// ThinkingSDK.default-Base-Core-Extension-Router-Util-iOS
|
||||
//
|
||||
// Created by wwango on 2022/10/7.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@protocol TAServiceProtocol <NSObject>
|
||||
|
||||
@optional
|
||||
|
||||
+ (BOOL)singleton;
|
||||
|
||||
+ (id)shareInstance;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,33 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 985dd88351bbf664fa7d4d48d3c9596e
|
||||
PluginImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
iconMap: {}
|
||||
executionOrder: {}
|
||||
defineConstraints: []
|
||||
isPreloaded: 0
|
||||
isOverridable: 0
|
||||
isExplicitlyReferenced: 0
|
||||
validateReferences: 1
|
||||
platformData:
|
||||
- first:
|
||||
Any:
|
||||
second:
|
||||
enabled: 0
|
||||
settings: {}
|
||||
- first:
|
||||
Editor: Editor
|
||||
second:
|
||||
enabled: 0
|
||||
settings:
|
||||
DefaultValueInitialized: true
|
||||
- first:
|
||||
iPhone: iOS
|
||||
second:
|
||||
enabled: 1
|
||||
settings:
|
||||
AddToEmbeddedBinaries: false
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user