关于iOS本地推送的那些事儿

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_27339239/article/details/52184967

最近在做一个项目,需要大量的本地推送,本地推送有一个坑,就是iOS系统限制了注册本地推送的数量,最大的注册量为64条,没有那么多的容量供我们挥霍。网上相关的文章比较少提到推送数量限制。

不说废话,请看代码
AppDelegate.m

#import "AppDelegate.h"

@interface AppDelegate ()

@end

@implementation AppDelegate


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

    //注册本地通知
    [self registerLocalNotification];

    return YES;
}


- (void)registerLocalNotification{

    /**
     *iOS 8之后需要向系统注册通知,让用户开放权限
     */
    if (CurrenVersiongreaterThan(@"8.0")) {
        if ([[UIApplication sharedApplication] respondsToSelector:@selector(registerUserNotificationSettings:)]) {

            UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeBadge|UIUserNotificationTypeSound|UIUserNotificationTypeAlert categories:nil];

            [[UIApplication sharedApplication] registerUserNotificationSettings:settings];
        }
    }
}

- (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification{
    UIApplicationState state = application.applicationState;
    if (state == UIApplicationStateActive) {
        if (CurrenVersiongreaterThan(@"9.0")) {
            UIAlertController * alert = [UIAlertController alertControllerWithTitle:@"警告" message:notification.alertBody preferredStyle:UIAlertControllerStyleAlert];
            UIAlertAction *okAction = [UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleDefault handler:nil];
            [alert addAction:okAction];
            [self.window.rootViewController presentViewController:alert animated:YES completion:nil];

        }else{
            UIAlertView * alert = [[UIAlertView alloc] initWithTitle:@"警告" message:notification.alertBody delegate:nil cancelButtonTitle:@"确定" otherButtonTitles:nil, nil];
            [alert show];

        }

        //清除已经推送的消息
        [LocalNotificationManager  compareFiretime:notification needRemove:^(UILocalNotification *item) {
            [[UIApplication sharedApplication] cancelLocalNotification:notification];
        }];
    }

}

@end

创建一个本地推送的管理类 LocalNotificationManager
LocalNotificationManager.h 放出两个方法,供外部调用,可以根据工程适量增加API

#import <Foundation/Foundation.h>


@interface LocalNotificationManager : NSObject

+ (BOOL)insertLocalNotificationToSystemQueueWithNotificationID:(NSString *)notificationID;

+ (void)compareFiretime:(UILocalNotification *)notification needRemove:(void(^)(UILocalNotification * item))needRemove;
@end

LocalNotificationManager.m

#import "LocalNotificationManager.h"

#define KEY_NOTIFICATION @"this is a key for notification"

@implementation LocalNotificationManager

+ (BOOL)insertLocalNotificationToSystemQueueWithNotificationID:(NSString *)notificationID{

    //新增前先清楚已注册的相同ID的本地推送
    [self deleteLocadNotificationWithNotificationID:notificationID];

    //初始化
    UILocalNotification * localNotification = [[UILocalNotification alloc] init];

    //设置开火时间(演示为当前时间5秒后)
    localNotification.fireDate = [NSDate dateWithTimeIntervalSinceNow:5];

    //设置时区,取手机系统默认时区
    localNotification.timeZone = [NSTimeZone defaultTimeZone];

    //重复次数 kCFCalendarUnitEra为不重复
    localNotification.repeatInterval = kCFCalendarUnitEra;

    //通知的主要内容
    localNotification.alertBody = @"人生苦短,我用Objcetive-C";

    //小提示
    localNotification.alertAction = @"查看详情";

    //设置音效,系统默认为电子音,在系统音效中标号为1015
    localNotification.soundName = UILocalNotificationDefaultSoundName;

    //or localNotification.soundName = @"send.caf" 自己的音频文件

    //localNotification.applicationIconBadgeNumber = 1; Icon上的红点和数字

    //查找本地系统通知的标识
    localNotification.userInfo = @{KEY_NOTIFICATION: notificationID};

    //提交到系统服务中,系统限制一个APP只能注册64条通知,已经提醒过的通知可以清除掉
    /**
     *64条是重点,必需mark一下
     */
    [[UIApplication sharedApplication] scheduleLocalNotification:localNotification];

    return YES;
}


#pragma mark - 查询符合条件的本地推送

+ (UILocalNotification *)queryNotificationWithNotificatioID:(NSString *)notificatioID{

    NSArray * notifications = [self queryAllSystemNotifications];
    __block UILocalNotification * localnotification = nil;

    if (notifications.count > 0) {
        [notifications enumerateObjectsUsingBlock:^(UILocalNotification  * obj, NSUInteger idx, BOOL * _Nonnull stop) {
            //查找符合条件的本地推送
            if ([obj.userInfo[KEY_NOTIFICATION] isEqualToString:notificatioID]) {
                localnotification = obj;
                *stop = YES;
            }
        }];
    }
    return localnotification;
}

#pragma mark - 查询所有已注册的本地推送

+ (NSArray *)queryAllSystemNotifications{
    return [[UIApplication sharedApplication] scheduledLocalNotifications];
}


+ (void)cleanFiretimeIsPastNofications:(NSArray *)notifications{

    [notifications enumerateObjectsUsingBlock:^(UILocalNotification * notification, NSUInteger idx, BOOL * _Nonnull stop) {

        [self compareFiretime:notification needRemove:^(UILocalNotification *item) {
            /**
             *如果设置了重复的周期,这时候打印notificaion,会有个Next fire time字样
             */
            //销毁通知
            [[UIApplication sharedApplication] cancelLocalNotification:item];

        }];

    }];
}

#pragma mark - 对比,是否过期

+ (void)compareFiretime:(UILocalNotification *)notification needRemove:(void(^)(UILocalNotification * item))needRemove{

    NSComparisonResult result = [notification.fireDate compare:[NSDate date]];

    if (result == NSOrderedAscending) {
        needRemove(notification);
    }

}

#pragma mark - 注销一条本地推送(用于更新同一个ID的推送)

+ (void)deleteLocadNotificationWithNotificationID:(NSString *)notificationID{

    UILocalNotification * notification = [self queryNotificationWithNotificatioID:notificationID];

    if (notification) {
        [[UIApplication sharedApplication] cancelLocalNotification:notification];
    }

}
@end

在ViewController中设置参数就可以了,这里只是示范,具体的notification自己定义
ViewController.m

#import "ViewController.h"
#import "LocalNotificationManager.h"

#define CurrenVersiongreaterThan(X) ([[[UIDevice currentDevice] systemVersion] compare:X options:NSNumericSearch] != NSOrderedAscending)

@interface ViewController ()
@property (strong, nonatomic) IBOutlet UIButton *pushBtn;
@property (strong, nonatomic) IBOutlet UITextField *idTextField;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    [self commonInit];

}

- (void)commonInit{

}

- (IBAction)pushMessage:(UIButton *)sender {
    if (self.idTextField.text.length == 0) {
        if (CurrenVersiongreaterThan(@"9.0")) {

            UIAlertController * alert = [UIAlertController alertControllerWithTitle:@"警告" message:@"请输入ID" preferredStyle:UIAlertControllerStyleAlert];
            UIAlertAction *okAction = [UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleDefault handler:nil];
            [alert addAction:okAction];
            [self presentViewController:alert animated:YES completion:nil];


        }else{

            UIAlertView * alert = [[UIAlertView alloc] initWithTitle:@"警告" message:@"请输入ID" delegate:nil cancelButtonTitle:@"确定" otherButtonTitles:nil, nil];
            [alert show];

        }
        return;
    }

    [LocalNotificationManager insertLocalNotificationToSystemQueueWithNotificationID:self.idTextField.text];
}

@end

效果图:

初次打开,弹出提示框,向用户请求本地通知的权限
初次打开会请求权限

App在前端时候,AppDelegate里面会接受到一个notification,可以获取里面的信息用Alert来展示
App在前端时候,AppDelegate里面会接受到一个notification,可以获取里面的信息用Alert来展示

弹框提醒,样式取决于用户在系统中设置的样式
弹框提醒,样式取决于用户在系统中设置的样式

在通知栏中的效果
通知栏里面的现实

总结:用完的本地推送,必须删除,然后没有推送的可以储存在数据库或者其他plsit中,对时间要求比较准确或者数量要求更多的,要么推送到系统日历,由日历去提醒。要么就要每次打开APP就去查询数据库,再去遍历数据库中满足条件的推送信息!!

扫描二维码关注公众号,回复: 4761973 查看本文章

猜你喜欢

转载自blog.csdn.net/qq_27339239/article/details/52184967