關於iOS本地推送的那些事兒
阿新 • • 發佈:2019-01-03
最近在做一個專案,需要大量的本地推送,本地推送有一個坑,就是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來展示
彈框提醒,樣式取決於使用者在系統中設定的樣式
在通知欄中的效果
總結:用完的本地推送,必須刪除,然後沒有推送的可以儲存在資料庫或者其他plsit中,對時間要求比較準確或者數量要求更多的,要麼推送到系統日曆,由日曆去提醒。要麼就要每次開啟APP就去查詢資料庫,再去遍歷資料庫中滿足條件的推送資訊!!