为AppDelegate解耦和瘦身

在实际的开发过程中,AppDelegate应该除了负责应用生命周期之外,不应该再有多余的责任。但是往往在一个项目的业务不断扩展的时候一般都会伴随着 AppDelegate这个文件变的臃肿不堪,往往AppDelegate中会出现极光推送,友盟分享,微信支付宝支付等第三方的注册代码,变得十分的 凌乱。这时候你一般就会想着法的去封装代码,给这个臃肿的 AppDelegate瘦身。那么怎么合理的给AppDelegate瘦身呢?下面我们就介绍几种比较常用且好用的方法。

第一种为APPDelegate创建分类

将一些第三方初始化以及创建的代码抽离到APPDelegate的分类当中,实现APPDelegate的瘦身。

先以友盟推送为例
具体方法为先创建一个类别AppDelegate+UMengPush.h
给类别添加一个userInfo属性用来临时存放接收到的推送消息。

@property (nonatomic, strong) NSDictionary *userInfo;

以及一个配置友盟的方法

/**
 配置友盟推送

 @param appKey 友盟appkey
 @param launchOptions App launchOptions
 */
- (void)configureUMessageWithAppKey:(NSString *)appKey launchOptions:(NSDictionary *)launchOptions;

因为类别增加的属性不能直接赋值和取值, 还要再专门增加
getter / setter方法

/**
 给类别属性赋值

 @param userInfo 推送消息字典
 */
- (void)zx_setUserInfo:(NSDictionary *)userInfo;

/**
 获取类别属性值

 @return 暂存的推送消息
 */
- (NSDictionary *)zx_getUserInfo;

.m文件

#import "AppDelegate+UMengPush.h"
#import "UMessage.h"

#import 

static char UserInfoKey;

@implementation AppDelegate (UMengPush)

#pragma mark - Configure UMessage SDK

- (void)configureUMessageWithAppKey:(NSString *)appKey launchOptions:(NSDictionary *)launchOptions {
    
    // 设置AppKey & LaunchOptions
    [UMessage startWithAppkey:appKey launchOptions:launchOptions];
    
    // 注册
    [UMessage registerForRemoteNotifications];
    
    // 开启Log
    [UMessage setLogEnabled:YES];
    
    // 检查是否为iOS 10以上版本
    if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 10.0) {
        
        // 如果检查到时iOS 10以上版本则必须执行以下操作
        UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
        center.delegate                  = self;
        UNAuthorizationOptions types10   = \
        UNAuthorizationOptionBadge | UNAuthorizationOptionAlert | UNAuthorizationOptionSound;
        
        [center requestAuthorizationWithOptions:types10 completionHandler:^(BOOL granted, NSError * _Nullable error) {
            
            if (granted) {
                
                // 点击允许
                // 这里可以添加一些自己的逻辑
            } else {
                
                // 点击不允许
                // 这里可以添加一些自己的逻辑
            }
        }];
        
    }
}

#pragma mark - UMessage Delegate Methods

- (void)application:(UIApplication *)application
            didReceiveRemoteNotification:(nonnull NSDictionary *)userInfo {
    
    // 关闭友盟自带的弹出框
    [UMessage setAutoAlert:NO];
    
    [UMessage didReceiveRemoteNotification:userInfo];
    
    [self zx_setUserInfo:userInfo];
    
    // 定制自己的弹出框
    if ([UIApplication sharedApplication].applicationState == UIApplicationStateActive) {
        
        UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"提示"
                                                            message:userInfo[@"aps"][@"alert"]
                                                           delegate:self
                                                  cancelButtonTitle:@"确定"
                                                  otherButtonTitles:nil];
        [alertView show];
    }
}

// iOS 10新增: 处理前台收到通知的代理方法
- (void)userNotificationCenter:(UNUserNotificationCenter *)center
       willPresentNotification:(UNNotification *)notification
         withCompletionHandler:(void (^)(UNNotificationPresentationOptions))completionHandler{
    
    NSDictionary * userInfo = notification.request.content.userInfo;
    if([notification.request.trigger isKindOfClass:[UNPushNotificationTrigger class]]) {
        
        //应用处于前台时的远程推送接受
        //关闭友盟自带的弹出框
        [UMessage setAutoAlert:NO];
        //必须加这句代码
        [UMessage didReceiveRemoteNotification:userInfo];
        
    }else{
        
        //应用处于前台时的本地推送接受
    }
    
    //当应用处于前台时提示设置,需要哪个可以设置哪一个
    completionHandler(UNNotificationPresentationOptionSound |
                      UNNotificationPresentationOptionBadge |
                      UNNotificationPresentationOptionAlert);
}

//iOS10新增:处理后台点击通知的代理方法
-(void)userNotificationCenter:(UNUserNotificationCenter *)center
            didReceiveNotificationResponse:(UNNotificationResponse *)response
                withCompletionHandler:(void (^)())completionHandler{
    
    NSDictionary * userInfo = response.notification.request.content.userInfo;
    if([response.notification.request.trigger isKindOfClass:[UNPushNotificationTrigger class]]) {
        
        //应用处于后台时的远程推送接受
        //必须加这句代码
        [UMessage didReceiveRemoteNotification:userInfo];
        
    }else{
        
        //应用处于后台时的本地推送接受
    }
}


- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
    
    [UMessage sendClickReportForRemoteNotification:[self zx_getUserInfo]];
}

- (void)zx_setUserInfo:(NSDictionary *)userInfo {
    
    objc_setAssociatedObject(self, &UserInfoKey, userInfo, OBJC_ASSOCIATION_COPY_NONATOMIC);
}

- (NSDictionary *)zx_getUserInfo {
    
    if (objc_getAssociatedObject(self, &UserInfoKey)) {
        
        return objc_getAssociatedObject(self, &UserInfoKey);
    } else {
        
        return nil;
    }
}

@end

这样当们有项目需要继承友盟推送的时候, 只要配置好key, 在AppDelegate中只要简单一句话就完成了

#import "AppDelegate.h"
#import "AppDelegate+UMengPush.h"

@interface AppDelegate ()

@end

@implementation AppDelegate


- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    // Override point for customization after application launch.
    
    // 配置UMessage
    [self configureUMessageWithAppKey:UMessageAppKey launchOptions:launchOptions];
    
    return YES;
}

方法二. 组件化设计

解释:SOA面向服务的架构
面向服务的架构(SOA)是一个组件模型,它将应用程序的不同功能单元(称为服务)通过这些服务之间定义良好的接口和契约联系起来。接口是采用中立的方式进行定义的,它应该独立于实现服务的硬件平台、操作系统和编程语言。这使得构建在各种各样的系统中的服务可以以一种统一和通用的方式进行交互。

作用:

1、SOA是面向服务的架构,所有的第三方功能都被分别封装成服务。
2、Component 表示这个类是用于引用的,不能用于继承。

实现步骤

一、首先创建服务类,服务类是对第三方服务的封装。第三方服务包括推送、支付、统计等

1、服务举例 BaiduPushService 头文件
新创建的服务类需要添加 协议,根据需要实现协议中的方法。这里只添加了一个作为演示。

BaiduPushService.h

#import   
#import   
  
@interface BaiduPushService : NSObject    
  
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions ;  
  
@end  
BaiduPushService.m

#import "BaiduPushService.h"  
  
@implementation BaiduPushService  
  
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions  
{  
    NSLog(@"BaiduPushService didFinishLaunchingWithOptions");  
    return YES;  
}  
@end  

二、组件类

1、 SOAComponentAppDelegate.h 头文件
定义单例方法instance()和获取服务的方法services。

#import   
  
@interface SOAComponentAppDelegate : NSObject  
 
+ (instancetype)instance ;  
//装服务的数组  
-(NSMutableArray*) services;  
  
@end  

2、SOAComponentAppDelegate.m实现
在实现类中,需要引用并注册第三方的服务类。

 
#import "SOAComponentAppDelegate.h"  
#import "BaiduPushService.h"  
  
@implementation SOAComponentAppDelegate  
{  
    NSMutableArray* allServices;  
}  
  
#pragma mark - 服务静态注册  
  
//需要运行程序之前,手工增加根据需要的新服务  
  
-(void)registeServices  
{  
    [self registeService:[[BaiduPushService alloc] init]];  
      
}  
  
#pragma mark - 获取SOAComponent单实例  
  
+ (instancetype)instance {  
      
    static SOAComponentAppDelegate *insance = nil;  
    static dispatch_once_t once;  
    dispatch_once(&once, ^{  
        insance = [[SOAComponentAppDelegate alloc] init];  
    });  
      
      
    return insance;  
}  
  
#pragma mark - 获取全部服务  
-(NSMutableArray *)services  
{  
      
    if (!allServices) {  
        allServices = [[NSMutableArray alloc]init];  
        [self registeServices];  
    }  
  
    return allServices;  
}  
  
#pragma mark - 服务动态注册  
-(void)registeService:(id)service  
{  
    if (![allServices containsObject:service])  
    {  
        [allServices addObject:service];  
    }     
}  
@end 

三、使用SOAComponentAppDelegate

1、AppDelegate.h 不做任何改动。

#import   
  
@interface AppDelegate : UIResponder   
  
@property (strong, nonatomic) UIWindow *window;  
 
@end  

2、AppDelegate.m
导入 SOAComponentAppDelegate 和 BaiduPushService
在对应的方法里调用第三方服务中已经封装好的方法。

#import "AppDelegate.h"  
#import "SOAComponentAppDelegate.h"  
#import "BaiduPushService.h"  
  
@interface AppDelegate ()  
  
@end  
  
@implementation AppDelegate  
  
  
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {  
      
    id service;  
    for(service in [[SOAComponentAppDelegate instance] services]){  
        if ([service respondsToSelector:@selector(application:didFinishLaunchingWithOptions:)]){  
            [service application:application didFinishLaunchingWithOptions:launchOptions];  
        }  
    }  
      
    return YES;  
}  
  
- (void)applicationWillResignActive:(UIApplication *)application {  
    id service;  
    for(service in [[SOAComponentAppDelegate instance] services]){  
        if ([service respondsToSelector:@selector(applicationWillResignActive:)]){  
            [service applicationWillResignActive:application];  
        }  
    }  
}  
  
- (void)applicationDidEnterBackground:(UIApplication *)application {  
    id service;  
    for(service in [[SOAComponentAppDelegate instance] services]){  
        if ([service respondsToSelector:@selector(applicationDidEnterBackground:)]){  
            [service applicationDidEnterBackground:application];  
        }  
    }  
}  
  
- (void)applicationWillEnterForeground:(UIApplication *)application {  
    id service;  
    for(service in [[SOAComponentAppDelegate instance] services]){  
        if ([service respondsToSelector:@selector(applicationWillEnterForeground:)]){  
            [service applicationWillEnterForeground:application];  
        }  
    }  
}  
  
- (void)applicationDidBecomeActive:(UIApplication *)application {  
    id service;  
    for(service in [[SOAComponentAppDelegate instance] services]){  
        if ([service respondsToSelector:@selector(applicationDidBecomeActive:)]){  
            [service applicationDidBecomeActive:application];  
        }  
    }  
}  
  
- (void)applicationWillTerminate:(UIApplication *)application {  
    id service;  
    for(service in [[SOAComponentAppDelegate instance] services]){  
        if ([service respondsToSelector:@selector(applicationWillTerminate:)]){  
            [service applicationWillTerminate:application];  
        }  
    }  
}  
@end  

上面的范例你是不是对SOA面向服务的架构有一个初略的了解了呢。
其实网上有一个很好用的模块管理小工具FRDModuleManager
FRDModuleManager 是一个简单的 iOS 模块管理工具由豆瓣开发人员开放的。FRDModuleManager 可以减小 AppDelegate 的代码量,把很多职责拆分至各个模块中去。使得 AppDelegate 会变得容易维护。
如果你发现自己项目中实现了 UIApplicationDelegate 协议的 AppDelegate 变得越来越臃肿,你可能会需要这样一个类似的小工具;或者如果你的项目实施了组件化或者模块化,你需要为各个模块在 UIApplicationDelegate 定义的各个方法中留下钩子(hook),以便模块可以知晓整个应用的生命周期,你也可能会需要这样一个小工具,以便更好地管理模块在 UIApplicationDelegate 协议各个方法中留下的钩子。

FRDModuleManager 可以使得留在 AppDelegate 的钩子方法被统一管理。实现了 UIApplicationDelegate 协议的 AppDelegate 是我知晓应用生命周期的重要途径。如果某个模块需要在应用启动时初始化,那么我们就需要在 AppDelegate 的 application:didFinishLaunchingWithOptions: 调用一个该模块的初始化方法。模块多了,调用的初始化方法也会增多。最后,AppDelegate 会越来越臃肿。FRDModuleManager 提供了一个统一的接口,让各模块知晓应用的生命周期。这样将使 AppDelegate 得以简化。

严格来说,AppDelegate 除了通知应用生命周期之外就不应该担负其他的职责。对 AppDelegate 最常见的一种不太好的用法是,把全局变量挂在 AppDelegate 上。这样就获得了一个应用内可以使用的全局变量。如果你需要对项目实施模块化的话,挂了太多全局变量的 AppDelegate 将会成为一个棘手的麻烦。因为,这样的 AppDelegate 成为了一个依赖中心点。它依赖了很多模块,这一点还不算是一个问题。但是,由于对全局变量的访问需要通过 AppDelegate,这就意味着很多模块也同时依赖着 AppDelegate,这就是一个大问题了。这是因为,AppDelegate 可以依赖要拆分出去的模块;但反过来,要拆分出去的模块却不能依赖 AppDelegate。

这个问题,首先要将全局变量从 AppDelegate 上剔除。各个类应该自己直接提供对其的全局访问方法,最简单的实现方法是将类实现为单例。变量也可以挂在一个能提供全局访问的对象上。当然,这个对象不应该是 AppDelegate。

其次,对于 AppDelegate 仅应承担的责任:提供应用生命周期变化的通知。就可以通过使用 FRDModuleManager 更优雅地解决。

这两步之后,AppDelegate 的依赖问题可以很好地解决,使得 AppDelegate 不再是项目的依赖中心点。

下面讲解一下如何使用FRDModuleManager。
已JPush为例
首先创建一个实现Jpush 的类。继承于NSObject,然后导入
"FRDModuleManager.h" 遵守 协议

JPushModule.h

#import 
#import "FRDModuleManager.h"
@interface JPushModule : NSObject

@end

然后将Jpush的实现放在JPushModule的.m内部
//#import "syste"
@interface JPushModule ()
@property (nonatomic, strong) HYWPushServiceViewModel *viewModel;
@property (nonatomic, strong) NSTimer *homePageTimer;
/*是否已经成功将极光ID上传给后台。
 
 上传方法:[self uploadRegisterationIDAndUserID]
 上传时机:打开app + 从后台到前台 + 极光注册成功 + 登录成功
 
 YES:上传成功,不需要再上传
 NO: 上传失败,需要再次上传
 注意:登录,退出登录时要设置为NO,目的是为了再次上传
 **/
@property (nonatomic, assign) BOOL finishUpLoadJPUSHID;

@end
@implementation JPushModule


- (void)regisJPushWithOptions:(NSDictionary *)launchOptions
                pushViewModel:(HYWPushServiceViewModel *)viewModel
{
    self.viewModel = viewModel;
    //Required
    if ([[UIDevice currentDevice].systemVersion floatValue] >= 10.0) {
        JPUSHRegisterEntity * entity = [[JPUSHRegisterEntity alloc] init];
        entity.types = UNAuthorizationOptionAlert|UNAuthorizationOptionBadge|UNAuthorizationOptionSound;
        [JPUSHService registerForRemoteNotificationConfig:entity delegate:self];
        
    }else if ([[UIDevice currentDevice].systemVersion floatValue] >= 8.0) {
        //可以添加自定义categories
        [JPUSHService registerForRemoteNotificationTypes:(UIUserNotificationTypeBadge |
                                                          UIUserNotificationTypeSound |
                                                          UIUserNotificationTypeAlert)
                                              categories:nil];
    }else {
        //categories 必须为nil
        [JPUSHService registerForRemoteNotificationTypes:(UNAuthorizationOptionBadge |
                                                          UNAuthorizationOptionSound |
                                                          UNAuthorizationOptionAlert)
                                              categories:nil];
    }
    // Optional
    // 获取IDFA
    //     如需使用IDFA功能请添加此代码并在初始化方法的advertisingIdentifier参数中填写对应值
    [JPUSHService setupWithOption:launchOptions appKey:JPUSHAPPKey
                          channel:CHANNEL
                 apsForProduction:YES
            advertisingIdentifier:nil];
    
    [self uploadRegisterationIDAndUserID];
}
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    
    self.viewModel = [[HYWPushServiceViewModel alloc] init];
    [self regisJPushWithOptions:launchOptions pushViewModel:self.viewModel];
    
    return YES;
}
#pragma mark - 实现注册APNs失败接口
- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error
{
    //Optional
    NSLog(@"did Fail To Register For Remote Notifications With Error: %@", error);
}

#pragma mark - 实现注册APNs
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
{
    /// Required - 注册 DeviceToken
    [JPUSHService registerDeviceToken:deviceToken];
}

#pragma mark---- ios 7

- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo {
    // Required,For systems with less than or equal to iOS6
    [JPUSHService handleRemoteNotification:userInfo];
    [self push_handle:userInfo application:application];
}

#pragma mark---- ios 10.0

- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
    
    if ([[UIDevice currentDevice].systemVersion floatValue]<10.0 || application.applicationState>0) {
        
    }
    [self push_handle:userInfo application:application];
    // Required, iOS 7 Support
    [JPUSHService handleRemoteNotification:userInfo];
    
    completionHandler(UIBackgroundFetchResultNewData);
    
    
    // 应用在前台 或者后台开启状态下,不跳转页面,让用户选择。
    if (application.applicationState == UIApplicationStateActive || application.applicationState == UIApplicationStateBackground) {
        
    }
    else
    {
        
        //跳转到指定页面
        [self pushToViewController];
    }
}

- (void)applicationWillEnterForeground:(UIApplication *)application {
    
    [self uploadRegisterationIDAndUserID];
    
    UIWindow *window = [UIApplication sharedApplication].keyWindow;
    if (![window.rootViewController isKindOfClass:[LoginViewController class]]) {
        [self.homePageTimer setFireDate:[NSDate date]];
    }

    application.applicationIconBadgeNumber = 0;
    [JPUSHService setBadge:0];
    
}

- (void)applicationDidBecomeActive:(UIApplication *)application {

    application.applicationIconBadgeNumber = 0;
    [JPUSHService setBadge:0];
}

- (void)applicationWillTerminate:(UIApplication *)application {
}

- (void)uploadRegisterationIDAndUserID
{
    if (self.finishUpLoadJPUSHID) {
        return;
    }
    //判断token是否存在
    if (![[WSOTokenAgent sharedAgent] getAccessToken]) {
        return;
    }
    __weak typeof(self) this = self;
    NSString *registerationID = [JPUSHService registrationID];
    NSNumber *user_id =  [[NSUserDefaults standardUserDefaults] objectForKey:@"uid"];
    
    if (registerationID.length > 0) {
        
        [self.viewModel setBlockWithReturnBlock:^(id returnValue) {
            this.finishUpLoadJPUSHID = YES;
        } WithErrorBlock:^(id errorCode, NSString *message) {
            this.finishUpLoadJPUSHID = NO;
        } WithFailureBlock:^{
            this.finishUpLoadJPUSHID = NO;
        }];
        [self.viewModel wso_uploadRegisterationID:registerationID userID:user_id];
    }
}

#pragma mark - 
- (void)jpushNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(NSInteger))completionHandler
{
    // Required
    NSDictionary * userInfo = notification.request.content.userInfo;
    if([notification.request.trigger isKindOfClass:[UNPushNotificationTrigger class]]) {
        [JPUSHService handleRemoteNotification:userInfo];
        
        
        NSLog(@"%ld",(long)[UIApplication sharedApplication].applicationState);
        
        if ([UIApplication sharedApplication].applicationState == UIApplicationStateActive) {
            //程序运行时收到通知,先弹出消息框
            NSLog(@"程序在前台");
        }
        
        else{
            //跳转到指定页面
            [self pushToViewController];
        }
    }
    completionHandler(UNNotificationPresentationOptionAlert); // 需要执行这个方法,选择是否提醒用户,有Badge、Sound、Alert三种类型可以选择设置
}

- (void)jpushNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void (^)())completionHandler
{
    // Required
    NSDictionary * userInfo = response.notification.request.content.userInfo;
    NSLog(@"response====%@",response);
    //    NSString *type = userInfo[@"type"];
    
    if([response.notification.request.trigger isKindOfClass:[UNPushNotificationTrigger class]]) {
        [JPUSHService handleRemoteNotification:userInfo];
        
        if ([UIApplication sharedApplication].applicationState == UIApplicationStateActive) {//用户点击的时候执行跳转
            
            //程序运行时收到通知,先弹出消息框
            [self pushToViewController];//程序激活状态下点击跳转逻辑
            //            [self pushToViewControllerWithTypeStr:type];
            
        }
        
        else{
            //跳转到指定页面
            [self pushToViewController];
        }
    }
    completionHandler();  // 系统要求执行这个方法
    [self push_handle:@{} application:nil];
}

- (void)push_handle:(NSDictionary *)userInfo application:(UIApplication *)application{
    
    [[NSNotificationCenter defaultCenter] postNotificationName:@"JPUSH" object:nil];
    application.applicationIconBadgeNumber = 0;
    
}

- (void)pushToViewController{
    
    UIViewController *vc = nil;
    if ([self.window.rootViewController isKindOfClass:[UINavigationController class]]) {
        vc = ((UINavigationController *)self.window.rootViewController).viewControllers.lastObject;
    }else{
        vc = self.window.rootViewController;
    }
    
    //判断如果是在登录页面,那么不进行跳转
    if ([vc isKindOfClass:[LoginViewController class]]) {
        return;
    }
    //判断如果是在消息中心页面,那么不进行跳转
    if ([vc isKindOfClass:[MessageCenterViewController class]]) {
        return;
    }
    
    MessageCenterViewController *messageVC = [MessageCenterViewController new];
    if (vc.presentedViewController) {
        //根控制器不是导航控制器
        messageVC.isPresent = YES;
        UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:messageVC];
        //实现转场动画 present的时候实现push的动画效果。
        [vc.presentedViewController wxs_presentViewController:nav animationType:WXSTransitionAnimationTypeSysPushFromRight completion:nil];
    }else{
        //根控制器是导航控制器
        UINavigationController *nav = (UINavigationController *)vc;
        
        [nav pushViewController:messageVC animated:YES];
    }
}

//根据不同的type类型进行跳转
- (void)pushToViewControllerWithTypeStr:(NSString *)typeStr{
    UIViewController *vc = nil;
    if ([self.window.rootViewController isKindOfClass:[UINavigationController class]]) {
        vc = ((UINavigationController *)self.window.rootViewController).viewControllers.lastObject;
    }else{
        vc = self.window.rootViewController;
    }
    
    //判断如果是在登录页面,那么不进行跳转
    if ([vc isKindOfClass:[LoginViewController class]]) {
        return;
    }
    //判断如果是在告警提醒中心页面,那么不进行跳转
    if ([vc isKindOfClass:[MessageCenterViewController class]]) {
        return;
    }
//    //判断如果是在系统通知中心页面,那么不进行跳转
//    if ([vc isKindOfClass:[SystematicNotificationViewController class]]) {
//        return;
//    }
    if ([typeStr isEqualToString:@"msg"]) {
        MessageCenterViewController *messageVC = [MessageCenterViewController new];
        if (vc.presentedViewController) {
            //根控制器不是导航控制器
            messageVC.isPresent = YES;
            UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:messageVC];
            //实现转场动画 present的时候实现push的动画效果。
            [vc.presentedViewController wxs_presentViewController:nav animationType:WXSTransitionAnimationTypeSysPushFromRight completion:nil];
        }else{
            //根控制器是导航控制器
            UINavigationController *nav = (UINavigationController *)vc;
            [nav pushViewController:messageVC animated:YES];
        }
    }
    

在APPDelegate文件中导入#import "FRDModuleManager.h"

FRDModuleManager 使用一个 plist 文件注册所有模块

- (BOOL)application:(UIApplication *)application willFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    
    NSString* plistPath = [[NSBundle mainBundle] pathForResource:@"ModulesRegister" ofType:@"plist"];
    
    FRDModuleManager *manager = [FRDModuleManager sharedInstance];
    [manager loadModulesWithPlistFile:plistPath];
    
    [manager application:application willFinishLaunchingWithOptions:launchOptions];
    
    return YES;
}

在 UIApplicationDelegate 各方法中留下钩子

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {

  NSString* plistPath = [[NSBundle mainBundle] pathForResource:@"ModulesRegister" ofType:@"plist"];
  FRDModuleManager *manager = [FRDModuleManager sharedInstance];
  [manager loadModulesWithPlistFile:plistPath];

  [manager application:application didFinishLaunchingWithOptions:launchOptions];

  return YES;
}


- (void)applicationWillResignActive:(UIApplication *)application {
  [[FRDModuleManager sharedInstance] applicationWillResignActive:application];
}

- (void)applicationDidEnterBackground:(UIApplication *)application {
  [[FRDModuleManager sharedInstance] applicationDidEnterBackground:application];
}

- (void)applicationWillEnterForeground:(UIApplication *)application {
  [[FRDModuleManager sharedInstance] applicationWillEnterForeground:application];
}

- (void)applicationDidBecomeActive:(UIApplication *)application {
  [[FRDModuleManager sharedInstance] applicationDidBecomeActive:application];
}

- (void)applicationWillTerminate:(UIApplication *)application {
  [[FRDModuleManager sharedInstance] applicationWillTerminate:application];
}

#pragma mark - Handling Remote Notification

- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
  [[FRDModuleManager sharedInstance] application:application didRegisterForRemoteNotificationsWithDeviceToken:deviceToken];
}

- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error {
  [[FRDModuleManager sharedInstance] application:application didFailToRegisterForRemoteNotificationsWithError:error];
}

- (void)application:(UIApplication *)application
  didReceiveRemoteNotification:(NSDictionary *)userInfo
  fetchCompletionHandler:(void (^)(UIBackgroundFetchResult result))completionHandler
{
  [[FRDModuleManager sharedInstance] application:application
                    didReceiveRemoteNotification:userInfo
                          fetchCompletionHandler:completionHandler];
}

- (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification {
  [[FRDModuleManager sharedInstance] application:application
                     didReceiveLocalNotification:notification];
}

- (void)userNotificationCenter:(UNUserNotificationCenter *)center
       willPresentNotification:(UNNotification *)notification
         withCompletionHandler:(void (^)(UNNotificationPresentationOptions options))completionHandler
{
  [[FRDModuleManager sharedInstance] userNotificationCenter:center
                                    willPresentNotification:notification
                                      withCompletionHandler:completionHandler];
}

- (void)userNotificationCenter:(UNUserNotificationCenter *)center
didReceiveNotificationResponse:(UNNotificationResponse *)response
         withCompletionHandler:(void (^)())completionHandler
{
  [[FRDModuleManager sharedInstance] userNotificationCenter:center
                             didReceiveNotificationResponse:response
                                      withCompletionHandler:completionHandler];
}
在 FRDModuleManager 被 UIApplicationDelegate 各方法内留下的钩子调用时,会调用注册的每个模块的相同的方法。这样每个模块就都知晓了应用的生命周期

其实FRDModuleManager的内部原理就是将所有的第三方的实现封装到各自的FRDModule内部,然后将FRDModule添加到自己的服务数组中,然后在程序的不同生命周期中遍历所有的服务,然后去调用FRDModule内部的注册方法,实现对第三方服务的封装,这样可以让APPdelegate内部的代码更加整洁清晰,不同的FRDModule实现不同的服务注册,方便管理。

你可能感兴趣的:(为AppDelegate解耦和瘦身)