iOS 给AppDelegate瘦身
项目中经常要用到第三方的SDK每次都要在AppDelegate中注册APPKEY 接受回调等 这样就使本来很简洁的AppDelegate中的代码越来越多 那么问题来了 怎样把这些第三方的代码提到其他的地方使用啊?
runtime是一个好东西 给AppDelegate写个分类(AppDelegate+TimingChat) 在分类中替换原来的方法。
本人项目中是这样写的 如下:
#import "AppDelegate+TimingChat.h"
#import <objc/runtime.h>
#import "TimingCustomAttachmentDecoder.h"
#import "TimingCellLayoutConfig.h"
#define APPKEY @""
#define APNSCERNAME @""
//这个暂时不需要
#define PKCERNAME @""
@implementation AppDelegate (TimingChat)
+(void)load {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
Class class = [self class];
swizzleMethod(class, @selector(application:didFinishLaunchingWithOptions:), @selector(aop_application:didFinishLaunchingWithOptions:));
swizzleMethod(class, @selector(applicationDidEnterBackground:), @selector(aop_applicationDidEnterBackground:));
swizzleMethod(class, @selector(applicationWillEnterForeground:), @selector(aop_applicationWillEnterForeground:));
swizzleMethod(class, @selector(applicationDidBecomeActive:), @selector(aop_applicationDidBecomeActive:));
swizzleMethod(class, @selector(applicationWillTerminate:), @selector(aop_applicationWillTerminate:));
swizzleMethod(class, @selector(application:didRegisterForRemoteNotificationsWithDeviceToken:), @selector(aop_application:didRegisterForRemoteNotificationsWithDeviceToken:));
swizzleMethod(class, @selector(handleNotification:), @selector(aop_handleNotification:));
});
}
static inline void swizzleMethod(Class class, SEL originalSelector, SEL swizzledSelector) {
Method originalMethod = class_getInstanceMethod(class, originalSelector);
Method swizzledMethod = class_getInstanceMethod(class, swizzledSelector);
BOOL didAddMethod = class_addMethod(class, originalSelector, method_getImplementation(swizzledMethod), method_getTypeEncoding(swizzledMethod));
if (didAddMethod) {
class_replaceMethod(class, swizzledSelector, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod));
} else {
method_exchangeImplementations(originalMethod, swizzledMethod);
}
}
- (BOOL)aop_application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
NSLog(@"分类launchOptions");
[self aop_application:application didFinishLaunchingWithOptions:launchOptions];
NIMServerSetting *setting = [[NIMServerSetting alloc] init];
//#ifdef DEBUG
// setting.httpsEnabled = NO;
//#endif
setting.httpsEnabled = NO;
[[NIMSDK sharedSDK] setServerSetting:setting];
[[NIMSDK sharedSDK] registerWithAppID:APPKEY cerName:APNSCERNAME];
[[TNIMNotificationCenter sharedCenter] start];
//自定义消息布局
[[NIMKit sharedKit] registerLayoutConfig:[TimingCellLayoutConfig new]];
//自定义消息对象序列化
[NIMCustomObject registerCustomDecoder:[[TimingCustomAttachmentDecoder alloc]init]];
//存云端历史
NIMMessageSetting *messageSetting = [[NIMMessageSetting alloc] init];
messageSetting.historyEnabled = YES;
[[NIMSDK sharedSDK].loginManager addDelegate:self];
[self registerAPNs];
return YES;
}
#pragma mark - 退出登陆
-(void)setupLogout{
[[[NIMSDK sharedSDK] loginManager] logout:^(NSError *error) {
if (error == nil){
NSLog(@"云信退出登陆");
}
}];
}
#pragma mark -多端登陆问题 踢下线
-(void)onKick:(NIMKickReason)code clientType:(NIMLoginClientType)clientType{
[self setupLogout];
[self postNotification:KL_NOTIFICATION_ACCOUNT_LOGIN_OTHER];
}
#pragma mark -自动登陆的回调
-(void)onLogin:(NIMLoginStep)step{
switch (step) {
case NIMLoginStepLinking:{//链接服务器
NSLog(@"链接服务器");
}
break;
case NIMLoginStepLinkOK:{//连接服务器成功
NSLog(@"连接服务器成功");
}
break;
case NIMLoginStepLinkFailed:{//连接服务器失败
NSLog(@"连接服务器失败");
}
break;
case NIMLoginStepLogining:{//登陆中
NSLog(@"登陆中");
}
break;
case NIMLoginStepLoginOK:{//登陆成功
NSLog(@"登陆成功");
}
break;
case NIMLoginStepLoginFailed:{//登陆失败
NSLog(@"登陆失败");
[[[TAlertView alloc] initWithErrorMsg:@"自动--登陆失败"] showStatusWithDuration:1.5];
}
break;
case NIMLoginStepLoseConnection:{//链接断开
NSLog(@"链接断开");
}
break;
default:
break;
}
}
#pragma mark -手动登陆
-(void)loginManual{
NSLog(@"手动登陆");
[SharedApiClient neteaseimCreateUserGetTokenWithUserID:^(NSURLSessionDataTask *task, KLApiResponse *aResponse, NSError *anError) {
NSLog(@"createUserGetToken=====:%@",aResponse.data);
if (aResponse.success) {
NSString *token = aResponse.data[@"token"];
NSString *account = aResponse.data[@"accid"];
SharedData.user.token = token;
SharedData.user.account = account;
[[[NIMSDK sharedSDK] loginManager] login:account
token:token
completion:^(NSError *error) {
if (!error){
NSLog(@"手动登陆----云信登陆成功。。。。。。。。。。");
//覆盖更新的用户要调用云信的修改用户资料
[[NIMSDK sharedSDK].userManager updateMyUserInfo:@{@(NIMUserInfoUpdateTagNick):SharedData.user.nickname,@(NIMUserInfoUpdateTagAvatar):SharedData.user.avatar,@(NIMUserInfoUpdateTagExt):SharedData.user.categoryAlias} completion:nil];
//将群的通知关闭
NSArray *array = [SharedCache allTeamInfo];
for (TTeamChannelInfoModel *teamInfo in array) {
[[NIMSDK sharedSDK].teamManager updateNotifyState:NIMTeamNotifyStateNone inTeam:teamInfo.teamID completion:nil];
}
}else{
NSString *toast = [NSString stringWithFormat:@"登录失败 code:%ld",error.code];
NSLog(@"toast====%@",toast);
[[[TAlertView alloc] initWithErrorMsg:toast] showStatusWithDuration:1.5];
}
}];
}
}];
}
#pragma mark - 登陆
- (void)setupLogin
{
if (!SharedData.user.token) {
[self loginManual];
}else{
NSLog(@"开始自动登陆");
NIMAutoLoginData *loginData = [[NIMAutoLoginData alloc] init];
loginData.account = SharedData.user.account;
loginData.token = SharedData.user.token;
NSLog(@"SharedData.user.account====%@",SharedData.user.account);
NSLog(@"SharedData.user.token====%@",SharedData.user.token);
[[[NIMSDK sharedSDK] loginManager] autoLogin:loginData];
}
}
#pragma mark - 客户端注册 APNS,并在获取到 APNS Token 时将值传给 SDK
- (void)registerAPNs
{
if ([[UIApplication sharedApplication] respondsToSelector:@selector(registerForRemoteNotifications)]){
UIUserNotificationType types = UIUserNotificationTypeBadge | UIUserNotificationTypeSound | UIUserNotificationTypeAlert;
UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:types categories:nil];
[[UIApplication sharedApplication] registerUserNotificationSettings:settings];
[[UIApplication sharedApplication] registerForRemoteNotifications];
}else{
UIRemoteNotificationType types = UIRemoteNotificationTypeAlert | UIRemoteNotificationTypeSound | UIRemoteNotificationTypeBadge;
[[UIApplication sharedApplication] registerForRemoteNotificationTypes:types];
// UNAuthorizationOptions typeax = UNAuthorizationOptionBadge | UNAuthorizationOptionSound |UNAuthorizationOptionAlert;
//
// [[UIApplication sharedApplication] registerForRemoteNotifications];
}
}
-(void)aop_applicationDidEnterBackground:(UIApplication *)application{
[self aop_applicationDidEnterBackground:application];
NSLog(@"分类 applicationDidEnterBackground");
}
-(void)aop_applicationWillEnterForeground:(UIApplication *)application{
[self aop_applicationWillEnterForeground:application];
NSLog(@"分类 applicationWillEnterForeground");
}
-(void)aop_applicationDidBecomeActive:(UIApplication *)application{
[self aop_applicationDidBecomeActive:application];
NSLog(@"分类 applicationDidBecomeActive");
}
-(void)aop_applicationWillTerminate:(UIApplication *)application{
[self aop_applicationWillTerminate:application];
NSLog(@"分类 applicationWillTerminate");
}
#pragma mark - 获取到 APNS Token 时将值传给 SDK
-(void)aop_application:(UIApplication *)app didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken{
[self aop_application:app didRegisterForRemoteNotificationsWithDeviceToken:deviceToken];
// NSLog(@"分类----deviceToken======%@",deviceToken);
[[NIMSDK sharedSDK] updateApnsToken:deviceToken];
}
@end
runtime的方法交换是个好东西(也是魔鬼)
细心的读者应该注意到了下面的方法中调用了 [self aop_applicationDidEnterBackground:application]; 会产生死循环调用的问题吗?其实没有死循环 他会调用原来的方法applicationDidEnterBackground: 在调用aop_applicationDidEnterBackground:替换的方法 这样就不会影响原来的applicationDidEnterBackground:方法里面的调用内容
-(void)aop_applicationDidEnterBackground:(UIApplication *)application{
[self aop_applicationDidEnterBackground:application];
NSLog(@"分类 applicationDidEnterBackground");
}
这样就可以给AppDelegate瘦身了 其他的第三方可以这样写