iOS10 Notification Service Extension(實(shí)現(xiàn)后臺(tái)語(yǔ)音播報(bào)功能)以及IOS 12.1之后咖摹,語(yǔ)音播報(bào)失效情況處理

前言:
前段時(shí)間, 產(chǎn)品提出一個(gè)新的需求闸溃,要求實(shí)現(xiàn)外賣訂單的語(yǔ)音播報(bào)功能, 之前的開(kāi)發(fā)僅僅實(shí)現(xiàn)了前臺(tái)的語(yǔ)音播報(bào)功能潘拱,我這邊要實(shí)現(xiàn)的功能就是點(diǎn)擊APP進(jìn)入后臺(tái)或者APP進(jìn)程殺死之后揩瞪,依舊能收到語(yǔ)音播報(bào)赋朦,于是先是考慮用IOS7支持的靜默推送,不過(guò)沒(méi)有達(dá)到要求李破,聲音沒(méi)有播放出來(lái)宠哄,又想到了VoIP,蘋(píng)果推出的支持網(wǎng)絡(luò)電話的那一套嗤攻,看到網(wǎng)上的介紹毛嫉,后臺(tái)不好上線,就放棄了妇菱,在迷茫之時(shí)承粤,想到了IOS 10之后
推出的新功能,就是蘋(píng)果的推送擴(kuò)展(Notification Service Extension), 網(wǎng)上也有不少教程闯团,然后就按照教程一步一步的進(jìn)行下去...... 在此過(guò)程中遇到不少問(wèn)題辛臊,特此根據(jù)自己的實(shí)現(xiàn)過(guò)程(已上線),總結(jié)分析房交,如有錯(cuò)誤之處彻舰,請(qǐng)指出

一:Notification Service Extension通知服務(wù)擴(kuò)展

解析: 通俗點(diǎn)說(shuō)就是我們?cè)谑盏酵扑颓以趶椏蛘故局埃瑢?duì)通知內(nèi)容進(jìn)行修改(只針對(duì)遠(yuǎn)程推送)候味,如圖簡(jiǎn)易表示:


1.png

在實(shí)現(xiàn)功能之前刃唤,我也查閱不少資料,剛開(kāi)始看的時(shí)候白群,有點(diǎn)暈尚胞,因?yàn)樯婕暗搅酥匦屡渲米C書(shū)的問(wèn)題,不過(guò)帜慢,有的工程是直接自動(dòng)適配證書(shū)笼裳,如下:


2.png

但是我們的工程關(guān)于證書(shū)這方面,是手動(dòng)配置的崖堤,類似:


3.png

所以接下來(lái)侍咱,我所講述的大多涉及手動(dòng)配置證書(shū)方面,關(guān)于主工程的開(kāi)發(fā)環(huán)境和生產(chǎn)環(huán)境的Provisioning Profile密幔,具體的步驟,網(wǎng)上又不少講解撩轰,我這邊就直接省略了胯甩,上面廢話居多昧廷,接下來(lái)講述實(shí)現(xiàn)后臺(tái)語(yǔ)音播報(bào)功能的具體步驟。

二:

主工程需要如下配置:


Capabilities1.png

Capabilities2.png
創(chuàng)建Service Extension

1:
4.png

2:
5.png

3: 點(diǎn)擊上圖右下角的Next
6.png

4: 點(diǎn)擊上圖右下角的Finish
7.png

點(diǎn)擊上圖右下角的Activate,這個(gè)時(shí)候最基本的操作就創(chuàng)建好了.

三:

經(jīng)過(guò)上面的步驟之后偎箫,會(huì)出現(xiàn)如下的截圖顯示
8.png

在TARGETS里面會(huì)出現(xiàn)一個(gè)新的推送擴(kuò)展工程木柬,它的Bundle Identifier與主工程的有一定的關(guān)聯(lián)性,這個(gè)時(shí)候涉及了Provisioning Profile淹办,剛開(kāi)始弄的時(shí)候眉枕,心情是萬(wàn)馬奔騰的,心想怜森,這難道還要再弄配置文件嘛速挑?還要再制作推送證書(shū)嗎?如果對(duì)這個(gè)推送擴(kuò)展制作推送證書(shū)的之后副硅,我的極光推送平臺(tái)上配置的關(guān)于推送的p12證書(shū)可需要替換姥宝?總之,一些列問(wèn)題涌向心頭......

1: 關(guān)于是否需要制作新的Provisioning Profile恐疲,答案是肯定的腊满,具體的制作方法和之前主工程制作推送證書(shū)的步驟是一致的,就是按部就班的從APP IDs 到 Provisioning Profiles(我這邊也配置了推送證書(shū)培己,不過(guò)后期沒(méi)用到), 配置好開(kāi)發(fā)環(huán)境碳蛋、生產(chǎn)環(huán)境的Provisioning Profile之后,按照下圖選擇好相對(duì)應(yīng)的配置文件省咨,即可


9.png

到了這一步疮蹦,關(guān)于推送擴(kuò)展的證書(shū)配置就完成了.

2: 關(guān)于是否制作推送證書(shū),我制作了茸炒,但是沒(méi)用到

3: 極光推送之前配置的P12證書(shū)愕乎,不需要改動(dòng),用之前的就行了

四:

1: 在設(shè)置推送的時(shí)候壁公,一定要帶上這個(gè)字段:"mutable -content" 感论,只有將該字段設(shè)置為1,下面的方法才會(huì)有效(具體如何添加紊册,和后臺(tái)協(xié)商)比肄。已極光推送為例,在測(cè)試環(huán)境下發(fā)推送的時(shí)候,可以打印出類似如下的數(shù)據(jù)(下面是我簡(jiǎn)單的寫(xiě)一下囊陡,方便參考)芳绩,

aps = {
         alert = ‘輸入文字’;
         badge = 1;
         “mutable-content” = 1;
 }

2: 下面兩個(gè)截圖是測(cè)試時(shí)在極光推送后臺(tái)配置的情況:


極光推送1.png

極光推送2.png

3: 此時(shí)打開(kāi)推送擴(kuò)展的.m文件,


10.png

語(yǔ)音播報(bào)就是在這個(gè)NotificationService.m文件里面實(shí)現(xiàn)的撞反,

#import "NotificationService.h"
#import <AVFoundation/AVFAudio.h>

@interface NotificationService ()

@property (nonatomic, strong) void (^contentHandler)(UNNotificationContent *contentToDeliver);
@property (nonatomic, strong) UNMutableNotificationContent *bestAttemptContent;
@property (nonatomic, strong) AVSpeechSynthesizer *speechSynthesizer;

@end

@implementation NotificationService

- (void)didReceiveNotificationRequest:(UNNotificationRequest *)request withContentHandler:(void (^)(UNNotificationContent * _Nonnull))contentHandler {
    /**
     *  備注: 后臺(tái)推送過(guò)來(lái)的數(shù)據(jù)要協(xié)商好格式妥色,只要格式協(xié)商好,這部分就不會(huì)有問(wèn)題
     */
    self.contentHandler = contentHandler;
    self.bestAttemptContent = [request.content mutableCopy];
    self.speechSynthesizer = [[AVSpeechSynthesizer alloc] init];
    /*語(yǔ)音播報(bào)的內(nèi)容*/
    NSString* soundTitle = self.bestAttemptContent.userInfo[@"aps"][@"alert"];
    AVSpeechUtterance* speechUtterance = [[AVSpeechUtterance alloc] initWithString:soundTitle];
    /*設(shè)置語(yǔ)速*/
    speechUtterance.rate = 0.5;
    /*設(shè)置音量*/
    speechUtterance.volume = 1.0;
    /*設(shè)置語(yǔ)調(diào)*/
    speechUtterance.pitchMultiplier = 3.0;
    /*設(shè)置哪國(guó)語(yǔ)言*/
    speechUtterance.voice = [AVSpeechSynthesisVoice voiceWithLanguage:@"zh-CN"];
    [self.speechSynthesizer speakUtterance:speechUtterance];
    self.contentHandler(self.bestAttemptContent);
}

- (void)serviceExtensionTimeWillExpire {
    self.contentHandler(self.bestAttemptContent);
}
@end

按照上面的步驟遏片,在極光平臺(tái)測(cè)試推送嘹害,就可以實(shí)現(xiàn)簡(jiǎn)單的語(yǔ)音播報(bào).

注意點(diǎn):

1: Debug測(cè)試撮竿,如下圖設(shè)置,可以對(duì)NotificationService.m進(jìn)行斷點(diǎn)操作


斷點(diǎn).png

2: 推送的過(guò)程中會(huì)對(duì)數(shù)據(jù)進(jìn)行相應(yīng)的處理笔呀,這個(gè)與極光推送后臺(tái)API發(fā)送推送數(shù)據(jù)會(huì)有些誤差幢踏,我當(dāng)時(shí)也是踩了不少坑,我這邊的處理方法如下:

格式(大致的數(shù)據(jù)):
{ 
    "aps": {
        "alert": "您有一個(gè)新的商品訂單许师,點(diǎn)擊查看詳情", 
        "extras": {
            "has_voice": true, 
            "type": "weixin_order"
        },
        "mutable-content": 1
    }
}

- (void)didReceiveNotificationRequest:(UNNotificationRequest *)request withContentHandler:(void (^)(UNNotificationContent * _Nonnull))contentHandler {
    self.bestAttemptContent = [request.content mutableCopy];
    NSMutableDictionary *extras = [NSMutableDictionary dictionaryWithDictionary: self.bestAttemptContent.userInfo]; 
    [extras removeObjectForKey:@"aps"];
    NSMutableDictionary *params = [NSMutableDictionary dictionary];
    [params setValue:extras forKey:@"extras"];
    NSString* type = params[@"extras"][@"type"];
    BOOL has_voice = [params[@"extras"][@"has_voice"] boolValue];
}

看到上面的方法房蝉,估計(jì)你會(huì)有點(diǎn)郁悶,我之前嘗試過(guò)

NSString* type = self.attemptContent.userInfo[@"aps"][@"extras"][@"type"];

不過(guò)沒(méi)有獲取type的值.

3: 如果感覺(jué)系統(tǒng)自帶的文字轉(zhuǎn)語(yǔ)音, 播放的音質(zhì)不太滿意微渠,可以嘗試語(yǔ)音合成的方法搭幻,具體可參考這個(gè)鏈接(如果有不理解的,我這邊也是用合成語(yǔ)音的方法實(shí)現(xiàn)語(yǔ)音播報(bào)的敛助,可分享):
自定義語(yǔ)音合成播報(bào)

下面是關(guān)于iOS12.1之后粗卜,語(yǔ)音播報(bào)失效的情況分析與處理.

1: 下圖是官方給出的說(shuō)明,之前給出這個(gè)拓展推送主要是為了豐富推送的UI樣式纳击,推送信息加密之類的续扔,結(jié)果卻被用做推送語(yǔ)音播報(bào),所以就發(fā)了這個(gè)聲明焕数,在12.1之后纱昧,在這個(gè)推送擴(kuò)展里面AVAudioPlayer就失效了.


官方說(shuō)明.png

2: 解決方法:
既然我們可以修改推送內(nèi)容的title、subtitle和body堡赔,那么由此類推识脆,同樣的話,我們也可以修改推送的sound善已,又因?yàn)橥扑蛿U(kuò)展和主工程是相互隔離的狀態(tài)灼捂,這點(diǎn)在外面debug的時(shí)候已經(jīng)明確了,這個(gè)時(shí)候采用本地通送的方式换团,在推送擴(kuò)展里面發(fā)出本地推送去調(diào)取主目錄下的音頻文件悉稠。

具體實(shí)現(xiàn)方法如下:

- (void)didReceiveNotificationRequest:(UNNotificationRequest *)request withContentHandler:(void (^)(UNNotificationContent * _Nonnull))contentHandler { 
      if (@available(iOS 12.1, *)) {
            [self registerNotificationServiceType:type completeHandler:^{
                weakSelf.contentHandler(weakSelf.attemptContent);
            }];
        } else {
          // 此處調(diào)用之前的語(yǔ)音播報(bào)的內(nèi)容   
    }
}

// type: 后臺(tái)推送過(guò)來(lái)的
- (void)registerNotificationServiceType:(NSString*) type completeHandler:(void(^)(void))completeHandler{
    [[UNUserNotificationCenter currentNotificationCenter] requestAuthorizationWithOptions:UNAuthorizationOptionBadge|UNAuthorizationOptionSound|UNAuthorizationOptionAlert completionHandler:^(BOOL granted, NSError * _Nullable error){
        
        if(granted) {
            UNMutableNotificationContent *content = [[UNMutableNotificationContent alloc]init];
            content.title = @"";
            content.subtitle = @"";
            content.body = @"";
            
            NSString* sound = @"";
            if ([type isEqualToString:@"take_order"]) {
                sound = @"外賣訂單";
            }else if ([type isEqualToString:@"weixin_order"]) {
                sound = @"商品訂單";
            }else if ([type isEqualToString:@"food_order"]) {
                sound = @"點(diǎn)餐訂單";
            }else if ([type isEqualToString:@"online_yuyue"]) {
                sound = @"預(yù)約訂單";
            }
            // mp3格式的也是可以的
            content.sound = [UNNotificationSound soundNamed:[NSString stringWithFormat:@"%@.m4a",sound]];
            content.categoryIdentifier = [NSString stringWithFormat:@"noti_%@",type];
            UNTimeIntervalNotificationTrigger *trigger = [UNTimeIntervalNotificationTrigger triggerWithTimeInterval:1 repeats:NO];
            UNNotificationRequest* notificationRequest =
            [UNNotificationRequest requestWithIdentifier:[NSString stringWithFormat:@"noti_%@",type] content:content trigger:trigger];
            [[UNUserNotificationCenter currentNotificationCenter]addNotificationRequest:notificationRequest withCompletionHandler:^(NSError * _Nullable error) {
                if(error == nil) {
                    completeHandler();
                }
            }];
        }
    }];
}

3: 其實(shí)上面的代碼實(shí)現(xiàn)起來(lái)不難,但是我卻碰到一個(gè)問(wèn)題艘包,就是剛開(kāi)始的時(shí)候的猛,我怎么推送都沒(méi)聲音,當(dāng)時(shí)以為是不是音頻格式的問(wèn)題想虎,最后發(fā)現(xiàn)是都不是卦尊,然后無(wú)意間點(diǎn)擊home鍵讓app進(jìn)入后臺(tái)狀態(tài),卻有了推送聲音舌厨,此時(shí)我想既然進(jìn)入后臺(tái)和殺死進(jìn)程狀態(tài)下都有語(yǔ)音播報(bào)聲音岂却,那么前臺(tái)情況下就更好處理了,然后打開(kāi)appdelegate.m文件下,看看能不能在

- (void)jpushNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(NSInteger))completionHandler{ 
    completionHandler(UNNotificationPresentationOptionAlert);
}

處理一番淌友,結(jié)果發(fā)現(xiàn)煌恢,之前只寫(xiě)了 UNNotificationPresentationOptionAlert 骇陈,恍然大悟震庭,然后做了如下處理就可以了.

- (void)jpushNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(NSInteger))completionHandler { 
    completionHandler(UNNotificationPresentationOptionAlert |UNNotificationPresentationOptionBadge| UNNotificationPresentationOptionSound);
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市你雌,隨后出現(xiàn)的幾起案子器联,更是在濱河造成了極大的恐慌,老刑警劉巖婿崭,帶你破解...
    沈念sama閱讀 221,548評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件拨拓,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡氓栈,警方通過(guò)查閱死者的電腦和手機(jī)渣磷,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,497評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)授瘦,“玉大人醋界,你說(shuō)我怎么就攤上這事√嵬辏” “怎么了形纺?”我有些...
    開(kāi)封第一講書(shū)人閱讀 167,990評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)徒欣。 經(jīng)常有香客問(wèn)我逐样,道長(zhǎng),這世上最難降的妖魔是什么打肝? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 59,618評(píng)論 1 296
  • 正文 為了忘掉前任脂新,我火速辦了婚禮,結(jié)果婚禮上粗梭,老公的妹妹穿的比我還像新娘争便。我一直安慰自己,他們只是感情好楼吃,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,618評(píng)論 6 397
  • 文/花漫 我一把揭開(kāi)白布始花。 她就那樣靜靜地躺著,像睡著了一般孩锡。 火紅的嫁衣襯著肌膚如雪酷宵。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 52,246評(píng)論 1 308
  • 那天躬窜,我揣著相機(jī)與錄音浇垦,去河邊找鬼。 笑死荣挨,一個(gè)胖子當(dāng)著我的面吹牛男韧,可吹牛的內(nèi)容都是我干的朴摊。 我是一名探鬼主播,決...
    沈念sama閱讀 40,819評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼此虑,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼甚纲!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起朦前,我...
    開(kāi)封第一講書(shū)人閱讀 39,725評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤介杆,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后韭寸,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體春哨,經(jīng)...
    沈念sama閱讀 46,268評(píng)論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,356評(píng)論 3 340
  • 正文 我和宋清朗相戀三年恩伺,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了赴背。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,488評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡晶渠,死狀恐怖凰荚,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情乱陡,我是刑警寧澤浇揩,帶...
    沈念sama閱讀 36,181評(píng)論 5 350
  • 正文 年R本政府宣布,位于F島的核電站憨颠,受9級(jí)特大地震影響胳徽,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜爽彤,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,862評(píng)論 3 333
  • 文/蒙蒙 一养盗、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧适篙,春花似錦往核、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,331評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至硫痰,卻和暖如春衩婚,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背效斑。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,445評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工根吁, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留灶芝,地道東北人澎粟。 一個(gè)月前我還...
    沈念sama閱讀 48,897評(píng)論 3 376
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像护侮,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子储耐,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,500評(píng)論 2 359

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

  • 1羊初、通過(guò)CocoaPods安裝項(xiàng)目名稱項(xiàng)目信息 AFNetworking網(wǎng)絡(luò)請(qǐng)求組件 FMDB本地?cái)?shù)據(jù)庫(kù)組件 SD...
    陽(yáng)明先生_X自主閱讀 15,988評(píng)論 3 119
  • 我不是個(gè)好女人,但也不是個(gè)壞女人弧岳。用我自己的話說(shuō)凳忙,我不好不壞业踏,亦正亦邪禽炬。 好壞的標(biāo)準(zhǔn)是什么,以什么來(lái)區(qū)分呢勤家?好女人...
    素墨無(wú)痕閱讀 1,571評(píng)論 5 27
  • 時(shí)間仿佛定格到了半個(gè)月前腹尖,我曾以為你是我年少的歡喜,不能錯(cuò)過(guò)的珍惜伐脖,不想最后淪為錯(cuò)過(guò)的風(fēng)景热幔,只是現(xiàn)在愿你以后都好...
    波風(fēng)r水門(mén)閱讀 187評(píng)論 0 0
  • 真的要相信貴的東西除了貴沒(méi)有其他缺點(diǎn)了這個(gè)高潮色腮紅雖然名字污了一點(diǎn) 但其實(shí)是很少女的 涂到臉上還會(huì)一閃一閃的 但...
    鹽幸閱讀 210評(píng)論 0 0
  • 1
    健康分享家閱讀 70評(píng)論 0 0