前言
上一篇文章[iOS]如何封裝第三方庫(非Appdelegate啟動)(一)介紹了如何封裝非Appdelegate啟動
的三方庫,這篇文章講述如何抽象化需要Appdelegate啟動
的三方庫.其實(shí)封裝這種三方庫的目的是在于減少appdelegate的體積.值得一提的是,這是我們team一位伙伴提出來的服務(wù)化思想
,經(jīng)過整體的討論完善,才在項(xiàng)目中有了運(yùn)用.
舉個(gè)例子
我們都集成過微信支付或者微信登錄這個(gè)三方,它需要在appdelegate中進(jìn)行appId的注冊,然后執(zhí)行各種handler和resp回調(diào).如果再加上支付寶或者其他sdk,那么appdelegate中的代碼會越來越多,后期耦合加重,會越來越難以維護(hù).這里以我剛做過的微信登錄為例.
在用服務(wù)化之前代碼只這樣的:
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions userInfo:(NSDictionary *)userInfo{
[WXApi registerApp:@"appid"];
return YES;
}
- (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options{
[WXApi handleOpenURL:url delegate:self];
return YES;
}
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation{
[WXApi handleOpenURL:url delegate:self];
return YES;
}
- (BOOL)application:(UIApplication *)application handleOpenURL:(NSURL *)url{
[WXApi handleOpenURL:url delegate:self];
return YES;
}
- (void)onResp:(BaseResp *)resp{
if (resp.errCode == 0){
SendAuthResp *rep = (SendAuthResp *)resp;
[[NSNotificationCenter defaultCenter] postNotificationName:WXDIDLOGINSUCCESS object:nil userInfo:@{WXCode : rep.code}];
}
}
@end
需要拉起微信的地方也會有如下直接耦合WXApi的代碼:
SendAuthReq *request = [[SendAuthReq alloc] init];
request.state = state;
request.scope = scope;
[WXApi sendReq:request];
服務(wù)化思想
將每個(gè)需要在appdelegate進(jìn)行設(shè)置的sdk功能當(dāng)做一個(gè)服務(wù),通過一個(gè)Services.plist
表來對這些服務(wù)進(jìn)行注冊;如果該服務(wù)需要傳入?yún)?shù),那么可以考慮新建一個(gè)ServiceParam.plist
表來對這些services
提供參數(shù),當(dāng)然你也可以直接在Services.plist
直接維護(hù)這些參數(shù),這里采取前者.
具體實(shí)現(xiàn)
1.新建一個(gè)類AppdelegateComponents
,同時(shí)聲明AppdelegateComponentsDelegate
協(xié)議,同時(shí)提供獲取所有服務(wù),加載plist文件的api,其中協(xié)議方法tp_application: didFinishLaunchingWithOptions: userInfo:
,是其他服務(wù)必須實(shí)現(xiàn)的方法.
@protocol ICXAppdelegateComponentsDelegate<UIApplicationDelegate>
- (BOOL)tp_application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions userInfo:(NSDictionary *)userInfo;
@end
@interface ICXAppdelegateComponents : NSObject
/**
獲取單例
*/
+ (instancetype)shareInstance ;
/**
根據(jù)plist文件注冊服務(wù)
@param plistFile 文件名
*/
- (void)loadModulesWithPlistFile:(NSString *)plistFile;
/**
所有注冊的服務(wù)
@return 所有服務(wù)
*/
- (NSMutableArray*)services;
@end
2.新建一個(gè)服務(wù)(WXLoginService),并為上述的兩個(gè)plist文件填充好參數(shù)
這個(gè)微信登錄的服務(wù)實(shí)現(xiàn)如下:
#import "ICXWXLoginModule.h"
#import "ICXAppdelegateComponents.h"
#import "WXApi.h"
NSString * const WXDIDLOGINSUCCESS = @"WXDIDLOGINSUCCESS";
NSString * const WXCode = @"WXCode";
@interface ICXWXLoginModule()<ICXAppdelegateComponentsDelegate,WXApiDelegate>
@end
@implementation ICXWXLoginModule
+ (BOOL)wxInstalled{
return [WXApi isWXAppInstalled];
}
+ (void)sendWXAuthReqeustWithState:(NSString *)state scope:(NSString *)scope otherParam:(NSString *)other{
SendAuthReq *request = [[SendAuthReq alloc] init];
request.state = state;
request.scope = scope;
[WXApi sendReq:request];
}
- (BOOL)icx_application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions userInfo:(NSDictionary *)userInfo{
[WXApi registerApp:[userInfo objectForKey:@"ICXWXLoginModule"]];
return YES;
}
- (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options{
[WXApi handleOpenURL:url delegate:self];
return YES;
}
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation{
[WXApi handleOpenURL:url delegate:self];
return YES;
}
- (BOOL)application:(UIApplication *)application handleOpenURL:(NSURL *)url{
[WXApi handleOpenURL:url delegate:self];
return YES;
}
- (void)onResp:(BaseResp *)resp{
if (resp.errCode == 0){
SendAuthResp *rep = (SendAuthResp *)resp;
[[NSNotificationCenter defaultCenter] postNotificationName:WXDIDLOGINSUCCESS object:nil userInfo:@{WXCode : rep.code}];
}
}
@end
3.到這里服務(wù)已經(jīng)生成完畢,接下來是到appdelegate里面調(diào)用:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
ICXLoginViewController *tabVC = [[ICXLoginViewController alloc] init];
UINavigationController *navi = [[UINavigationController alloc] initWithRootViewController:tabVC];
self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
self.window.rootViewController = navi;
[self.window makeKeyAndVisible];
//加載服務(wù)列表
[[ICXAppdelegateComponents shareInstance] loadModulesWithPlistFile:@"ICXModulesRegister"];
id<ICXAppdelegateComponentsDelegate> service;
//獲取參數(shù)列表
NSString *keyPlistPath = [[NSBundle mainBundle] pathForResource:@"ICXAppKeysInfo" ofType:@"plist"];
NSDictionary *keysInfo = [NSDictionary dictionaryWithContentsOfFile:keyPlistPath];
//循環(huán)遍歷列表中的服務(wù),并調(diào)用
for(service in [[ICXAppdelegateComponents shareInstance] services]){
if([service respondsToSelector:@selector(icx_application:didFinishLaunchingWithOptions:userInfo:)]){
[service icx_application:application didFinishLaunchingWithOptions:launchOptions userInfo:keysInfo];
}
}
return YES;
}
//因?yàn)閣x登錄還需要另外幾個(gè)方法輔助,所以還需要添加如下代碼,用來啟動wx的拉取回調(diào)功能
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation{
for(id<ICXAppdelegateComponentsDelegate>service in [[ICXAppdelegateComponents shareInstance] services]){
if([service respondsToSelector:_cmd]){
#pragma clang diagnostic push
#pragma clang diagnostic ignored"-Wdeprecated-declarations"
[service application:application openURL:url sourceApplication:sourceApplication annotation:annotation];
#pragma clang diagnostic pop
}
}
return YES;
}
- (BOOL)application:(UIApplication *)application handleOpenURL:(NSURL *)url{
for(id<ICXAppdelegateComponentsDelegate> service in [[ICXAppdelegateComponents shareInstance] services]){
if([service respondsToSelector:_cmd]){
#pragma clang diagnostic push
#pragma clang diagnostic ignored"-Wdeprecated-declarations"
[service application:application handleOpenURL:url];
#pragma clang diagnostic pop
}
}
return YES;
}
然后在需要拉取微信的地方如下調(diào)用:
if ([ICXWXLoginModule wxInstalled]){
[ICXWXLoginModule sendWXAuthReqeustWithState:@"xxxx" scope:@"snsapi_userinfo" otherParam:nil];
}else{
}
這樣appdelegate就只耦合了AppdelegateComponents
這個(gè)類,并沒有包含其他任何sdk,同時(shí)在業(yè)務(wù)需要響應(yīng)的地方也沒有直接耦合sdk,你可以想象一下這種方式帶來的好處.同時(shí)多個(gè)服務(wù)都不需要進(jìn)行額外的操作,最多只是在appdelegate里面處理幾個(gè)協(xié)議方法,其他任何地方都不需要動.
demo暫時(shí)不放出了,因?yàn)橘N的是項(xiàng)目代碼,哈哈自己領(lǐng)悟吧.