1. 程式人生 > >關於iOS本地推送的那些事兒

關於iOS本地推送的那些事兒

最近在做一個專案,需要大量的本地推送,本地推送有一個坑,就是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就去查詢資料庫,再去遍歷資料庫中滿足條件的推送資訊!!