iOS遠(yuǎn)程推送和本地推送總結(jié)

因?yàn)榈玫揭粋€(gè)新功能:在前臺,后臺微酬,和鎖屏狀態(tài)下,得到后臺通知時(shí)語音播報(bào),查閱一些資料并作出總結(jié)离钝。為了方便理解以下內(nèi)容分為三個(gè)部分:

  • APP生命周期
  • 合成語音
  • 各個(gè)系統(tǒng)下收到通知的邏輯處理

首先我們要先了解APP在各情況下的活躍狀態(tài)以及涉及的系統(tǒng)方法:
1.首次啟動正常前臺運(yùn)行:活躍狀態(tài)

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{
        return YES;
}
- (void)applicationDidBecomeActive:(UIApplication *)application {
     NSLog(@" 程序激活 !");
}

2.鎖屏狀態(tài):掛起->進(jìn)入后臺

- (void)applicationWillResignActive:(UIApplication *)application {
    // 比如:當(dāng)有電話進(jìn)來或者鎖屏,這時(shí)你的應(yīng)用程會掛起褪储,在這時(shí)卵渴,UIApplicationDelegate委托會收到通知,調(diào)用 applicationWillResignActive 方法鲤竹,你可以重寫這個(gè)方法浪读,做掛起前的工作,比如關(guān)閉網(wǎng)絡(luò)辛藻,保存數(shù)據(jù)碘橘。
    NSLog(@" 程序掛起 !");
}
- (void)applicationDidEnterBackground:(UIApplication *)application {
    NSLog(@" 程序進(jìn)入后臺 !");
}

3.點(diǎn)擊home:掛起->進(jìn)入后臺

- (void)applicationWillResignActive:(UIApplication *)application {
    NSLog(@" 程序掛起 !");
}
- (void)applicationDidEnterBackground:(UIApplication *)application {
    NSLog(@" 程序進(jìn)入后臺 !");
}

4.后臺狀態(tài)時(shí),點(diǎn)擊收到的通知或者icon

- (void)applicationWillEnterForeground:(UIApplication *)application {
    // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
    NSLog(@"程序進(jìn)入前臺 !");
}
- (void)applicationDidBecomeActive:(UIApplication *)application {
     NSLog(@"程序激活 !");
}

二吱肌、語音部分
用系統(tǒng)強(qiáng)大的AVSpeechSynthesizer(10_14, 7_0)痘拆,寫成一個(gè)單例

+(instancetype)sharedInstance{
    static CRSpeechManger *instance;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        instance = [[CRSpeechManger alloc] init];
        instance.synthesizer = [[AVSpeechSynthesizer alloc] init];
    });
    return instance;
}

- (void)syntheticVoice:(NSString*)string {
    //  語音合成
    AVSpeechUtterance *speechUtterance = [AVSpeechUtterance speechUtteranceWithString:string];
    //設(shè)置語言類別(不能被識別,返回值為nil)
    speechUtterance.voice = [AVSpeechSynthesisVoice voiceWithLanguage:@"zh-CN"];
    //設(shè)置語速快慢
    speechUtterance.rate=0.5;//0.5是一個(gè)    //語音合成器會生成音頻
    [self.synthesizer speakUtterance:speechUtterance];
}

三氮墨、通知部分
我們先聊本地通知纺蛆,其中iOS10是一個(gè)分水嶺,iOS10以前的系統(tǒng)用UILocalNotification规揪,iOS10以后的系統(tǒng)包括10桥氏,系統(tǒng)新增<UserNotifications/UserNotifications.h>庫,增加自定義多媒體消息的功能猛铅。
1.發(fā)送通知

- (void)pushNotification_IOS10_before{
    UILocalNotification *notif = [[UILocalNotification alloc] init];
    // 發(fā)出推送的日期
    notif.fireDate = [NSDate dateWithTimeIntervalSinceNow:10];
    // 推送的內(nèi)容
    notif.alertBody = @"本地推送語音測試";
    // 可以添加特定信息
    notif.userInfo = @{ @"name": @"123" };
    // 角標(biāo)
    notif.applicationIconBadgeNumber = 1;
    // 提示音
    notif.soundName = UILocalNotificationDefaultSoundName;
    
    [[UIApplication sharedApplication] scheduleLocalNotification:notif];
}

-(void)pushNotification_IOS_10_after {
    //獲取通知中心用來激活新建的通知
    UNUserNotificationCenter * center  = [UNUserNotificationCenter currentNotificationCenter];
    
    UNMutableNotificationContent * content = [[UNMutableNotificationContent alloc]init];
    
    content.body = body;
    content.userInfo = @{@"name":@"123"};
    //通知的提示音
    if ([promptTone containsString:@"."]) {
        UNNotificationSound *sound = [UNNotificationSound soundNamed:promptTone];
        content.sound = sound;
    }
    
    __block UNNotificationAttachment *imageAtt;
    __block UNNotificationAttachment *movieAtt;
    __block UNNotificationAttachment *soundAtt;
    NSString * imageName = @"";
    if ([imageName containsString:@"."]) {
        [self addNotificationAttachmentContent:content attachmentName:imageName options:nil withCompletion:^(NSError *error, UNNotificationAttachment *notificationAtt) {
            
            imageAtt = [notificationAtt copy];
        }];
    }
     NSString * soundName = @"";
    if ([soundName containsString:@"."]) {
        [self addNotificationAttachmentContent:content attachmentName:soundName options:nil withCompletion:^(NSError *error, UNNotificationAttachment *notificationAtt) {
            soundAtt = [notificationAtt copy];
        }];
    }
      NSString * movieName = @"";
    if ([movieName containsString:@"."]) {
        UNNotificationAttachmentOptionsThumbnailTimeKey
        [self addNotificationAttachmentContent:content attachmentName:movieName options:@{@"UNNotificationAttachmentOptionsThumbnailTimeKey":@10} withCompletion:^(NSError *error, UNNotificationAttachment *notificationAtt) {
            movieAtt = [notificationAtt copy];
        }];
    }
    
    NSMutableArray * array = [NSMutableArray array];
    //    [array addObject:soundAtt];
    //    [array addObject:imageAtt];
    //    [array addObject:movieAtt];
    
    content.attachments = array;
    
    //添加通知下拉動作按鈕
    NSMutableArray * actionMutableArray = [NSMutableArray array];
    UNNotificationAction * actionA = [UNNotificationAction actionWithIdentifier:@"identifierNeedUnlock" title:@"進(jìn)入應(yīng)用" options:UNNotificationActionOptionAuthenticationRequired];
    UNNotificationAction * actionB = [UNNotificationAction actionWithIdentifier:@"identifierRed" title:@"忽略" options:UNNotificationActionOptionDestructive];
    [actionMutableArray addObjectsFromArray:@[actionA,actionB]];
    
    if (actionMutableArray.count > 1) {
        
        UNNotificationCategory * category = [UNNotificationCategory categoryWithIdentifier:@"categoryNoOperationAction" actions:actionMutableArray intentIdentifiers:@[] options:UNNotificationCategoryOptionCustomDismissAction];
        [center setNotificationCategories:[NSSet setWithObjects:category, nil]];
        content.categoryIdentifier = @"categoryNoOperationAction";
    }
    
    //UNTimeIntervalNotificationTrigger   延時(shí)推送
    //UNCalendarNotificationTrigger       定時(shí)推送
    //UNLocationNotificationTrigger       位置變化推送
    
    UNTimeIntervalNotificationTrigger * tirgger = [UNTimeIntervalNotificationTrigger triggerWithTimeInterval:10 repeats:NO];
    
    //建立通知請求
    UNNotificationRequest * request = [UNNotificationRequest requestWithIdentifier:identifier content:content trigger:tirgger];
    
    //將建立的通知請求添加到通知中心
    [center addNotificationRequest:request withCompletionHandler:^(NSError * _Nullable error) {
        if (error) {
             NSLog(@"%@本地推送 :( 報(bào)錯(cuò) %@",identifier,error);
        } else {
             NSLog(@"本地推送 :成功");
        }
       
        
    }];
}

2.注冊本地通知

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
    self.window.backgroundColor = [UIColor whiteColor];
    
    if ([[UIDevice currentDevice].systemVersion doubleValue]>=10.0) {
        [[UNUserNotificationCenter currentNotificationCenter] setDelegate:self];
        UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
        [center requestAuthorizationWithOptions:UNAuthorizationOptionAlert|UNAuthorizationOptionBadge|UNAuthorizationOptionSound completionHandler:^(BOOL granted, NSError * _Nullable error) {
            if (granted) {
                NSLog(@"新版通知-注冊成功-success");
            }else{
                NSLog(@"新版通知-注冊失敗-error");
            }
        }];
    }else if([[UIDevice currentDevice].systemVersion doubleValue]>=8.0){//8.0以后使用這種方法來注冊推送通知
        UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeBadge|UIUserNotificationTypeSound|UIUserNotificationTypeAlert categories:nil];
        [[UIApplication sharedApplication] registerUserNotificationSettings:settings];
    }else{
        [[UIApplication sharedApplication] registerUserNotificationSettings:[UIUserNotificationSettings settingsForTypes:(UIUserNotificationTypeSound | UIUserNotificationTypeAlert | UIUserNotificationTypeBadge) categories:nil]];
    } 
    return YES;
}

3.收到本地通知后的處理邏輯

- (void)application:(UIApplication *)application didReceiveLocalNotification:(nonnull UILocalNotification *)notification{
    NSString *voiceString =nil;
    voiceString = [NSString stringWithFormat:@"語音播報(bào):%@", notification.alertBody];
    [[CRSpeechManger sharedInstance] syntheticVoice:voiceString];
}

總結(jié):本地推送較為簡單字支,但要注意的是只有在前臺時(shí)會調(diào)用didReceiveLocalNotification,后臺狀態(tài)時(shí)奕坟,只有用戶點(diǎn)擊后才能調(diào)用此方法祥款。

遠(yuǎn)程通知
1.注冊通知(和本地通知一樣),用戶同意后月杉,會調(diào)用此程序刃跛,獲取系統(tǒng)的deviceToken,應(yīng)把deviceToken傳給服務(wù)器保存苛萎,此函數(shù)會在程序每次啟動時(shí)調(diào)用:

//registerForRemoteNotifications方法調(diào)用時(shí)機(jī)
//對于任何遠(yuǎn)程推送桨昙,registerForRemoteNotifications可以直接調(diào)用來注冊遠(yuǎn)程推送检号,而不需要用戶允許。也就是說只要調(diào)用-[UIApplication registerForRemoteNotifications]蛙酪,就可以在AppDelegate的application:didRegisterForRemoteNotificationsWithDeviceToken:中獲取到設(shè)備的push token齐苛。
那么通常的彈窗詢問權(quán)限有什么用呢?其實(shí)只是請求用戶允許在推送通知到來時(shí)能夠有alert, badge和sound桂塞,而并不是在請求注冊推送本身的權(quán)限凹蜂。
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken{
    
}

2.收到消息的邏輯處理
ios10以后,需要實(shí)現(xiàn)[UNUserNotificationCenter currentNotificationCenter]的代理方法阁危。

//用戶點(diǎn)擊通知欄玛痊,前后臺處理方式一致,iOS 10以后是用戶點(diǎn)擊才回調(diào)
- (void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void(^)(void))completionHandler{
    //可按需求進(jìn)行數(shù)據(jù)處理
    NSLog(@"%@",response);
}

// 下面處理iOS 10之后狂打,設(shè)置前臺收到遠(yuǎn)程消息時(shí)是否顯示 當(dāng)APP處于前臺的時(shí)候接收到通知
- (void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions))completionHandler
{
    NSString *voiceString = [NSString stringWithFormat:@"語音播報(bào):%@", notification.request.content.body];
    [[CRSpeechManger sharedInstance] syntheticVoice:voiceString];

}

iOS10以前通知回調(diào)方法,前臺收到消息時(shí)調(diào)用擂煞,
后臺模式下
普通推送:收到推送后(有文字有聲音),點(diǎn)開通知趴乡,進(jìn)入APP后对省,才執(zhí)行
靜默推送:收到推送(沒有文字沒有聲音),不用點(diǎn)開通知晾捏,不用打開APP蒿涎,就能執(zhí)行,用戶完全感覺不到粟瞬,可以理解允許應(yīng)用在收到通知后在后臺運(yùn)行一段代碼同仆,且能夠馬上執(zhí)行

靜默推送簡介:靜默推送(Silent Push)并不是必須要“靜默”,只要推送payload中aps字典里包含了"content-available": 1的鍵值對裙品,都具有靜默推送的特性(比如喚醒應(yīng)用)俗批,而無論你是否推了alert, badge或sound。則可以不打擾用戶的情況下進(jìn)行內(nèi)容更新等操作市怎。

- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler{
    // 獲取通知所帶的數(shù)據(jù)
    //程序關(guān)閉狀態(tài)點(diǎn)擊推送消息打開
    NSLog(@"%@",userInfo[@"alert"]);
    //前臺運(yùn)行
    if ([UIApplication sharedApplication].applicationState == UIApplicationStateActive) {
       
    }
    //后臺掛起時(shí)
    else{
      
    }
    //設(shè)置應(yīng)用程序角標(biāo)數(shù)為0
    [UIApplication sharedApplication].applicationIconBadgeNumber = 0;
    NSString *voiceString =nil;
    voiceString = [NSString stringWithFormat:@"語音播報(bào):%@", userInfo[@"alert"]];
    [[CRSpeechManger sharedInstance] syntheticVoice:voiceString];
}

知識點(diǎn)梳理告一段落岁忘,下面討論需求實(shí)現(xiàn)
我的想法是:
iOS 10之前的版本,采用靜默推送区匠,在實(shí)現(xiàn)播放固定的聲音干像。

iOS 10之后,使用新增的UNNotificationServiceExtension
(mutable-content : 1)驰弄,合成語音播報(bào)麻汰。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市戚篙,隨后出現(xiàn)的幾起案子五鲫,更是在濱河造成了極大的恐慌,老刑警劉巖岔擂,帶你破解...
    沈念sama閱讀 218,546評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件位喂,死亡現(xiàn)場離奇詭異浪耘,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)塑崖,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,224評論 3 395
  • 文/潘曉璐 我一進(jìn)店門七冲,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人规婆,你說我怎么就攤上這事澜躺。” “怎么了聋呢?”我有些...
    開封第一講書人閱讀 164,911評論 0 354
  • 文/不壞的土叔 我叫張陵苗踪,是天一觀的道長。 經(jīng)常有香客問我削锰,道長,這世上最難降的妖魔是什么毕莱? 我笑而不...
    開封第一講書人閱讀 58,737評論 1 294
  • 正文 為了忘掉前任器贩,我火速辦了婚禮,結(jié)果婚禮上朋截,老公的妹妹穿的比我還像新娘蛹稍。我一直安慰自己,他們只是感情好部服,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,753評論 6 392
  • 文/花漫 我一把揭開白布唆姐。 她就那樣靜靜地躺著,像睡著了一般廓八。 火紅的嫁衣襯著肌膚如雪奉芦。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,598評論 1 305
  • 那天剧蹂,我揣著相機(jī)與錄音声功,去河邊找鬼。 笑死宠叼,一個(gè)胖子當(dāng)著我的面吹牛先巴,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播冒冬,決...
    沈念sama閱讀 40,338評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼伸蚯,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了简烤?” 一聲冷哼從身側(cè)響起剂邮,我...
    開封第一講書人閱讀 39,249評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎乐埠,沒想到半個(gè)月后抗斤,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體囚企,經(jīng)...
    沈念sama閱讀 45,696評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,888評論 3 336
  • 正文 我和宋清朗相戀三年瑞眼,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了龙宏。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,013評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡伤疙,死狀恐怖银酗,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情徒像,我是刑警寧澤黍特,帶...
    沈念sama閱讀 35,731評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站锯蛀,受9級特大地震影響灭衷,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜旁涤,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,348評論 3 330
  • 文/蒙蒙 一翔曲、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧劈愚,春花似錦瞳遍、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,929評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至注祖,卻和暖如春猾蒂,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背氓轰。 一陣腳步聲響...
    開封第一講書人閱讀 33,048評論 1 270
  • 我被黑心中介騙來泰國打工婚夫, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人署鸡。 一個(gè)月前我還...
    沈念sama閱讀 48,203評論 3 370
  • 正文 我出身青樓案糙,卻偏偏與公主長得像,于是被迫代替她去往敵國和親靴庆。 傳聞我的和親對象是個(gè)殘疾皇子时捌,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,960評論 2 355

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