前言
上一篇文章[iOS]如何封装第三方库(非Appdelegate启动)(一)介绍了如何封装非Appdelegate启动
的三方库,这篇文章讲述如何抽象化需要Appdelegate启动
的三方库.其实封装这种三方库的目的是在于减少appdelegate的体积.值得一提的是,这是我们team一位伙伴提出来的服务化思想
,经过整体的讨论完善,才在项目中有了运用.
举个例子
我们都集成过微信支付或者微信登录这个三方,它需要在appdelegate中进行appId的注册,然后执行各种handler和resp回调.如果再加上支付宝或者其他sdk,那么appdelegate中的代码会越来越多,后期耦合加重,会越来越难以维护.这里以我刚做过的微信登录为例.
在用服务化之前代码只这样的:
@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];
服务化思想
将每个需要在appdelegate进行设置的sdk功能当做一个服务,通过一个Services.plist
表来对这些服务进行注册;如果该服务需要传入参数,那么可以考虑新建一个ServiceParam.plist
表来对这些services
提供参数,当然你也可以直接在Services.plist
直接维护这些参数,这里采取前者.
具体实现
1.新建一个类AppdelegateComponents
,同时声明AppdelegateComponentsDelegate
协议,同时提供获取所有服务,加载plist文件的api,其中协议方法tp_application: didFinishLaunchingWithOptions: userInfo:
,是其他服务必须实现的方法.
@protocol ICXAppdelegateComponentsDelegate<UIApplicationDelegate>
- (BOOL)tp_application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions userInfo:(NSDictionary *)userInfo;
@end
@interface ICXAppdelegateComponents : NSObject
/**
获取单例
*/
+ (instancetype)shareInstance ;
/**
根据plist文件注册服务
@param plistFile 文件名
*/
- (void)loadModulesWithPlistFile:(NSString *)plistFile;
/**
所有注册的服务
@return 所有服务
*/
- (NSMutableArray*)services;
@end
2.新建一个服务(WXLoginService),并为上述的两个plist文件填充好参数
这个微信登录的服务实现如下:
#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.到这里服务已经生成完毕,接下来是到appdelegate里面调用:
- (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];
//加载服务列表
[[ICXAppdelegateComponents shareInstance] loadModulesWithPlistFile:@"ICXModulesRegister"];
id<ICXAppdelegateComponentsDelegate> service;
//获取参数列表
NSString *keyPlistPath = [[NSBundle mainBundle] pathForResource:@"ICXAppKeysInfo" ofType:@"plist"];
NSDictionary *keysInfo = [NSDictionary dictionaryWithContentsOfFile:keyPlistPath];
//循环遍历列表中的服务,并调用
for(service in [[ICXAppdelegateComponents shareInstance] services]){
if([service respondsToSelector:@selector(icx_application:didFinishLaunchingWithOptions:userInfo:)]){
[service icx_application:application didFinishLaunchingWithOptions:launchOptions userInfo:keysInfo];
}
}
return YES;
}
//因为wx登录还需要另外几个方法辅助,所以还需要添加如下代码,用来启动wx的拉取回调功能
- (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;
}
然后在需要拉取微信的地方如下调用:
if ([ICXWXLoginModule wxInstalled]){
[ICXWXLoginModule sendWXAuthReqeustWithState:@"xxxx" scope:@"snsapi_userinfo" otherParam:nil];
}else{
}
这样appdelegate就只耦合了AppdelegateComponents
这个类,并没有包含其他任何sdk,同时在业务需要响应的地方也没有直接耦合sdk,你可以想象一下这种方式带来的好处.同时多个服务都不需要进行额外的操作,最多只是在appdelegate里面处理几个协议方法,其他任何地方都不需要动.
demo暂时不放出了,因为贴的是项目代码,哈哈自己领悟吧.
网友评论