iOS10本地推送,上線項(xiàng)目中的實(shí)際運(yùn)用

離上次寫iOS集成極光推送之后盈电,我還得這樣做總結(jié)已過(guò)去半年了,半年的時(shí)間,在碼代碼的過(guò)程中,慢慢的體會(huì)到了一點(diǎn),看到需求精拟、設(shè)計(jì)不要急于寫代碼,先在腦子里想想,該怎么設(shè)計(jì),應(yīng)該考慮哪些方面的問(wèn)題,怎么編寫效率更高燎斩,用戶體驗(yàn)更好等等虱歪?這樣才能更快的提升。

有關(guān)iOS10推送的介紹和使用栅表,早有很多前輩已寫好了博客笋鄙,這里我就不介紹怎么使用推送了,著重介紹本地推送在實(shí)際項(xiàng)目中的使用流程怪瓶,以及需要注意的地方萧落。蘋果提供本地推送這么一個(gè)功能,我想一般是用來(lái)結(jié)合網(wǎng)絡(luò)洗贰、時(shí)間針對(duì)性的提醒某些用戶的找岖。

相比遠(yuǎn)程推送,1.本地推送沒(méi)有相關(guān)證書方面的要求哆姻;2.在沒(méi)有自己平臺(tái)推送服務(wù)器的情況下宣增,可以在app內(nèi)部對(duì)用戶進(jìn)行推送提醒。而遠(yuǎn)程推送最大的優(yōu)點(diǎn)就是可以輕松利用三方平臺(tái)矛缨,無(wú)論用戶是否有網(wǎng)絡(luò),都能隨時(shí)對(duì)app用戶進(jìn)行推送帖旨,當(dāng)然也可以對(duì)個(gè)別用戶進(jìn)行推送箕昭。關(guān)鍵還得看需求~


應(yīng)用處于前臺(tái)收到通知

談?wù)勛罱窘拥囊粋€(gè)項(xiàng)目中的一個(gè)需求,以下是項(xiàng)目需求:

用戶在使用APP的過(guò)程中解阅,要能及時(shí)(30s)看到他的交易信息落竹,
1. 在APP內(nèi)以彈窗的形式提醒用戶,點(diǎn)擊“查看”跳轉(zhuǎn)到對(duì)應(yīng)消息界面货抄;
2. 在后臺(tái)運(yùn)行時(shí)述召,以推送通知的形式提醒用戶,用戶點(diǎn)擊消息跳轉(zhuǎn)到對(duì)應(yīng)的消息界面蟹地。
由于沒(méi)有自己的推送服務(wù)器积暖,又涉及到網(wǎng)絡(luò)請(qǐng)求,暫不考慮APP處于退出狀態(tài)時(shí)的情況怪与。

看到這么一個(gè)需求夺刑,當(dāng)時(shí)就想到用推送,至于遠(yuǎn)程推還是本地推分别,當(dāng)然選擇后者遍愿,遠(yuǎn)程推的話必須借助極光推送平臺(tái),而且不能滿足從公司后臺(tái)獲取用戶實(shí)時(shí)交易的消息耘斩,并有針對(duì)性的給用戶推送沼填。

下面說(shuō)說(shuō)實(shí)現(xiàn)思路,涉及到iOS10推送API括授、讀取用戶對(duì)通知權(quán)限的設(shè)置坞笙、定時(shí)器轧邪、通知中心界面跳轉(zhuǎn)羞海、定時(shí)器和通知的移除忌愚,以下關(guān)于本地通知都用iOS10的API。

1.給APP申請(qǐng)通知權(quán)限却邓,
2.讀取用戶對(duì)通知的設(shè)置硕糊;
3.創(chuàng)建定時(shí)器;
4.添加通知中心觀察者腊徙;
5.創(chuàng)建 UNUserNotificationCenter對(duì)象简十,配置推送內(nèi)容;
6.分別處理前臺(tái)和后臺(tái)接收通知的情況撬腾;
7.用戶點(diǎn)擊通知后的界面跳轉(zhuǎn)螟蝙;
8.移除定時(shí)器、通知中心對(duì)象民傻。

開(kāi)始上代碼:

  • 1.給APP申請(qǐng)通知權(quán)限
    // 1.給APP申請(qǐng)通知權(quán)限,關(guān)于請(qǐng)求權(quán)限(定位等)務(wù)必放在APPdelegate中,程序一啟動(dòng)馬上提醒用戶選擇.否則設(shè)置-通知中心根本就沒(méi)有此應(yīng)用程序的通知設(shè)置,自己想去后臺(tái)設(shè)置打開(kāi)都找不到地方胰默。
    // 這是iOS10請(qǐng)求通知權(quán)限的API
    [[UNUserNotificationCenter currentNotificationCenter] requestAuthorizationWithOptions:(UNAuthorizationOptionAlert | UNAuthorizationOptionSound | UNAuthorizationOptionBadge) completionHandler:^(BOOL granted, NSError * _Nullable error) {
        // 用戶對(duì)通知的設(shè)置
        [[UNUserNotificationCenter currentNotificationCenter] getNotificationSettingsWithCompletionHandler:^(UNNotificationSettings * _Nonnull settings) {
            DLog(@"%@", (long)settings.authorizationStatus == 2 ? @"成獲取到通知權(quán)限" : @"用戶關(guān)閉了通知");
            if (settings.authorizationStatus != 2) {
                DLog(@"用戶關(guān)閉了通知");
            }
        }];
    }];
  • 2.檢查用戶對(duì)通知功能的設(shè)置狀態(tài),我放在首頁(yè)viewDidLoad中漓踢,當(dāng)用戶一進(jìn)入首頁(yè)如果發(fā)現(xiàn)沒(méi)有打開(kāi)則以彈窗的形式提醒用戶牵署,引導(dǎo)其打開(kāi);否則不進(jìn)行接下來(lái)的操作喧半。注:以下代碼都放在首頁(yè)控制器中奴迅。
// 2.檢查用戶對(duì)通知功能的設(shè)置狀態(tài)
- (BOOL)isPermissionedPushNotification {
    if ([[UIApplication sharedApplication] currentUserNotificationSettings].types == UIUserNotificationTypeNone) {
        DLog(@"用戶關(guān)閉了通知功能");
        // 彈窗
        UIAlertController *alertvc = [UIAlertController alertControllerWithTitle:@"溫馨提醒" message:@"請(qǐng)打開(kāi)通知功能,否則無(wú)法收到交易提醒." preferredStyle:UIAlertControllerStyleAlert];
        UIAlertAction *confirmAction = [UIAlertAction actionWithTitle:@"去設(shè)置" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
            DLog(@"引導(dǎo)用戶去設(shè)置中心打開(kāi)通知");
            // 點(diǎn)擊跳轉(zhuǎn)至設(shè)置中心
            NSURL *url = [NSURL URLWithString:UIApplicationOpenSettingsURLString];
            if([[UIApplication sharedApplication] canOpenURL:url]) {
                NSURL *url =[NSURL URLWithString:UIApplicationOpenSettingsURLString];
                [[UIApplication sharedApplication] openURL:url];
            }
        }];
        UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"忽略交易提醒" style:UIAlertActionStyleCancel handler:nil];
        
        [alertvc addAction:cancelAction];
        [alertvc addAction:confirmAction];
        [self presentViewController:alertvc animated:YES completion:nil];
        
        return false;
    } else {
        DLog(@"可以進(jìn)行推送");
        return true;
    }
}
  • 3.創(chuàng)建定時(shí)器,獲得新消息未讀數(shù)
  • 4.創(chuàng)建通知中心觀察者
- (void)viewDidLoad {
    [super viewDidLoad];
    // ...
    if ([self isPermissionedPushNotification])
    {
        // 3.創(chuàng)建定時(shí)器挺据,獲得新消息未讀數(shù)
        self.timer = [NSTimer scheduledTimerWithTimeInterval:RequestTimeInterval target:self selector:@selector(setupUnreadTradeMsg) userInfo:nil repeats:YES];
        // 設(shè)置timer模式
        [[NSRunLoop mainRunLoop] addTimer:self.timer forMode:NSRunLoopCommonModes];
    }

    // 4.創(chuàng)建通知中心觀察者
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(confirmReadNoticeContent:) name:@"ReadNoticeContent" object:nil];
}

// 定時(shí)器執(zhí)行方法
- (void)setupUnreadTradeMsg {
    dispatch_async(dispatch_get_global_queue(0, 0), ^{
            [NetworkEngine signPostWithURL:PARAMQUERY parmas:params success:^(id requestResult) {
                // ...
                // 省略部分網(wǎng)絡(luò)請(qǐng)求代碼
                
                // 設(shè)置app角標(biāo)數(shù)量 = 未讀消息數(shù)量
                [[UIApplication sharedApplication] setApplicationIconBadgeNumber:badge];
                // 消息按鈕紅點(diǎn)
                [self.msgBtn setBackgroundImage:[UIImage imageNamed:@"new_message"] forState:UIControlStateNormal];
                // 將新的交易信息內(nèi)容傳入推送
                NSMutableDictionary *params = [[NSMutableDictionary alloc] init];
                // ...
                // 發(fā)起推送
                [self pushNotificationOfTradeMsg:params];
            } failure:^(NSError *error) {
                // [self showToast:@"請(qǐng)求失敗,請(qǐng)檢查網(wǎng)絡(luò)連接"];
                return ;
            }];
        });
  • 5.配置推送內(nèi)容
// 5.配置推送內(nèi)容
- (void)pushNotificationOfTradeMsg:(NSDictionary *)params {
    // 1取具、創(chuàng)建通知對(duì)象
    UNUserNotificationCenter *center  = [UNUserNotificationCenter currentNotificationCenter];
    // 必須設(shè)置代理,否則無(wú)法收到通知
    center.delegate = self;
    // 權(quán)限
    [center requestAuthorizationWithOptions:(UNAuthorizationOptionAlert | UNAuthorizationOptionSound | UNAuthorizationOptionBadge) completionHandler:^(BOOL granted, NSError * _Nullable error) {
        if (granted) {
            // 2扁耐、創(chuàng)建通知內(nèi)容
            UNMutableNotificationContent *content = [[UNMutableNotificationContent alloc] init];
            // 標(biāo)題
            content.title = params[@"title"];
            content.body = params[@"content"];
            // 聲音
            content.sound = [UNNotificationSound soundNamed:@"notification.wav"];
            // 圖片
            NSURL *imageUrl = [[NSBundle mainBundle] URLForResource:@"msgImg" withExtension:@"png"];
            UNNotificationAttachment *attachment = [UNNotificationAttachment attachmentWithIdentifier:@"imageIndetifier" URL:imageUrl options:nil error:nil];
            content.attachments = @[attachment];
            // 標(biāo)識(shí)符
            content.categoryIdentifier = @"categoryIndentifier";
            
            // 3暇检、創(chuàng)建通知觸發(fā)時(shí)間
            UNTimeIntervalNotificationTrigger *trigger = [UNTimeIntervalNotificationTrigger triggerWithTimeInterval:1.0 repeats:NO];
            // 4、創(chuàng)建通知請(qǐng)求
            UNNotificationRequest *notificationRequest = [UNNotificationRequest requestWithIdentifier:@"KFGroupNotification" content:content trigger:trigger];
            // 5做葵、將請(qǐng)求加入通知中心
            [center addNotificationRequest:notificationRequest withCompletionHandler:^(NSError * _Nullable error) {
                if (!error) {
                    DLog(@"已成功加入通知請(qǐng)求");
                } else {
                    DLog(@"出錯(cuò)啦%@", [error localizedDescription]);
                }
            }];
        }
    }];
}
  • 6.分別處理前臺(tái)和后臺(tái)接收通知的情況
/** 6.1當(dāng)用戶處于前臺(tái)時(shí),消息發(fā)送前走這個(gè)方法 */
-(void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions))completionHandler{
    DLog(@"--------通知即將發(fā)出-------");
    // 在前臺(tái)時(shí),通過(guò)此方法監(jiān)聽(tīng)到消息發(fā)出,不讓其在通知欄顯示,以彈窗的形式展示出來(lái);設(shè)置聲音提示
    completionHandler(UNNotificationPresentationOptionSound);
    
    // 獲取消息內(nèi)容
    NSMutableDictionary *content = [[NSMutableDictionary alloc] init];
    [content setObject:notification.request.content.title forKey:@"content"];
    [content setObject:notification.request.content.body forKey:@"body"];
    
    // 彈窗
    UIAlertController *alertvc = [UIAlertController alertControllerWithTitle:notification.request.content.title message:notification.request.content.body preferredStyle:UIAlertControllerStyleAlert];
    UIAlertAction* updateAction = [UIAlertAction actionWithTitle:@"查看" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
        // 創(chuàng)建通知對(duì)象
        NSNotification *notice = [NSNotification notificationWithName:@"ReadNoticeContent" object:nil userInfo:content];
        // 發(fā)送通知
        [[NSNotificationCenter defaultCenter] postNotification:notice];
        DLog(@"點(diǎn)擊查看消息");
    }];
    UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"忽略" style:UIAlertActionStyleCancel handler:nil];
    [alertvc addAction:cancelAction];
    [alertvc addAction:updateAction];
    [self presentViewController:alertvc animated:YES completion:nil];
}
/** 6.2不處于前臺(tái)時(shí),與通知交互走這個(gè)方法 */
-(void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void (^)())completionHandler {

    completionHandler(UIBackgroundFetchResultNewData);
    // 獲取消息內(nèi)容
    NSMutableDictionary *content = [[NSMutableDictionary alloc] init];
    [content setObject:response.notification.request.content.title forKey:@"content"];
    [content setObject:response.notification.request.content.body forKey:@"body"];
    
    // 判斷是否為本地通知 
    if([response.notification.request.trigger isKindOfClass:[UNPushNotificationTrigger class]]) {
        NSLog(@"收到遠(yuǎn)程通知");
    } else {
        // 判斷為本地通知
        //創(chuàng)建通知對(duì)象
        NSNotification *notice = [NSNotification notificationWithName:@"ReadNoticeContent" object:nil userInfo:content];
        //發(fā)送通知
        [[NSNotificationCenter defaultCenter] postNotification:notice];
    }
}
  • 7.用戶點(diǎn)擊通知后的界面跳轉(zhuǎn)
// 點(diǎn)擊查看消息占哟,進(jìn)行界面跳轉(zhuǎn)
- (void)confirmReadNoticeContent:(NSDictionary *)content {
    DLog(@"跳轉(zhuǎn)頁(yè)面 %@", content);
    
    // 點(diǎn)擊通知查看內(nèi)容,角標(biāo)清零,紅點(diǎn)消失
    [[UIApplication sharedApplication] setApplicationIconBadgeNumber:0];
    [self.msgBtn setBackgroundImage:[UIImage imageNamed:@"nav_message"] forState:UIControlStateNormal];
    
    // 獲取當(dāng)前跟控制器
    UIViewController *rootVC = nil;
    UIWindow *window = [UIApplication sharedApplication].windows.firstObject;
    if ([window.rootViewController isKindOfClass:[GFNavigationController class]])
    {
        rootVC = [(GFNavigationController *)window.rootViewController visibleViewController];
    }
    else if ([window.rootViewController isKindOfClass:[GFTabBarController class]])
    {
        GFTabBarController *tabVC = (GFTabBarController *)window.rootViewController;
        rootVC = [(GFNavigationController *)[tabVC selectedViewController] visibleViewController];
    }
    else
    {
        rootVC = window.rootViewController;
    }
    
    // 跳轉(zhuǎn)到消息列表頁(yè)面
    TradeMessageViewController *tmvc = [[TradeMessageViewController alloc] init];
    [rootVC.navigationController pushViewController:tmvc animated:YES];
}
  • 8.移除定時(shí)器酿矢、通知中心對(duì)象
- (void)dealloc {
    // 移除通知
    [[NSNotificationCenter defaultCenter] removeObserver:self];
    // 銷毀定時(shí)器
    [self.timer invalidate];
    self.timer = nil;
}
處于前臺(tái)時(shí)收到消息.gif
處于后臺(tái)時(shí)收到消息.gif

至此榨乎,消息已經(jīng)可以成功發(fā)出,從前臺(tái)點(diǎn)擊查看或從后臺(tái)點(diǎn)擊都可以成功進(jìn)行界面跳轉(zhuǎn)瘫筐,然后返回到之前的頁(yè)面蜜暑。
總結(jié):

1、UNUserNotificationCenter對(duì)象的創(chuàng)建及內(nèi)容配置可以根據(jù)需要放在控制器中策肝,不一定非得放在APPdelegate中肛捍;
2隐绵、上面前臺(tái)和后臺(tái)點(diǎn)擊查看消息內(nèi)容是以發(fā)通知的形式進(jìn)行處理的,其實(shí)可以直接用[self methodName]的形式調(diào)用拙毫,原因是接收通知的方法和點(diǎn)擊查看消息的方法在同一個(gè)控制器中依许,如果不在同一個(gè)控制器中(跨界面)就得用通知進(jìn)行接收了。
3缀蹄、這里我的跟控制器是TabBar峭跳,所以界面跳轉(zhuǎn)走的是第二個(gè)else if,如果是導(dǎo)航控制器或其他缺前,會(huì)跟著變的蛀醉。

最后,由于是客戶的項(xiàng)目衅码,就沒(méi)有單獨(dú)整理demo拯刁。本地通知實(shí)際運(yùn)用并不難,自己稍微花點(diǎn)時(shí)間整理下逝段,就全部弄明白了垛玻,思路流程都已經(jīng)列出來(lái)了,可以根據(jù)需要一步一步來(lái)惹恃,這個(gè)弄清楚夭谤,其實(shí)遠(yuǎn)程通知也差不多了。好了巫糙,如果發(fā)現(xiàn)有不對(duì)或者需要優(yōu)化的地方,請(qǐng)指出颊乘,真心感謝参淹!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市乏悄,隨后出現(xiàn)的幾起案子浙值,更是在濱河造成了極大的恐慌,老刑警劉巖檩小,帶你破解...
    沈念sama閱讀 217,542評(píng)論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件开呐,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡规求,警方通過(guò)查閱死者的電腦和手機(jī)筐付,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,822評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)阻肿,“玉大人瓦戚,你說(shuō)我怎么就攤上這事〈运” “怎么了较解?”我有些...
    開(kāi)封第一講書人閱讀 163,912評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵畜疾,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我印衔,道長(zhǎng)啡捶,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書人閱讀 58,449評(píng)論 1 293
  • 正文 為了忘掉前任奸焙,我火速辦了婚禮瞎暑,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘忿偷。我一直安慰自己金顿,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,500評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布鲤桥。 她就那樣靜靜地躺著揍拆,像睡著了一般。 火紅的嫁衣襯著肌膚如雪茶凳。 梳的紋絲不亂的頭發(fā)上嫂拴,一...
    開(kāi)封第一講書人閱讀 51,370評(píng)論 1 302
  • 那天,我揣著相機(jī)與錄音贮喧,去河邊找鬼筒狠。 笑死,一個(gè)胖子當(dāng)著我的面吹牛箱沦,可吹牛的內(nèi)容都是我干的辩恼。 我是一名探鬼主播,決...
    沈念sama閱讀 40,193評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼谓形,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼灶伊!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起寒跳,我...
    開(kāi)封第一講書人閱讀 39,074評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤聘萨,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后童太,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體米辐,經(jīng)...
    沈念sama閱讀 45,505評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,722評(píng)論 3 335
  • 正文 我和宋清朗相戀三年书释,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了翘贮。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,841評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡征冷,死狀恐怖择膝,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情检激,我是刑警寧澤肴捉,帶...
    沈念sama閱讀 35,569評(píng)論 5 345
  • 正文 年R本政府宣布腹侣,位于F島的核電站,受9級(jí)特大地震影響齿穗,放射性物質(zhì)發(fā)生泄漏傲隶。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,168評(píng)論 3 328
  • 文/蒙蒙 一窃页、第九天 我趴在偏房一處隱蔽的房頂上張望跺株。 院中可真熱鬧,春花似錦脖卖、人聲如沸乒省。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 31,783評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)袖扛。三九已至,卻和暖如春十籍,著一層夾襖步出監(jiān)牢的瞬間蛆封,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 32,918評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工勾栗, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留惨篱,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,962評(píng)論 2 370
  • 正文 我出身青樓围俘,卻偏偏與公主長(zhǎng)得像砸讳,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子界牡,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,781評(píng)論 2 354

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