iOS Crazies

iOS零行代码搞定本地通知

2017-12-19  本文已影响13人  hehtao

本地通知很简单喽,关键是这个零行如何实现? 也许你已经知道了,runtime 嘛,只需要将 AppDelegate 的分类 .m文件拖进工程即可,彻底解放你的 AppDelegate.m;


一.原理解析:

使用runtime 在 +(void)load 替换 UIApplicationDelegate一些方法的实现,比如:

application:didFinishLaunchingWithOptions:
application:handleActionWithIdentifier:forLocalNotification:completionHandler:
...等等通知相关的代理方法,在自己的方法实现处理通知;

二.上代码:

1.新建 AppDelegate 分类,只要 .m文件即可:
2. 实现基本的方法交换接口:+(void)swapSelector:(SEL)systemSelector toSelector:(SEL)customSelector;
3. 在自己的方法实现中处理通知相关代码:
如下:
1 . 新建 AppDelegate 分类: 略过 ....
2 . 基本接口实现骨架:

+(void)swapSelector:(SEL)systemSelector toSelector:(SEL)customSelector{
//    static dispatch_once_t onceToken;
//    dispatch_once(&onceToken, ^{
        SEL org_Selector = systemSelector;
        SEL new_Selector  = customSelector;
        
        Method org_method = class_getInstanceMethod([self class], org_Selector);
        Method new_method  = class_getInstanceMethod([self class], new_Selector);
        
        BOOL isAdd = class_addMethod(self, org_Selector, method_getImplementation(new_method), method_getTypeEncoding(new_method));
        if (isAdd) {
            class_replaceMethod(self, customSelector, method_getImplementation(new_method), method_getTypeEncoding(new_method));
        }else{
            method_exchangeImplementations(org_method, new_method);
        }
//    });
}

注意: 这里的 dispatch_once 是注释掉的!!!!

3 . 在自己的方法实现中处理通知相关代码:

@implementation AppDelegate (LocalNotification)

+(void)load{
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{  // 知道为什么上面没有 dispatch_once 了吧;
        [self swapSelector:@selector(application:didFinishLaunchingWithOptions:)                                                            toSelector:@selector(GIN_application:didFinishLaunchingWithOptions:)];
        [self swapSelector:@selector(application:didRegisterUserNotificationSettings:)  toSelector:@selector(GIN_application:didRegisterUserNotificationSettings:)];
        [self swapSelector:@selector(application:handleActionWithIdentifier:forLocalNotification:completionHandler:) toSelector:@selector(GIN_application:handleActionWithIdentifier:forLocalNotification:completionHandler:)];
        [self swapSelector:@selector(application:handleActionWithIdentifier:forLocalNotification: withResponseInfo: completionHandler:) toSelector:@selector(GIN_application:handleActionWithIdentifier:forLocalNotification: withResponseInfo: completionHandler:) ];
        [self swapSelector:@selector(application:didReceiveLocalNotification:) toSelector:@selector(GIN_application:didReceiveLocalNotification:)];
    });
    
}


-(BOOL)GIN_application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{
    [self GIN_application:application didFinishLaunchingWithOptions:launchOptions];
    [self configLocalNotificationWithApplication:application];
    return YES;
}

-(void)GIN_application:(UIApplication *)application didRegisterUserNotificationSettings:(UIUserNotificationSettings *)notificationSettings{
    [self GIN_application:application didRegisterUserNotificationSettings:notificationSettings];
    /*
     *  your code (通知相关)
     */
    
}

-(void)GIN_application:(UIApplication *)application handleActionWithIdentifier:(NSString *)identifier forLocalNotification:(UILocalNotification *)notification completionHandler:(void (^)())completionHandler{
    [self GIN_application:application handleActionWithIdentifier:identifier forLocalNotification:notification completionHandler:completionHandler];
    /*
     *  your code (通知相关)
     */
}

-(void)GIN_application:(UIApplication *)application handleActionWithIdentifier:(NSString *)identifier forLocalNotification:(UILocalNotification *)notification withResponseInfo:(NSDictionary *)responseInfo completionHandler:(void (^)())completionHandler{
    [self GIN_application:application handleActionWithIdentifier:identifier forLocalNotification:notification withResponseInfo:responseInfo completionHandler:completionHandler];
    /*
     *  your code (通知相关)
     */
}

-(void)GIN_application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification{
    [self GIN_application:application didReceiveLocalNotification:notification];
    /*
     *  your code (通知相关)
     */
}

三.完整代码:

//
//  AppDelegate+LocalNotification.m

#import "AppDelegate.h"
#import <UserNotifications/UserNotifications.h>
#import "NSObject+swapMethod.h"

@interface AppDelegate ()<UNUserNotificationCenterDelegate>
@end

NSInteger badge;

@implementation AppDelegate (LocalNotification)

+(void)load{
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        [self swapSelector:@selector(application:didFinishLaunchingWithOptions:)                                                            toSelector:@selector(GIN_application:didFinishLaunchingWithOptions:)];
        [self swapSelector:@selector(application:didRegisterUserNotificationSettings:)  toSelector:@selector(GIN_application:didRegisterUserNotificationSettings:)];
        [self swapSelector:@selector(application:handleActionWithIdentifier:forLocalNotification:completionHandler:) toSelector:@selector(GIN_application:handleActionWithIdentifier:forLocalNotification:completionHandler:)];
        [self swapSelector:@selector(application:handleActionWithIdentifier:forLocalNotification: withResponseInfo: completionHandler:) toSelector:@selector(GIN_application:handleActionWithIdentifier:forLocalNotification: withResponseInfo: completionHandler:) ];
        [self swapSelector:@selector(application:didReceiveLocalNotification:) toSelector:@selector(GIN_application:didReceiveLocalNotification:)];
    });
    
}

-(BOOL)GIN_application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{
    [self GIN_application:application didFinishLaunchingWithOptions:launchOptions];
    [self configLocalNotificationWithApplication:application];
    return YES;
}

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

    if ([[UIDevice currentDevice] systemVersion].floatValue >= 10.0) {
        UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
        center.delegate = self;
        [center requestAuthorizationWithOptions:(UNAuthorizationOptionBadge | UNAuthorizationOptionSound | UNAuthorizationOptionAlert) completionHandler:^(BOOL granted, NSError * _Nullable error) {
            if (granted)  //点击允许
            {
                NSLog(@"注册通知成功");
                [center getNotificationSettingsWithCompletionHandler:^(UNNotificationSettings * _Nonnull settings) {
                    [self registerCalendarNotificationTrigger:YES locationNotificationTrigger:YES];
                }];
            } else//点击不允许
            {
                NSLog(@"注册通知失败");
            }
        }];
        //注册推送(同iOS8)
        [[UIApplication sharedApplication] registerForRemoteNotifications];
        
    }else if([[UIDevice currentDevice] systemVersion].floatValue < 10.0 &&[[UIDevice currentDevice] systemVersion].floatValue >= 8.0){//iOS8到iOS10

        //1.创建消息上面要添加的动作(按钮的形式显示出来)
        UIMutableUserNotificationAction *action = [[UIMutableUserNotificationAction alloc] init];
        action.identifier = @"action";//按钮的标示
        action.title=@"Accept";//按钮的标题
        action.activationMode = UIUserNotificationActivationModeForeground;//当点击的时候启动程序
        //    action.authenticationRequired = YES;
        //    action.destructive = YES;

        UIMutableUserNotificationAction *action2 = [[UIMutableUserNotificationAction alloc] init];
        action2.identifier = @"action2";
        action2.title=@"Reject";
        action2.activationMode = UIUserNotificationActivationModeBackground;//当点击的时候不启动程序,在后台处理
        action.authenticationRequired = YES;//需要解锁才能处理,如果action.activationMode = UIUserNotificationActivationModeForeground;则这个属性被忽略;
        action.destructive = YES;

        //2.创建动作(按钮)的类别集合
        UIMutableUserNotificationCategory *categorys = [[UIMutableUserNotificationCategory alloc] init];
        categorys.identifier = @"alert";//这组动作的唯一标示,推送通知的时候也是根据这个来区分
        [categorys setActions:@[action,action2] forContext:(UIUserNotificationActionContextMinimal)];

        //3.创建UIUserNotificationSettings,并设置消息的显示类类型
        if ([[UIApplication sharedApplication] respondsToSelector:@selector(registerUserNotificationSettings:)]) {
            UIUserNotificationType type =  UIUserNotificationTypeAlert | UIUserNotificationTypeBadge | UIUserNotificationTypeSound;
            UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:type categories:nil];
            [[UIApplication sharedApplication] registerUserNotificationSettings:settings];
        }
    }else {//iOS8以下
        [application registerForRemoteNotificationTypes: UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeAlert | UIRemoteNotificationTypeSound];
    }
}

-(void)GIN_application:(UIApplication *)application didRegisterUserNotificationSettings:(UIUserNotificationSettings *)notificationSettings{
    [self GIN_application:application didRegisterUserNotificationSettings:notificationSettings];
    if(notificationSettings.types & UIUserNotificationTypeBadge){

    }else if (notificationSettings.types & UIUserNotificationTypeAlert){

    }else if (notificationSettings.types & UIUserNotificationTypeSound){

    }else if (notificationSettings.types & UIUserNotificationTypeNone){

    }else{
        // what happened ??
    }
}

-(void)registerCalendarNotificationTrigger:(BOOL)calendarTrigger locationNotificationTrigger:(BOOL)locationTrigger{
        // 1、创建通知内容,注:这里得用可变类型的UNMutableNotificationContent,否则内容的属性是只读的
    UNMutableNotificationContent *content = [[UNMutableNotificationContent alloc] init];
    content.title = @"小主,还有15分钟就要上班了哦";
    content.subtitle = @"快让列车长开快点";
    content.body = @"我知道小主很着急,但是注意安全哦";
    badge++;
    content.badge = [NSNumber numberWithInteger:badge];
    content.sound = [UNNotificationSound defaultSound];

    NSString *path = [[NSBundle mainBundle] pathForResource:@"search_blue@2x" ofType:@"png"];
    UNNotificationAttachment *attachment = [UNNotificationAttachment attachmentWithIdentifier:@"imageIndetifier" URL:[NSURL fileURLWithPath:path] options:nil error:nil];
    // 附件 可以是音频、图片、视频 这里是一张图片
    content.attachments = @[attachment];
    
    // 标识符
    content.categoryIdentifier = @"categoryIndentifier";
    // 2、创建通知触发
    /* 触发器分三种:
     UNTimeIntervalNotificationTrigger : 在一定时间后触发,如果设置重复的话,timeInterval不能小于60
     UNCalendarNotificationTrigger : 在某天某时触发,可重复
     UNLocationNotificationTrigger : 进入或离开某个地理区域时触发
     */
    
    // UNCalendarNotificationTrigger
    if (calendarTrigger) {
        NSDateComponents *components = [[NSDateComponents alloc] init];
        components.hour = 8;
        components.minute = 45;
        components.second = 0;
        UNCalendarNotificationTrigger *cTrigger = [UNCalendarNotificationTrigger triggerWithDateMatchingComponents:components repeats:YES];
        UNNotificationRequest *calendarNotificationRequest = [UNNotificationRequest requestWithIdentifier:@"KFGroupNotification" content:content trigger:cTrigger];
        [[UNUserNotificationCenter currentNotificationCenter] addNotificationRequest:calendarNotificationRequest withCompletionHandler:^(NSError * _Nullable error) {
            if (!error) {
                NSLog(@"已成功添加calendar推送%@",calendarNotificationRequest.identifier);
            }
        }];
    }

    //UNLocationNotificationTrigger
    if (locationTrigger) {
        CLCircularRegion *circularRegion = [[CLCircularRegion alloc] initWithCenter:CLLocationCoordinate2DMake(39.9573921487, 116.2690370559) radius:1000.f identifier:@"circularRegionNotification"];
        UNLocationNotificationTrigger *localTrigger = [UNLocationNotificationTrigger  triggerWithRegion: circularRegion repeats:YES];
        UNNotificationRequest *localNotificationRequest = [UNNotificationRequest requestWithIdentifier:@"circularRegionNotification" content:content trigger:localTrigger];
        [[UNUserNotificationCenter currentNotificationCenter] addNotificationRequest:localNotificationRequest withCompletionHandler:^(NSError * _Nullable error) {
            if (!error) {
                NSLog(@"已成功添加circular推送%@",localNotificationRequest.identifier);
            }
        }];
    }

//    if (UNTimeIntervalNotificationTrigger) {}
}


//Begin ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ iOS10 - lastest 推送回调  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
#pragma mark - iOS10 及 10以上  __IOS_AVAILABLE(10.0) 推送代理
- (void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions))completionHandler {
    NSLog(@"应用在前/后台收到通知%@", notification.request.identifier);
    //如果需要在应用在前台也展示通知
    completionHandler(UNNotificationPresentationOptionBadge|UNNotificationPresentationOptionSound|UNNotificationPresentationOptionAlert);
}

- (void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void(^)())completionHandler {

    NSLog(@"点击通知栏:%@",response.notification.request.identifier);
    // 根据类别标识符处理目标反应
    if ([response.notification.request.content.categoryIdentifier isEqualToString:@"categoryIndentifier"]) {
        [self handleResponse:response];
    }
    completionHandler();
}

- (void)handleResponse:(UNNotificationResponse *)response {
    // response.actionIdentifier;
    // The action identifier that the user chose:
    // * UNNotificationDismissActionIdentifier if the user dismissed the notification
    // * UNNotificationDefaultActionIdentifier if the user opened the application from the notification
    // * the identifier for a registered UNNotificationAction for other actions
    if ([response.actionIdentifier isEqualToString:UNNotificationDismissActionIdentifier]) {
        
    }else if ([response.actionIdentifier isEqualToString:UNNotificationDefaultActionIdentifier]){
        
    }else{
        // what happened ??
    }
    NSString *actionIndentifier = response.actionIdentifier;
    NSLog(@"%@",@"处理通知");
}
//End ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ iOS10 - lastest 推送回调  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^




//Begin ****************************************** iOS8 - 10 推送回调 ***************************************************
#pragma mark - iOS8 - 10 NS_DEPRECATED_IOS(8_0, 10_0) 推送代理
- (void)GIN_application:(UIApplication *)application handleActionWithIdentifier:(nullable NSString *)identifier forLocalNotification:(UILocalNotification *)notification completionHandler:(void(^)())completionHandler{
    [self GIN_application:application handleActionWithIdentifier:identifier forLocalNotification:notification completionHandler:completionHandler];
        if ([identifier isEqualToString:@"alert"]) {

        }
        completionHandler();
    }
#pragma mark - NS_DEPRECATED_IOS(9_0, 10_0)
- (void)GIN_application:(UIApplication *)application handleActionWithIdentifier:(nullable NSString *)identifier forLocalNotification:(UILocalNotification *)notification withResponseInfo:(NSDictionary *)responseInfo completionHandler:(void(^)())completionHandler{
    [self GIN_application:application handleActionWithIdentifier:identifier forLocalNotification:notification withResponseInfo:responseInfo completionHandler:completionHandler];
    NSLog(@"handleActionWithIdentifier");
}

#pragma mark - NS_DEPRECATED_IOS(4_0, 10_0)  收到推送消息
- (void)GIN_application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification{
    [self GIN_application:application didReceiveLocalNotification:notification];
        NSLog(@"didReceiveLocalNotification notification");
}
//End ****************************************** iOS8 - 10 推送回调 ***************************************************
@end

上一篇下一篇

猜你喜欢

热点阅读