美文网首页
[iOS]如何封装第三方库(Appdelegate启动)(二)

[iOS]如何封装第三方库(Appdelegate启动)(二)

作者: 未来行者 | 来源:发表于2018-03-27 18:09 被阅读105次

    前言

    上一篇文章[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暂时不放出了,因为贴的是项目代码,哈哈自己领悟吧.

    相关文章

      网友评论

          本文标题:[iOS]如何封装第三方库(Appdelegate启动)(二)

          本文链接:https://www.haomeiwen.com/subject/ksqscftx.html