推送-iOS本地通知

前言

首先我們要明白通知和推送是不一樣的莫秆。

通知是iOS操作系統(tǒng)層面上的功能幸缕,說白了就是iPhone上的通知條,通知中心等凤覆,App來了一條通知链瓦,系統(tǒng)來了升級(jí)通知,待辦事項(xiàng)來了一條通知盯桦,這里的通知指的是iOS操作系統(tǒng)內(nèi)的一個(gè)功能慈俯,更多體現(xiàn)在UI、交互拥峦、觸發(fā)邏輯贴膘、通知方式上。

推送指的是由APNs服務(wù)器略号、ProviderService刑峡、iOS系統(tǒng)、App構(gòu)成的通訊系統(tǒng)玄柠,是移動(dòng)互聯(lián)網(wǎng)與傳統(tǒng)的Web最明顯的區(qū)別的地方突梦。正因?yàn)橛辛送扑停瑢?shí)現(xiàn)了服務(wù)端能夠反向與用戶建立聯(lián)系随闪,而不是等待用戶訪問Web服務(wù)器阳似。

本文主要講的是通知

說明

從 iOS 10 新增的 UserNotifications Framework 可以發(fā)現(xiàn),Apple 整合了原有散亂的 API铐伴,并且增加了許多強(qiáng)大的功能撮奏。以 Apple 官方的角度來看俏讹,也必然是相當(dāng)重視推送服務(wù)對(duì) App 的影響、以及對(duì) Apple iOS 生態(tài)圈長(zhǎng)遠(yuǎn)發(fā)展的影響畜吊。

iOS10的通知新功能泽疆,用戶體驗(yàn)的提升和開發(fā)者能夠發(fā)揮的地方非常多,使得iOS更具有競(jìng)爭(zhēng)力玲献。

  • iOS 10通知系統(tǒng)支持Images, GIFs, Audio and Video類型
  • iOS 10推出Notification Service Extension與Notification Content Extension殉疼,可以實(shí)現(xiàn)推送數(shù)據(jù)在展示前進(jìn)行下載更新、定制通知UI
  • iOS 10統(tǒng)一了通知類型捌年,具有時(shí)間間隔通知瓢娜、地理位置通知和日歷通知
iOS里的通知擴(kuò)展

User Notifications Framework 介紹:
關(guān)系圖:

User Notifications Framework類關(guān)系圖

重點(diǎn)介紹:

UNUserNotificationCenter通知中心,用以管理通知的注冊(cè)礼预、權(quán)限獲取和管理瞳腌、通知的刪除與更新袍镀,通過代理分發(fā)事件等。

UNNotification 通知實(shí)體,在UNUserNotificationCenter的代理回調(diào)事件中懒鉴,告知App接收到一條通知调鬓,包含一個(gè)發(fā)起通知的請(qǐng)求UNNotificationRequest

UNNotificationRequest包含通知內(nèi)容UNNotificationContent和觸發(fā)器UNNotificationTrigger

UNNotificationContent 通知內(nèi)容翩隧,通知的title窝革,sound,badge以及相關(guān)的圖像应结、聲音刨疼、視頻附件UNNotificationAttachment,觸發(fā)打開App時(shí)候指定的LacnchImage等

UNNotificationResponse摊趾,用戶在觸發(fā)了按鈕或者文本提交的UNNotificationAction的時(shí)候币狠,會(huì)形成一個(gè)response,通過通知中心的代理方法回調(diào)給App進(jìn)行處理或者是交給擴(kuò)展處理砾层。

UNNotificationServiceExtension漩绵,是一個(gè)在接收到APNs服務(wù)器推送過來的數(shù)據(jù)進(jìn)行處理的服務(wù)擴(kuò)展,如果App提供了服務(wù)擴(kuò)展肛炮,那么APNs下發(fā)推送后在通知顯示觸發(fā)之前止吐,會(huì)在UNNotificationServiceExtension內(nèi)接收到,此處有大約30秒的處理時(shí)間侨糟,開發(fā)者可以進(jìn)行一些數(shù)據(jù)下載碍扔、數(shù)據(jù)解密、更新等操作秕重,然后交由而后的內(nèi)容擴(kuò)展(UNNotificationContentExtension)或者是App進(jìn)行觸發(fā)顯示

UNNotificationCategory,用以定義一組樣式類型不同,該分類包含了某一個(gè)通知包含的交互動(dòng)作的組合,比如說UNNotificationRequest內(nèi)包含了一個(gè)Category標(biāo)示,那該通知就會(huì)以預(yù)定義好的交互按鈕或者文本框添加到通知實(shí)體上二拐。

UNNotificationAttachment服鹅,通知內(nèi)容UNNotificationContent包含的附件,一般為圖片百新、視頻和音頻企软,雖然iOS10的通知數(shù)據(jù)容量為4k,但依舊很少饭望,在添加了UNNotificationServiceExtension擴(kuò)展的情況下仗哨,可以在服務(wù)里下載圖片,生成圖片铅辞、視頻等的本地緩存厌漂,UNNotificationAttachment根據(jù)緩存數(shù)據(jù)生成并添加到UNNotificationContent中,交由UI顯示

UNNotificationAction巷挥,是通知中添加的action桩卵,展示在通知欄的下方。默認(rèn)以的button樣式展示倍宾。有一個(gè)文本輸入的子類UNTextInputNotificationAction∈どぃ可以在點(diǎn)擊button之后彈出一個(gè)鍵盤高职,輸入信息。用戶點(diǎn)擊信息和輸入的信息可以在UNNotificationResponse中獲取

系統(tǒng)級(jí)別的代理方法

// The method will be called on the delegate only if the application is in the foreground. 
 If the method is not implemented or the handler is not called in a timely manner 
 then the notification will not be presented.
  #翻譯
[UNUserNotificationCenterDelegate willPresentNotification:withCompletionHandler:]
[UNUserNotificationCenterDelegate didReceiveNotificationResponse:withCompletionHandler:]

說了這么多辞州,現(xiàn)在源碼展示不同系統(tǒng)下的本地通知的實(shí)現(xiàn)怔锌,親測(cè)有效。

源碼實(shí)現(xiàn)iOS8-iOS10的本地通知

這里必須說一下iOS8-iOS10的本地通知跟 iOS10以后的不一樣变过,在應(yīng)用在前臺(tái)時(shí)是不會(huì)有橫幅或者彈框提示的埃元,只會(huì)觸發(fā)代理方法,想要展示本地通知媚狰,需要把應(yīng)用切換到后臺(tái)岛杀,當(dāng)時(shí)就很糾結(jié)為什么不出現(xiàn)提示,浪費(fèi)了很多時(shí)間崭孤。

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
     
    if ([[UIApplication sharedApplication]  respondsToSelector:@selector(registerForRemoteNotifications)]) {
        // 這里 types 可以自定義类嗤,如果 types 為 0,那么所有的用戶通知均會(huì)靜默的接收辨宠,系統(tǒng)不會(huì)給用戶任何提示(當(dāng)然遗锣,App 可以自己處理并給出提示)
        UIUserNotificationType types = (UIUserNotificationType) (UIUserNotificationTypeBadge | UIUserNotificationTypeSound | UIUserNotificationTypeAlert);
        // 這里 categories 可暫不深入,本文后面會(huì)詳細(xì)講解嗤形。
        UIUserNotificationSettings *mySettings = [UIUserNotificationSettings settingsForTypes:types categories:nil];
        // 當(dāng)應(yīng)用安裝后第一次調(diào)用該方法時(shí)精偿,系統(tǒng)會(huì)彈窗提示用戶是否允許接收通知
        [[UIApplication sharedApplication] registerUserNotificationSettings:mySettings];
    }
    [self registerLocalNotificationInOldWay:10];
    
    return YES;
}

-(void)registerLocalNotificationInOldWay:(NSInteger)alertTime {
    
    UILocalNotification *notification = [[UILocalNotification alloc] init];
    // 設(shè)置觸發(fā)通知的時(shí)間
    NSDate *fireDate = [NSDate dateWithTimeIntervalSinceNow:alertTime];
    NSLog(@"fireDate=%@",fireDate);
    
    notification.fireDate = fireDate;
    // 時(shí)區(qū)
    notification.timeZone = [NSTimeZone defaultTimeZone];
    // 設(shè)置重復(fù)的間隔
    notification.repeatInterval = kCFCalendarUnitSecond;
    
    // 通知內(nèi)容
    notification.alertBody =  @"該起床了...";
    notification.applicationIconBadgeNumber = 1;
    // 通知被觸發(fā)時(shí)播放的聲音
    notification.soundName = UILocalNotificationDefaultSoundName;
    // 通知參數(shù)
    NSDictionary *userDict = [NSDictionary dictionaryWithObject:@"開始學(xué)習(xí)iOS開發(fā)了" forKey:@"key"];
    notification.userInfo = userDict;
    
    // ios8后,需要添加這個(gè)注冊(cè),才能得到授權(quán)
    if ([[UIApplication sharedApplication] respondsToSelector:@selector(registerUserNotificationSettings:)]) {
        UIUserNotificationType type =  UIUserNotificationTypeAlert | UIUserNotificationTypeBadge | UIUserNotificationTypeSound;
        UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:type
                                                                                 categories:nil];
        [[UIApplication sharedApplication] registerUserNotificationSettings:settings];
        // 通知重復(fù)提示的單位笔咽,可以是天墓阀、周、月
        notification.repeatInterval = NSCalendarUnitDay;
    } else {
        // 通知重復(fù)提示的單位拓轻,可以是天斯撮、周、月
        notification.repeatInterval = NSDayCalendarUnit;
    }
    
    // 執(zhí)行通知注冊(cè)
    [[UIApplication sharedApplication] scheduleLocalNotification:notification];
}

  //在后臺(tái)情況下點(diǎn)擊本地推送  或者   在前臺(tái)收到本地通知都會(huì)觸發(fā)這個(gè)方法
  - (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification
{
      NSLog(@"didReceiveLocalNotification notification");
      application.applicationIconBadgeNumber -= 1;

}
本地通知效果圖

源碼實(shí)現(xiàn)iOS10以后的本地通知

iOS10以后不論應(yīng)用在前臺(tái)或者在后臺(tái)扶叉,都可以展示本地通知勿锅。

- (void)viewDidLoad {
    [super viewDidLoad];
    
    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) {
                //點(diǎn)擊允許
                NSLog(@"注冊(cè)通知成功");
                [center getNotificationSettingsWithCompletionHandler:^(UNNotificationSettings * _Nonnull settings) {
                    [self registerNotification:5];
                }];
            } else {
                //點(diǎn)擊不允許
                NSLog(@"注冊(cè)通知失敗");
            }
        }];
        //注冊(cè)推送(同iOS8)
        [[UIApplication sharedApplication] registerForRemoteNotifications];
    }
}

/** * 描述 使用 UNNotification 本地通知(iOS 10) * @param alerTime 多長(zhǎng)時(shí)間后進(jìn)行推送 **/
-(void)registerNotification:(NSInteger)alerTime
{
    // 1、創(chuàng)建通知內(nèi)容枣氧,注:這里得用可變類型的UNMutableNotificationContent溢十,否則內(nèi)容的屬性是只讀的
    UNMutableNotificationContent *content = [[UNMutableNotificationContent alloc] init];
    // 標(biāo)題
    content.title = @"這是通知";
    // 次標(biāo)題
    content.subtitle = @"這是通知subtitle";
    // 內(nèi)容
    content.body = @"這是通知body這是通知body這是通知body這是通知body這是通知body這是通知body";
    
    // app顯示通知數(shù)量的角標(biāo)
    content.badge = [NSNumber numberWithInteger:4];
    
    // 通知的提示聲音,這里用的默認(rèn)的聲音
    content.sound = [UNNotificationSound defaultSound];
    NSURL *imageUrl = [[NSBundle mainBundle] URLForResource:@"cell2@2x" withExtension:@"png"];
    UNNotificationAttachment *attachment = [UNNotificationAttachment attachmentWithIdentifier:@"imageIndetifier" URL:imageUrl options:nil error:nil];
    // 附件 可以是音頻达吞、圖片张弛、視頻 這里是一張圖片
    content.attachments = @[attachment];
    // 標(biāo)識(shí)符
    content.categoryIdentifier = @"categoryIndentifier";
    // 2、創(chuàng)建通知觸發(fā)
    /* 觸發(fā)器分三種: UNTimeIntervalNotificationTrigger : 在一定時(shí)間后觸發(fā)酪劫,如果設(shè)置重復(fù)的話吞鸭,timeInterval不能小于60 UNCalendarNotificationTrigger : 在某天某時(shí)觸發(fā),可重復(fù) UNLocationNotificationTrigger : 進(jìn)入或離開某個(gè)地理區(qū)域時(shí)觸發(fā) */
    
    UNTimeIntervalNotificationTrigger *trigger = [UNTimeIntervalNotificationTrigger triggerWithTimeInterval:10 repeats:NO];
    //    NSDateComponents *components = [NSDateComponents new];
    //    components.second = 2.0f;
    //    UNCalendarNotificationTrigger *trigger = [UNCalendarNotificationTrigger triggerWithDateMatchingComponents:components repeats:NO];
    
    // 3覆糟、創(chuàng)建通知請(qǐng)求
    UNNotificationRequest *notificationRequest = [UNNotificationRequest requestWithIdentifier:@"KFGroupNotification" content:content trigger:trigger];
    // 4刻剥、將請(qǐng)求加入通知中心
    [[UNUserNotificationCenter currentNotificationCenter] addNotificationRequest:notificationRequest withCompletionHandler:^(NSError * _Nullable error) {
        if (error == nil) {
            NSLog(@"已成功加推送%@",notificationRequest.identifier);
        }
    }];
}

#pragma mark - iOS10 推送代理

//不實(shí)現(xiàn),通知不會(huì)有提示
- (void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions))completionHandler {
    //應(yīng)用在前臺(tái)收到通知
    NSLog(@"========%@", notification);
    
    UNNotificationRequest *request = notification.request; // 原始請(qǐng)求
    NSDictionary * userInfo = notification.request.content.userInfo;//userInfo數(shù)據(jù)
    UNNotificationContent *content = request.content; // 原始內(nèi)容
    NSString *title = content.title;  // 標(biāo)題
    NSString *subtitle = content.subtitle;  // 副標(biāo)題
    NSNumber *badge = content.badge;  // 角標(biāo)
    NSString *body = content.body;    // 推送消息體
    UNNotificationSound *sound = content.sound;  // 指定的聲音
    //建議將根據(jù)Notification進(jìn)行處理的邏輯統(tǒng)一封裝滩字,后期可在Extension中復(fù)用~
     //如果需要在應(yīng)用在前臺(tái)也展示通知
    completionHandler(UNNotificationPresentationOptionBadge|UNNotificationPresentationOptionSound|UNNotificationPresentationOptionAlert); // 回調(diào)block造虏,將設(shè)置傳入

}

// 對(duì)通知進(jìn)行響應(yīng)
- (void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void(^)())completionHandler {
    
    // 根據(jù)類別標(biāo)識(shí)符處理目標(biāo)反應(yīng)
    if ([response.notification.request.content.categoryIdentifier isEqualToString:@"categoryIndentifier"]) {
        [self handleResponse:response];
        
        UNNotificationRequest *request = response.notification.request; // 原始請(qǐng)求
        UNNotificationContent *content = request.content; // 原始內(nèi)容
        NSString *title = content.title;  // 標(biāo)題
        NSString *subtitle = content.subtitle;  // 副標(biāo)題
        NSNumber *badge = content.badge;  // 角標(biāo)
        NSString *body = content.body;    // 推送消息體
        UNNotificationSound *sound = content.sound;
        //在此,可判斷response的種類和request的觸發(fā)器是什么麦箍,可根據(jù)遠(yuǎn)程通知和本地通知分別處理漓藕,再根據(jù)action進(jìn)行后續(xù)回調(diào)
    }
    completionHandler();
}

- (void)handleResponse:(UNNotificationResponse *)response {
    
    NSString *actionIndentifier = response.actionIdentifier;
    [UIApplication sharedApplication].applicationIconBadgeNumber = 0;
    NSLog(@"%@",@"處理通知");

}

觸發(fā)器 UNNotificationTrigger有四個(gè)子類:

  • UNPushNotificationTrigger,遠(yuǎn)程推送觸發(fā)器挟裂,一般是遠(yuǎn)程推送推過來的通知帶有這類觸發(fā)器
  • UNTimeIntervalNotificationTrigger享钞,時(shí)間間隔觸發(fā)器,定時(shí)或者是重復(fù)话瞧,在本地推送設(shè)置中有用
  • UNCalendarNotificationTrigger嫩与,日歷觸發(fā)器,指定日期進(jìn)行通知
  • UNLocationNotificationTrigger交排,地理位置觸發(fā)器划滋,指定觸發(fā)通知的條件是地理位置CLRegion這個(gè)類型。

觸發(fā)器和內(nèi)容最后形成UNNotificationRequest埃篓,一個(gè)通知請(qǐng)求处坪,本地通知的請(qǐng)求,直接交給通知中心進(jìn)行發(fā)送,發(fā)送成功后同窘,該通知會(huì)按照觸發(fā)器的觸發(fā)條件進(jìn)行觸發(fā)玄帕,并且會(huì)顯示到通知中心上,用戶可與指定的category交互方式與通知進(jìn)行交互

效果圖

小結(jié)

本地通知其實(shí)很有用處想邦,可以做為一種提示使用裤纹,做類似布卡漫畫這種也可以推送正在追的漫畫的新章節(jié)并在后臺(tái)靜默下載,待到下載好再給用戶發(fā)送一個(gè)本地推送丧没,用戶點(diǎn)開即看無需再聯(lián)網(wǎng)鹰椒。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市呕童,隨后出現(xiàn)的幾起案子漆际,更是在濱河造成了極大的恐慌,老刑警劉巖夺饲,帶你破解...
    沈念sama閱讀 206,214評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件奸汇,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡往声,警方通過查閱死者的電腦和手機(jī)擂找,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,307評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來烁挟,“玉大人婴洼,你說我怎么就攤上這事『成ぃ” “怎么了?”我有些...
    開封第一講書人閱讀 152,543評(píng)論 0 341
  • 文/不壞的土叔 我叫張陵欢唾,是天一觀的道長(zhǎng)且警。 經(jīng)常有香客問我,道長(zhǎng)礁遣,這世上最難降的妖魔是什么斑芜? 我笑而不...
    開封第一講書人閱讀 55,221評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮祟霍,結(jié)果婚禮上杏头,老公的妹妹穿的比我還像新娘。我一直安慰自己沸呐,他們只是感情好醇王,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,224評(píng)論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著崭添,像睡著了一般寓娩。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,007評(píng)論 1 284
  • 那天棘伴,我揣著相機(jī)與錄音寞埠,去河邊找鬼。 笑死焊夸,一個(gè)胖子當(dāng)著我的面吹牛仁连,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播阱穗,決...
    沈念sama閱讀 38,313評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼饭冬,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了颇象?” 一聲冷哼從身側(cè)響起伍伤,我...
    開封第一講書人閱讀 36,956評(píng)論 0 259
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎遣钳,沒想到半個(gè)月后扰魂,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,441評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡蕴茴,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,925評(píng)論 2 323
  • 正文 我和宋清朗相戀三年劝评,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片倦淀。...
    茶點(diǎn)故事閱讀 38,018評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡蒋畜,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出撞叽,到底是詐尸還是另有隱情姻成,我是刑警寧澤,帶...
    沈念sama閱讀 33,685評(píng)論 4 322
  • 正文 年R本政府宣布愿棋,位于F島的核電站科展,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏糠雨。R本人自食惡果不足惜才睹,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,234評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望甘邀。 院中可真熱鬧琅攘,春花似錦、人聲如沸松邪。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,240評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽测摔。三九已至置济,卻和暖如春解恰,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背浙于。 一陣腳步聲響...
    開封第一講書人閱讀 31,464評(píng)論 1 261
  • 我被黑心中介騙來泰國(guó)打工护盈, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人羞酗。 一個(gè)月前我還...
    沈念sama閱讀 45,467評(píng)論 2 352
  • 正文 我出身青樓腐宋,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親檀轨。 傳聞我的和親對(duì)象是個(gè)殘疾皇子胸竞,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,762評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容