以下所有內(nèi)容均為個人觀點,轉(zhuǎn)載請注明出處<簡書--小蝸牛吱呀之悠悠 >,謝謝!
最近工作中新增一個告警推送帶圖片的需求拨匆,要求在云端服務(wù)器向極光推送圖片地址,APP在收到推送消息以后能夠?qū)⒌刂穼?yīng)的圖片下載完成并顯示在推送欄右側(cè)挽拂,經(jīng)過一段時間對極光推送官方文檔和iOS10新特性Service Extension的研究惭每,終于實現(xiàn)了該功能的開發(fā)。由于是初次使用此功能亏栈,遇到不少問題台腥,為做記錄以及方便大家查閱,故寫下這篇博客绒北,若有不恰當(dāng)之處敬請留言指導(dǎo)黎侈,不勝感激,話不多說闷游,開始正文蜓竹!
一、極光推送的流程介紹
通常储藐,后臺推送比較常見,本文僅介紹關(guān)于后臺極光推送的實現(xiàn)流程嘶是。如下圖紅色箭頭所示
1钙勃、云服務(wù)器調(diào)用極光的接口向極光發(fā)送消息,極光收到消息后會將消息發(fā)送給蘋果的APNs服務(wù)器聂喇,蘋果再根據(jù)唯一標(biāo)示找到手機辖源,手機收到推送消息后,會在屏幕上方彈出推送消息希太。
2克饶、iOS 10以前,iOS的推送只能實現(xiàn)推送文字消息誊辉,這時候就需要云服務(wù)器將推送的內(nèi)容發(fā)送給極光矾湃,APP展示在界面上。iOS 10以后堕澄,蘋果官方新增了一些特性邀跃,其中包括新的推送方式----推送攔截(Service Extension),這種推送方式允許iOS開發(fā)者對接收到的推送消息進行一定的處理蛙紫,以便達到自己想要的效果拍屑。
2、Service Extension介紹
如上圖所示坑傅,在iOS 10以后僵驰,在APNs與APP之間增加了一個擴展,這意味著在APNs到達我們的設(shè)備之前,還會經(jīng)過一層允許用戶自主設(shè)置的Extension服務(wù)進行處理蒜茴,為APNs增加了多樣性星爪,在這個Extension中,我們可以圖片矮男、音頻(比如支付寶的到賬提醒語音)移必,我們甚至可以修改顯示的文字消息(意義不大,如果需要修改毡鉴,直接讓服務(wù)器去修改推送的內(nèi)容就可以了)崔泵。
3、Service Extension集成介紹
極光推送的內(nèi)容此處忽略猪瞬,需要學(xué)習(xí)的請參考https://docs.jiguang.cn/jpush/client/iOS/ios_guide_new/
1憎瘸、新建Service Extension,File->New->Target
需要注意的一點是,這是一個新的target陈瘦,bundle ID與主APP不同幌甘,它是主APP的一個擴展,必須是主APP的bundle ID拼上target的名字痊项。
創(chuàng)建完成后锅风,會多一個target,如下圖:
2鞍泉、此時主工程需要如下配置:
3皱埠、對Extension做如下配置:
4、將極光的庫導(dǎo)入工程并引入依賴庫:
5咖驮、接下來就需要為新的target制作證書了边器,從APP IDs 到 Provisioning Profiles, 配置好開發(fā)環(huán)境托修、生產(chǎn)環(huán)境的Provisioning Profile之后忘巧,依次選擇對應(yīng)的證書即可,關(guān)于如何制作證書睦刃,這里不贅述砚嘴,請出門右拐找度娘。
證書配置完畢后涩拙,APP的準(zhǔn)備工作算是完成了枣宫,服務(wù)器需要將字段:"mutable -content" 設(shè)置為true后再發(fā)給極光,具體的集成步驟吃环,請服務(wù)器人員自行參考極光官網(wǎng)也颤。
二、Service Extension target編碼
進入到Xcode自動給你創(chuàng)建的.m文件中郁轻,會發(fā)現(xiàn)有2個方法翅娶。
-
didReceiveNotificationRequest:(UNNotificationRequest *)request withContentHandler:(void (^)(UNNotificationContent *contentToDeliver))contentHandler
-
serviceExtensionTimeWillExpire
第一個方法就是我們用于攔截推送消息后文留,自定義消息內(nèi)容的方法。第二個方法是對第一個方法的補救竭沫。第二個方法會在過期之前進行回調(diào)燥翅,此時你可以對你的APNs消息進行一下緊急處理,比如多媒體文件過大蜕提,下載的時間過長森书,會直接調(diào)用此方法。
注意:媒體資源文件不宜過大谎势,否則耗時過長凛膏,無法達到攔截效果
- (void)didReceiveNotificationRequest:(UNNotificationRequest *)request withContentHandler:(void (^)(UNNotificationContent * _Nonnull))contentHandler {
self.contentHandler = contentHandler;
self.bestAttemptContent = [request.content mutableCopy];
/*
* 解析圖片的地址
* 收到的字典數(shù)據(jù)結(jié)構(gòu)并不是和服務(wù)器約定好的,為了通用性脏榆,此處遞歸解析字典
*/
NSString *imgUrl = [self getURLForUserInfo:self.bestAttemptContent.userInfo];
if (imgUrl) {
//download
NSURL *fileURL = [NSURL URLWithString:imgUrl];
[self downloadAndSave:fileURL handler:^(NSString *localPath) {
if (localPath) {
UNNotificationAttachment * attachment = [UNNotificationAttachment attachmentWithIdentifier:@"myAttachment" URL:[NSURL fileURLWithPath:localPath] options:nil error:nil];
self.bestAttemptContent.attachments = @[attachment];
}
//此方法為極光SDK中的用于上傳appKey的方法
[self apnsDeliverWith:request];
}];
}else{
[self apnsDeliverWith:request];
}
}
此處收到的字典猖毫,但字典的數(shù)據(jù)結(jié)構(gòu)并不是與云服務(wù)器約定好的結(jié)構(gòu),此問題咨詢過極光的工作人員须喂,并未給出合理的解釋吁断,此處為了規(guī)避數(shù)據(jù)結(jié)構(gòu)異常導(dǎo)致的問題,采用遞歸解析的方式獲取地址坞生。解析方法如下:
- (NSString *)getURLForUserInfo:(NSDictionary *)userInfo {
__block NSString *url = nil;
__block __weak __typeof(&*self)weakSelf = self;
[userInfo enumerateKeysAndObjectsUsingBlock:^(id _Nonnull key, id _Nonnull obj, BOOL * _Nonnull stop) {
if ([key containsString:@"url"]) {
*stop = YES;
url = obj;
}
if ([obj isKindOfClass:[NSDictionary class]] || [obj isKindOfClass:[NSArray class]]) {
url = [weakSelf getURLForUserInfo:obj];
}
}];
return url;
}
由于這是擴展的target仔役,無法使用主工程的網(wǎng)絡(luò)請求庫,需要使用原生的網(wǎng)絡(luò)請求方法下載資源文件:
- (void)downloadAndSave:(NSURL *)fileURL handler:(void (^)(NSString *))handler {
NSURLSession * session = [NSURLSession sharedSession];
NSURLSessionDownloadTask *task = [session downloadTaskWithURL:fileURL completionHandler:^(NSURL * _Nullable location, NSURLResponse * _Nullable response, NSError * _Nullable error) {
NSString *localPath = nil;
if (!error) {
//臨時文件夾路徑是己,APP沒有運行時會自動清除圖片又兵,不會占用內(nèi)存
NSString * localURL = [NSString stringWithFormat:@"%@/%@", NSTemporaryDirectory(),fileURL.lastPathComponent];
if ([[NSFileManager defaultManager] moveItemAtPath:location.path toPath:localURL error:nil]) {
localPath = localURL;
}
}
handler(localPath);
}];
[task resume];
}
資源文件下載失敗,緊急處理:
- (void)serviceExtensionTimeWillExpire {
self.contentHandler(self.bestAttemptContent);
}
三赃泡、Service Extension target調(diào)試
編碼完成后,通常需要調(diào)試乘盼,主要涉及兩個方面升熊,一個是擴展工程的在線調(diào)試,另一個是極光推送的編譯環(huán)境調(diào)試绸栅。
1级野、極光在線調(diào)試
進入極光主頁,進入如下界面:
配置相關(guān)信息粹胯,需要注意的一點是蓖柔,Service Extension target需要勾選下圖中的選項:
點擊推送后,APP即可收到后臺推送消息风纠。如果需要顯示圖片况鸣,則在附件字段一欄,設(shè)置好鍵值對竹观。
2镐捧、擴展工程在線調(diào)試
首先需要運行主工程文件潜索,等主工程文件運行起來后點擊下圖操作,過一段時間會出現(xiàn)你的擴展工程(有時候會出不來懂酱,感覺像是Xcode的bug)竹习,當(dāng)你接受的推送后,會在你的擴展工程中的斷點處停下列牺。
3整陌、字段調(diào)試
如果2中所提的調(diào)試方法無法使用斷點,可以采用修改推送內(nèi)容的方式來調(diào)試瞎领,如下:
self.bestAttemptContent.title = [NSString stringWithFormat:@"%@ [NotificationService]", self.bestAttemptContent.title];
此時泌辫,你收到的推送消息將會拼接上[NotificationService],如果是這種格式顯示的默刚,那么恭喜你甥郑,你的擴展攔截是OK的;如果收到的沒有拼接上荤西,那么澜搅,說明你攔截失敗,需要考慮你的集成步驟是否正確邪锌,或者是證書的生成是否OK勉躺。