萬能API路由(api任意呼叫,元件完全解耦)
介紹:
萬能API路由通過AOP,KVC,指標入引數等程式設計思想,實現類,例項方法的任意呼叫,因為使用指標入參,支援C語言的基本資料型別,oc物件型別,結構體,block塊,代理等,通過kvc來實現屬性的動態賦值操作。實現大型app任意模組之間的解耦。特別對於大型依賴pod管理開發的元件相互依賴,更是解決不同sdk底層依賴相同庫產生的衝突,使得各個sdk完全解耦!
萬能路由API功能:
1.Api萬能路由利用AOP程式設計思想,指標引數,等來實現任意object-c 的API呼叫。支援基本資料型別,物件型別,代理,block,列舉,結構體等(系統自帶和自定義均支援)
2.本sdk用於元件化開發模式,多sdk巢狀等複雜的情況!完全解決專案開發的耦合度!
元件已開源,地址:https://github.com/Tkoul/TKRouter
pod引入 : pod'TKRouter'
如果找不到,刪除本地pod快取索引,更新下spec庫即可。
設計背景:
元件開發模式:在龐大專案開發下,有多個sdk共同開發。主app就是一個空殼,各個元件sdk開發完畢,進行pod驗證,打tag,執行repo push操作,最後提交到公司倉庫。最後只要在主app進行多pod依賴,一鍵pod update !把各個元件sdk拉下來!這就是最常用的元件開發。本人所在公司也是這種開發模式。
元件化開發的好處這裡不做贅述!網上有很多資料,可以說大的專案已經離不開元件化的思想。
元件化路由:那麼在這樣的開發模式下,效率大大提升,並且分工明確,各個團隊之間有條不紊。而在各個團隊之間的橋樑--路由的作用就不言而喻!常規的路由,包括目前流行的路由三方元件都有自己的定義規則,一個專案突然適配起來不是那麼簡單。
開發問題:專案主App,包含多個元件(舉個例子,比如就2個把,像京東商城,支付寶這個級別的有個百十個吧),比如其中一個元件A,一個元件B。分別有倆個團隊負責開發,都有自己完整的流程!那麼兩個庫都依賴了AFNetworking 這個請求第三方(大公司會封裝自己的請求框架輪子)。這裡依照afnet為例子吧,畢竟太牛!哈哈
A單獨開發:A專案,引入pod 'AFNetworking', '~> 3.0' 然後 高高興興去開發了,在專案期限結束的時候,打tag,pod lib驗證,pod repo push 完事。
B單獨開發:B為老元件,很早就引入pod 'AFNetworking', '~> 2.0' 然後 高高興興去開發了,在專案期限結束的時候,打tag,pod lib驗證,pod repo push 完事。兩個對很ok!
主app進行pod依賴,把各個元件下拉 pod 'A元件', pod 'B元件'!
1.這個時候執行pod update 就出現問題了 拉不下來,因為pod版本不相容。 記做 問題一
主APP負責人看了,會有兩種解決方案
方案一:立即聯絡B,告知版本庫升級到3.0用新的,告知所有的團隊以某個版本為準。
方案二:把AFNetworking作為主App的直接bundel內容,其它元件去掉AFNetworking
對於方案一:版本衝突解決了,但是有100個元件 依賴了100個AFNetworking,有的元件提供原始碼,沒問題,原始碼只會拉一份,有的提供的framework,經過pod打包預設加字首的(無--no-mangle命令)!也就是有多少個靜態庫提供的元件,就會生成同樣功能的AFNetworking,比如有50個元件是靜態庫,那麼最後拉下來就會有51個AFNetworking存在專案中。(如果不加--no-mangle)對於靜態庫型別的元件,就會報錯有很多個重複檔案。---記做問題二
對於方案二:主app管理AFNetworking,那麼在A和B單獨開發的時候,不能依賴AFNetworking,只能匯入主.h檔案,把AFNetworking作為demoApp加入demo工程。也可以正常開發。但是進行pod lib 和 pod repo push的時候就推不上倉庫了!因為pod驗證會檢測實現方法等,相當於少了AFNetworking庫,壓根過不去。--記做問題三
以上問題對元件特別的APP開發造成很大的困擾!為了解決這個問題,大牛們早就前行在道路上,就出現了“元件二進位制化||平滑二進位制元件”的實現,本人也在使用。原理就是把第三方共用元件比如AFNetworking先做成二進位制檔案,大家都依賴二進位制檔案來做到統一!能極大解決問題,弊端就是維護很多二進位制,並且每次升級不同團隊都要做二進位制檔案的md5雜湊取值,這個值一樣才能說明是同一個!每次程式碼升級開發完畢,必須把原始碼重新生成新的二進位制,維護成本很高!有時候就忘了!
針對諸多的問題,我就嘗試了TKRouter的實現。
TKRouter :
1.呼叫原子api ,沒有什麼規則,就像呼叫方法一樣。
2.多元件開發,都依賴某些第三方元件的時候,比如AFNetworking,我們一旦確定幾百個團隊有一個在用AFNetworking,那麼我們就不管依賴的事情了 甚至不去維護它,瞅一眼都懶! 我們就直接路由呼叫。我們的專案和AFNetworking無任何直接關係,標頭檔案都不需要引入。
下面是我的某個元件呼叫AFNetworking的網路檢測程式碼:
常規實現:
1. 專案依賴 AFNetworking
2. 實現的地方引入 AFNetworkReachabilityManager.h
3. 實現如下程式碼
AFNetworkReachabilityManager *maneage=[AFNetworkReachabilityManager sharedManager];
[maneage startMonitoring];
[maneage setReachabilityStatusChangeBlock:^(AFNetworkReachabilityStatus status) {
if (status == 0) {
//無網路連結
} else {
//有網連結
}
}];
TKRouter 實現:直接上程式碼 ,不要依賴,不需要引入標頭檔案:
ReturnStruct managerStur = [[[TKRouter router] routerClassName:@"AFNetworkReachabilityManager"] classMethodSelect:@"sharedManager" parameter:nil, nil];
NSObject *objManager = managerStur.returnValue;
[objManager instanceMethodSelect:@"startMonitoring" parameter:nil, nil];
void (^ReachabilityStatusChangeBlock)(NSInteger status) = ^(NSInteger status){
if (status == 0) {
//無網路連結
} else {
//有網連結
}
};
[objManager instanceMethodSelect:@"setReachabilityStatusChangeBlock:" parameter:&ReachabilityStatusChangeBlock, nil];
TKRouter好處就是不需要關心依賴的框架,只要主APP或者主APP依賴的諸多元件sdk有一份我就能執行通過TKRouter呼叫,元件工程不存在AFNetworking也依然可與執行pod lib lint 和 pod repo push!推送的是元件,想達到實際效果就在demo工程手動匯入一下AFNetworking即可。pod推送,驗證跟demo工程無關。
那麼 以上的諸多問題全部得到解決!且無任何成本!
注意事項:TKRouter 強大的原子呼叫毋庸置疑,三方sdk一旦開源!api就固定了,所以主工程種幾百個元件有一個AFNetworking就夠了,因為AFNetworking的api一般不會隨著版本升級而變更,只會裡面的實現會有所變更。但是咱們不關心啊,有其他團隊維護呢。:smile:
好處:咱們不用關係他升級到第幾個版本,讓別的團隊更新維護版本,而我們只關注api!
注意:某個開源庫萬不得已改變了api! 那麼由於我們用的路由aop思想編寫出來的程式,api變化,我們元件並沒有報錯,紅點提示。所以每次開源庫大版本升級關注下api變化即可。一般萬年不遇!:smile:再說,一般都會迭代幾個版本才會慢慢拋棄一些方法。
不要告訴我,你懶到自己程式碼寫一遍,一萬年都不再維護吧。:smile:
呼叫注意:我們的所有的方法引數為指標型別!就牽涉到左值右值方面的知識。我們傳的是左值-記憶體中有實際記憶體的。有興趣的小夥伴可以研究下。簡單起見,如果是方法傳來的值,直接使用會抱紅,我們定義一個它的物件,接收一下值,用新定義的物件取地址即可。左值、右值:https://www.jianshu.com/p/8095517dbb3f
核心方法:
一:
/**
例項子物件 給屬性 賦值
@param propertyParameter 屬性字典組合。 key為屬性的字串。 value為屬性需要賦予的值
@return 返回
*/
- (ReturnStruct)setPropertyParameter:(NSDictionary*)propertyParameter;
二:
/**
執行例項方法
@param selectString 方法名
@param methodParaments 方法引數 --- 指標引數 對應引數 以指標型別傳入
@return 返回值
*/
- (ReturnStruct)instanceMethodSelect:(NSString*)selectString parameter:(void *)methodParaments, ... NS_REQUIRES_NIL_TERMINATION;
三:
/**
執行類方法
@param selectString 方法名
@param methodParaments 方法引數 --- 指標引數 對應引數 以指標型別傳入
@return 返回值
*/
+ (ReturnStruct)classMethodSelect:(NSString*)selectString parameter:(void *)methodParaments, ... NS_REQUIRES_NIL_TERMINATION;
示例:
比如在demo工程:
呼叫方法:+ (NSString*)TestMethodOneWithObjectType:(NSDictionary*)dic andPar:(NSString*)strOne andPar:(NSNumber*)numTwo;
//step 二: AOP 呼叫+ 方法。即類方法
Class TKMethodTestClass = [[TKRouter router] routerClassName:@"TKMethodTest"];
NSDictionary *par1 =@{@"key1":@"Hello:TKRouter",@"key2":@"SayHi"};
NSString *par2 = @"字串型別引數";
NSNumber *par3 = [NSNumber numberWithInt:1688];
[TKMethodTestClass classMethodSelect:@"TestMethodOneWithObjectType:andPar:andPar:" parameter:&par1,&par2,&par3, nil];
呼叫方法:- (void)TestMethodTwoWithBasicType:(int)numberone andSecond:(CGFloat)floatTwo;
//step 四-: 例項物件呼叫- 方法 - 傳入基本資料型別
NSObject *object = [[TKRouter router] routerGetInstanceWithClassName:@"TKMethodTest"];
int par4 = 8888;
CGFloat par5 = 88.88;
ReturnStruct returnOne = [object instanceMethodSelect:@"TestMethodTwoWithBasicType:andSecond:" parameter:&par4,&par5, nil];
呼叫方法:- (BOOL)TestMethodTwoWithStructType:(CGRect)struOne and:(CGSize)struTwo;
//step 四二: 例項物件呼叫- 方法 - 傳入結構體
NSObject *object = [[TKRouter router] routerGetInstanceWithClassName:@"TKMethodTest"];
CGRect par6 = CGRectMake(100, 100, 200.5, 200);
CGSize par7 = CGSizeMake(666.0, 888.5);
ReturnStruct returnTwo = [object instanceMethodSelect:@"TestMethodTwoWithStructType:and:" parameter:&par6,&par7, nil];
呼叫方法:- (NSString*)TestMethodTwoWithBlockType:(void(^)(NSString *str1))block;
//step 四三: 例項物件呼叫- 方法 - 傳入block塊
NSObject *object = [[TKRouter router] routerGetInstanceWithClassName:@"TKMethodTest"];
void(^parblock8)(NSString *str1) = ^(NSString *str1){
NSLog(@"\n block 得到的值回撥。==%@\n\n\n",str1);
};
ReturnStruct returnThere = [object instanceMethodSelect:@"TestMethodTwoWithBlockType:" parameter:&parblock8, nil];
以上是基本的呼叫,更多的去github上download下來可自行檢視。(地址:https://github.com/Tkoul/TKRouter )
比如:初始化ctrl,TKRouter給ctrl賦值,TKRouter呼叫push,推出新的檢視,TKRouter設定代理!實現基本資料型別,結構體,oc型別,block塊,代理等!
如果有幫到你,請去俺的https://github.com/Tkoul/TKRouter 地址上 star一下。
歡迎大家交流,email:[email protected]