一塔鳍、以下為我集成時(shí)的問(wèn)題與解決方案:
1、iOS通知呻此,在官網(wǎng)后臺(tái)怎么推送轮纫,不能單獨(dú)推送通知?
iOS只能透?jìng)飨⒎傧剩瑐€(gè)推開(kāi)發(fā)人員說(shuō)掌唾,是因?yàn)樘O(píng)果的要走apns放前,而第一個(gè)默認(rèn)的推送是走的個(gè)推服務(wù)器。
2糯彬、如果應(yīng)用在前臺(tái)處于運(yùn)行狀態(tài)凭语,是不是不走APNs
這個(gè)是怎么實(shí)現(xiàn)的?實(shí)時(shí)監(jiān)控應(yīng)用是否在線?
判斷clientid和個(gè)推服務(wù)器的連接狀態(tài)撩扒。簡(jiǎn)單說(shuō)就是客戶端sdk和個(gè)推服務(wù)器是否是連接狀態(tài)的似扔。
3、字符串 字典 遠(yuǎn)程通知 區(qū)別 使用場(chǎng)景搓谆?
字符串是apn的簡(jiǎn)單推送
字典和遠(yuǎn)程通知是apn的高級(jí)推送
字符串和字典會(huì)有apn通知欄提示炒辉,遠(yuǎn)程通知沒(méi)有
4、為了更好支持SDK推送泉手,APP定期抓取離線數(shù)據(jù)黔寇,需要配置后臺(tái)運(yùn)行權(quán)限:Backgound fetch:后臺(tái)獲取Remote notifications: 推送喚醒(靜默推送,Silent Remote Notifications) 這個(gè)設(shè)置與不設(shè)置的區(qū)別斩萌?
這個(gè)不設(shè)置也沒(méi)關(guān)系的
5缝裤、clientid(CID)與 devictoken
devictoken是向蘋(píng)果注冊(cè)的,clientid(CID)是個(gè)推這邊推送消息用到的术裸,devicetoken是推送APNS消息用到的倘是,客戶端集成后會(huì)獲取clientid,我們會(huì)判斷clientid和個(gè)推服務(wù)器的連接狀態(tài)袭艺。簡(jiǎn)單說(shuō)就是客戶端sdk和個(gè)推服務(wù)器是否是連接狀態(tài)的搀崭。客戶端clientid和devictoken會(huì)有一個(gè)綁定關(guān)系猾编,我們系統(tǒng)會(huì)維護(hù)這個(gè)綁定關(guān)系瘤睹。
6、緩存消息存在問(wèn)題(消息中心)
如果緩存apns通知答倡,用戶點(diǎn)擊icon進(jìn)入應(yīng)用獲取不到通知內(nèi)容轰传,這個(gè)時(shí)候會(huì)消息丟失如果緩存透?jìng)飨?nèi)容,超出離線時(shí)間(最長(zhǎng)可設(shè)置72小時(shí))瘪撇,再打開(kāi)應(yīng)用获茬,這個(gè)時(shí)候也獲取不到透?jìng)飨ⅲ@樣就存在問(wèn)題了倔既,超出離線時(shí)間恕曲,無(wú)論緩存透?jìng)飨?nèi)容還是apns通知,都不會(huì)有可緩存內(nèi)容渤涌。
個(gè)推技術(shù)支持給的解決方案:
收到的消息保存在數(shù)據(jù)庫(kù)里佩谣,超過(guò)離線時(shí)間沒(méi)有下發(fā)的用戶,當(dāng)他點(diǎn)擊圖標(biāo)打開(kāi)應(yīng)用实蓬,或者進(jìn)入歷史消息頁(yè)面進(jìn)行查看時(shí)茸俭,客戶端可以主動(dòng)的去向服務(wù)器拉取數(shù)據(jù)吊履,這些數(shù)據(jù)你們是會(huì)在服務(wù)器中保存的。就是你們客戶端向你們的服務(wù)器上去獲取數(shù)據(jù)调鬓,不走推送了艇炎。客戶端向服務(wù)端發(fā)送請(qǐng)求腾窝,然后服務(wù)端把數(shù)據(jù)返回給客戶端比如銀行賬單也是這樣的冕臭,用戶在頁(yè)面中進(jìn)行下拉時(shí),會(huì)去刷新頁(yè)面燕锥,此時(shí)就是去服務(wù)器上重新提取的數(shù)據(jù)。
7悯蝉、問(wèn)題:
程序第一次啟動(dòng)的時(shí)候归形,即由死亡狀態(tài)進(jìn)入激活狀態(tài),這個(gè)時(shí)候接收到通知鼻由,點(diǎn)擊條幅通知暇榴,
要根據(jù)通知內(nèi)容進(jìn)行頁(yè)面跳轉(zhuǎn),但這個(gè)時(shí)候項(xiàng)目文件還沒(méi)加載完全蕉世,不能跳轉(zhuǎn)蔼紧,之前我們的
實(shí)現(xiàn)方法是這樣的,在didFinishLaunchingWithOptions代理下面添加如下方法
// 程序在死亡狀態(tài)狠轻,再次啟動(dòng)奸例,收到推送通知,跳轉(zhuǎn)至對(duì)應(yīng)頁(yè)面
if ([launchOptions objectForKey:UIApplicationLaunchOptionsRemoteNotificationKey]) {
NSDictionary * userInfo = [launchOptions objectForKey:UIApplicationLaunchOptionsRemoteNotificationKey];
self.notificationUserInfo = userInfo;
// 這里延遲1秒 否則不執(zhí)行跳轉(zhuǎn)
[self performSelector:@selector(skipToMessageCenter) withObject:nil afterDelay:1];
}
現(xiàn)在換成個(gè)推后要5秒后才能跳轉(zhuǎn)
[self performSelector:@selector(skipToMessageCenter) withObject:nil afterDelay:5];
這個(gè)延遲時(shí)間無(wú)法準(zhǔn)確計(jì)算向楼,所以上面方法是有缺陷的查吊,那么有沒(méi)更好的解決方案呢?
答案是有的湖蜕,以下為我優(yōu)化方案逻卖。如果你有更好的方法,歡迎指正昭抒。
AppDelegate.m:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// 程序在死亡狀態(tài)评也,再次啟動(dòng),收到推送通知灭返,跳轉(zhuǎn)至對(duì)應(yīng)頁(yè)面
if ([launchOptions objectForKey:UIApplicationLaunchOptionsRemoteNotificationKey]) {
NSDictionary * userInfo = [launchOptions objectForKey:UIApplicationLaunchOptionsRemoteNotificationKey];
self.notificationUserInfo = userInfo;
// 緩存apns通知內(nèi)容到本地
[[NSUserDefaults standardUserDefaults]setObject:self.notificationUserInfo forKey:KRemoteNotificationUserInfo];
[[NSUserDefaults standardUserDefaults ]synchronize];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(skipToMessageCenter) name:KReciveRemoteNotificationUserInfo object:nil];
}
}
-(void)skipToMessageCenter {
dispatch_async(dispatch_get_main_queue(), ^{
// 根據(jù)通知內(nèi)容盗迟,跳轉(zhuǎn)至不同頁(yè)面
MessageModel * messageModel = [[MessageModel alloc] initWithNoticeDic:self.notificationUserInfo];
MessageToSpecificViewController * messageToSpecificViewController = [[MessageToSpecificViewController alloc] init];
[messageToSpecificViewController messageFromViewController:update.mainViewController toSpecificViewControllerWithMessage:messageModel];
self.notificationUserInfo = nil;
});
}
MainViewController.m:
-(void)viewDidAppear:(BOOL)animated{
[super viewDidAppear:animated];
// 應(yīng)用由死亡狀態(tài)進(jìn)入激活狀態(tài),這個(gè)時(shí)候發(fā)送通知婆殿,appdelegate接受通知诈乒,根據(jù)通知內(nèi)容進(jìn)行不同跳轉(zhuǎn)
NSDictionary * notificationUserInfo =[[NSUserDefaults standardUserDefaults]valueForKey:KRemoteNotificationUserInfo];
if (notificationUserInfo) {
[[NSNotificationCenter defaultCenter] postNotificationName:KReciveremoteNotificationUserInfo object:nil];
[[NSUserDefaults standardUserDefaults]setObject:nil forKey:KRemoteNotificationUserInfo];
[[NSUserDefaults standardUserDefaults ]synchronize];
}
}
8、設(shè)置別名
使用別名進(jìn)行單點(diǎn)推送婆芦。
之前做極光推送的時(shí)候怕磨,我們別名使用的是[[UIDevice currentDevice] getCurrentDeviceUUID]喂饥,這個(gè)Id不能直接使用,因?yàn)椴环细袷匠辏野逊指舴?換成了分隔符_,這樣是可以的员帮。
原以為UUID全球唯一,請(qǐng)教了下同事导饲,同事說(shuō)這個(gè)id會(huì)變的捞高,就是不同證書(shū),即使同一臺(tái)設(shè)備渣锦,UUID也會(huì)不一樣硝岗。
個(gè)推的小伙伴給的建議是,別名使用clientId袋毙,?它是對(duì)應(yīng)每臺(tái)設(shè)備唯一的型檀。但是如果使用clientId,就又存在一個(gè)用戶登錄多臺(tái)設(shè)備听盖,使用clientId單點(diǎn)推送就存在問(wèn)題胀溺。解決方法,可以使用useId做別名皆看。
/** SDK啟動(dòng)成功返回cid */
- (void)GeTuiSdkDidRegisterClient:(NSString *)clientId {
//個(gè)推SDK已注冊(cè)仓坞,返回clientId
NSLog(@"\n>>>[GeTuiSdk RegisterClient]:%@\n\n", clientId);
// 綁定別名
[GeTuiSdk bindAlias:advertisingUUID];
NSLog(@"個(gè)推別名======%@",advertisingUUID);
}
9、關(guān)于下發(fā)率:
10%的下發(fā)率確實(shí)不高腰吟,離線時(shí)間設(shè)置的比較短无埃,可以設(shè)置長(zhǎng)一點(diǎn),整個(gè)大盤(pán)的下發(fā)率在20-40%左右蝎困。
iOS的如果不設(shè)置離線時(shí)間录语,個(gè)推這邊是不會(huì)下發(fā)APNS消息的。應(yīng)用在手機(jī)上禾乘,至少要打開(kāi)一次澎埠,初始化成功SDK,獲取到CID始藕,這樣才可以推送蒲稳。
如果后面一直沒(méi)有打開(kāi),離線時(shí)間也設(shè)置了伍派,個(gè)推會(huì)推送APNS消息下發(fā)江耀。
離線時(shí)間是針對(duì)離線用戶的,推送下發(fā)的時(shí)候诉植,在線的用戶消息就直接推送到客戶端了祥国,離線的用戶,消息會(huì)作為離線消息存在離線庫(kù)里,離線用戶在離線時(shí)間內(nèi)在線舌稀,離線消息就會(huì)下發(fā)啊犬。
只有在離線時(shí)間內(nèi)打開(kāi)過(guò)應(yīng)用才統(tǒng)計(jì)下發(fā)率。
用戶離線情況如壁查,用戶進(jìn)程是關(guān)閉的觉至,網(wǎng)絡(luò)是斷開(kāi)等...
iOS的下發(fā)統(tǒng)計(jì)的是應(yīng)用打開(kāi)后,走個(gè)推長(zhǎng)連接通道下發(fā)的透?jìng)飨⒌南掳l(fā)睡腿。
比如說(shuō)一個(gè)用戶收到了apn通知语御,用戶在2小時(shí)(設(shè)置的離線時(shí)間為2小時(shí))內(nèi)都沒(méi)有打開(kāi)過(guò)app,那這個(gè)透?jìng)飨⒕筒粫?huì)下發(fā)了席怪,對(duì)應(yīng)的就統(tǒng)計(jì)不到了应闯。
也就是說(shuō),如果我設(shè)置離線時(shí)間2小時(shí)挂捻,應(yīng)用進(jìn)程關(guān)閉或者應(yīng)用在后臺(tái)孽锥,通知到來(lái),兩個(gè)小時(shí)后我再打開(kāi)應(yīng)用细层,這個(gè)時(shí)候不會(huì)走個(gè)推的代理方法收到透?jìng)飨ⅰ?/p>
10、 iOS同一臺(tái)設(shè)備唬涧,中文環(huán)境下先打了“中文”標(biāo)簽疫赎,切換到英文環(huán)境后再打“英文”標(biāo)簽,這時(shí)候在個(gè)推后臺(tái)中心向“中文”標(biāo)簽進(jìn)行推送碎节,英文環(huán)境同樣收到了中文通知捧搞,有解決辦法沒(méi)?
一般情況狮荔,標(biāo)簽設(shè)置一天只能成功設(shè)置一次胎撇,如果需要一天多次,可以提需求添加的殖氏。
11晚树、后一個(gè)標(biāo)簽會(huì)頂替掉前一個(gè)標(biāo)簽么?還是以前打的標(biāo)簽和后面的標(biāo)簽同時(shí)存在雅采?
標(biāo)簽設(shè)置是全量覆蓋的爵憎,后者全部替換前者。
12婚瓜、打標(biāo)簽的時(shí)效性宝鼓,執(zhí)行打標(biāo)簽操作,時(shí)間過(guò)了好久才有這樣的標(biāo)簽用戶巴刻?
開(kāi)通權(quán)限后愚铡,最高設(shè)置的記錄是一天100次。這個(gè)權(quán)限目前只有個(gè)推技術(shù)支持那邊可以設(shè)置胡陪。
二沥寥、 Device token(設(shè)備?令牌)概念:
這周在學(xué)習(xí)蘋(píng)果的消息推送(Apple Push Notification)碍舍,官方畫(huà)的流程圖很清晰,但是對(duì)里面的一個(gè)概念 device token 卻語(yǔ)焉不詳营曼。
讀完冗長(zhǎng)的文檔乒验,唯一有用的卻是一個(gè)注意事項(xiàng):
An application should register [with APN servers] every time it launches and give its provider the current token.每次應(yīng)用被打開(kāi)時(shí),開(kāi)發(fā)者都要重新收集當(dāng)前設(shè)備的 device token蒂阱,因?yàn)樗赡茏兞伺丁?br> stackoverflow 針對(duì)Device token 什么時(shí)候會(huì)發(fā)生變化有個(gè)很棒的解答锻全。
在一臺(tái)設(shè)備中, device token 是系統(tǒng)級(jí)別的录煤,不同 App 獲得的 device token 是相同的鳄厌。
假如我的手機(jī)安裝了 Angry Bird 和 Evernote ,這兩個(gè)應(yīng)用獲得 device token 一模一樣妈踊。
device token 并不會(huì)因?yàn)閱蝹€(gè) app 的更新而發(fā)生改變了嚎。
假如我的 iPhone 升級(jí)了最新版的憤怒的小鳥(niǎo),這并不會(huì)導(dǎo)致我 device token 的改變廊营。
假如我的 iPhone 從 backup 中恢復(fù)數(shù)據(jù)歪泳,device token 不會(huì)發(fā)生變化。
用戶抹除 iPhone 的數(shù)據(jù)時(shí)露筒,意味著要與這臺(tái)手機(jī)撇清關(guān)系呐伞,比如出售或者送人。此時(shí)為了保護(hù)隱私慎式,device token 會(huì)改變伶氢。
在需要發(fā)送push時(shí),我們的服務(wù)端就會(huì)取出要發(fā)送的設(shè)備的device token,然后以如下方式組成特定結(jié)構(gòu)字符串瘪吏,然后發(fā)送至APNs
參考:
1癣防、http://www.cnphp6.com/archives/50193
2、http://www.reibang.com/p/c46b60f06880
3掌眠、http://www.reibang.com/p/803bfaae989e
4蕾盯、http://mednoter.com/device-token.html
5、http://www.360doc.com/content/12/1116/09/10941785_248142762.shtml