最近因?yàn)楣镜臉I(yè)務(wù)需求,對推送做了相應(yīng)的修改告喊。因?yàn)橹坝玫氖菢O光的推送麸拄,對于推送也沒有太多的要求,來消息就在通知欄展示黔姜,有角標(biāo)展示即可拢切。可是因?yàn)樽罱枨笞兏殉常瑢τ谕扑托枨笠灿辛嗽敿?xì)的要求淮椰。這也讓我從新來review遍關(guān)于推送方面的知識(shí)。尤其是iOS10之后,推送的細(xì)分化主穗,有了更多的認(rèn)識(shí)泻拦。特在此做一個(gè)總結(jié)。
這里不再對原理進(jìn)行闡述黔牵。
一聪轿、遠(yuǎn)程推送
iphone在接受到遠(yuǎn)端推送的通知,打開App后猾浦,程序會(huì)運(yùn)行appDelegate的代理陆错,這里分三種狀態(tài)
1.APP在未運(yùn)行,已殺死進(jìn)程的狀態(tài)金赦,遠(yuǎn)程推送過來消息
2.APP在已運(yùn)行音瓷,但APP未在前臺(tái),就是在后臺(tái)夹抗,APP展示的不是此時(shí)的這個(gè)程序绳慎,這個(gè)時(shí)候,遠(yuǎn)程推送過來消息
3.APP已運(yùn)行漠烧,此時(shí)程序在前臺(tái)杏愤,就是我們正在玩我們的APP時(shí),遠(yuǎn)程推送過來消息
此時(shí)我們點(diǎn)擊通知欄消息后已脓,在AppDelegate.m文件中相應(yīng)的代理(代碼中對應(yīng)的是個(gè)推的一些特殊跳轉(zhuǎn)處理):
1.1下面是對應(yīng)1這種情況珊楼,app首次打開會(huì)進(jìn)入這個(gè)方法:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
//獲取 APNs(通知) 推送內(nèi)容(app未啟動(dòng)時(shí)接受推送消息)
//推送的信息會(huì)含在launchOption的字典內(nèi),取出后度液,分析其對應(yīng)的key值
NSDictionary *remoteDic = [launchOptions objectForKey: UIApplicationLaunchOptionsRemoteNotificationKey];
if (remoteDic)
{
//這里因?yàn)閭€(gè)推平臺(tái)有一個(gè)所謂的透傳消息厕宗,從平臺(tái)推送過來和我們自己服務(wù)器搭建后臺(tái)推送的時(shí)候有所不同,所以做了處理堕担,以防止后面做跳轉(zhuǎn)崩潰
NSString *url = nil;
if ([remoteDic objectForKey:@"payload"])
{
NSString *payloadStr = [remoteDic objectForKey:@"payload"];
NSDictionary *payload = [NSString zhGetJSONSerializationObjectFormString:payloadStr];
url = [payload objectForKey:@"url"];
}
else
{
url = [remoteDic objectForKey:@"url"];
}
//這里寫自己的跳轉(zhuǎn)
[WYUserDefaultManager setDidFinishLaunchRemoteNoti:url];
}
}
1.2這里對應(yīng)2的情況已慢,因?yàn)閕OS10的原因所以,需要在兩個(gè)方法里都寫
//在iOS 10 以前霹购,為處理 APNs 通知點(diǎn)擊事件佑惠,統(tǒng)計(jì)有效用戶點(diǎn)擊數(shù),需在AppDelegate.m里的didReceiveRemoteNotification回調(diào)方法中調(diào)用個(gè)推SDK統(tǒng)計(jì)接口
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
// 將收到的APNs信息傳給個(gè)推統(tǒng)計(jì)
[GeTuiSdk handleRemoteNotification:userInfo];
completionHandler(UIBackgroundFetchResultNewData);
//推送后臺(tái)跳轉(zhuǎn)
if (application.applicationState == UIApplicationStateActive) {
NSLog(@"active");
//程序當(dāng)前正處于前臺(tái)
}
else if(application.applicationState == UIApplicationStateInactive)
{
[GeTuiSdk setBadge:0];
NSLog(@"inactive");
//程序處于后臺(tái)
[self jumpPage:userInfo];
}
}
// iOS 10: 點(diǎn)擊通知進(jìn)入App時(shí)觸發(fā)齐疙,在該方法內(nèi)統(tǒng)計(jì)有效用戶點(diǎn)擊數(shù)
- (void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void (^)())completionHandler {
NSLog(@"didReceiveNotification:%@", response.notification.request.content.userInfo);
// [ GTSdk ]:將收到的APNs信息傳給個(gè)推統(tǒng)計(jì)
[GeTuiSdk handleRemoteNotification:response.notification.request.content.userInfo];
completionHandler();
[GeTuiSdk setBadge:0];
//iOS10以上兢仰,點(diǎn)擊通知欄推送跳轉(zhuǎn)
NSDictionary *dic = response.notification.request.content.userInfo;
[self jumpPage:dic];
}
1.3第三種情況,這里要說下關(guān)于個(gè)推的透傳功能剂碴,個(gè)推的透傳功能說是為了補(bǔ)充APN的不穩(wěn)定的把将。但是在使用中,個(gè)推其實(shí)推送的到達(dá)率也并不是100%忆矛,而因?yàn)樵缙趯€(gè)推透傳功能的理解不太深入察蹲,尤其是在線和離線的消息推送请垛,走了不少坑。現(xiàn)在先說下在app開啟運(yùn)行的時(shí)候洽议,程序會(huì)運(yùn)行下面這個(gè)代理
- (void)GeTuiSdkDidReceivePayloadData:(NSData *)payloadData andTaskId:(NSString *)taskId andMsgId:(NSString *)msgId andOffLine:(BOOL)offLine fromGtAppId:(NSString *)appId {
//收到個(gè)推消息
NSString *payloadMsg = nil;
if (payloadData) {
payloadMsg = [[NSString alloc] initWithBytes:payloadData.bytes length:payloadData.length encoding:NSUTF8StringEncoding];
}
NSString *msg = [NSString stringWithFormat:@"taskId=%@,messageId:%@,payloadMsg:%@%@",taskId,msgId, payloadMsg,offLine ? @"<離線消息>" : @""];
NSLog(@"\n>>>[GexinSdk ReceivePayload]:%@\n\n", msg);
NSData *jsonData = [payloadMsg dataUsingEncoding:NSUTF8StringEncoding];
NSDictionary *dic = [NSJSONSerialization JSONObjectWithData:jsonData options:NSJSONReadingMutableContainers error:nil];
NSString *type = [[dic objectForKey:@"extra"] objectForKey:@"type"];
//不是離線消息處理
if (!offLine)
{
}
}
上面是當(dāng)app不在前臺(tái)的時(shí)候個(gè)推處于離線狀態(tài)宗收,app走APNS過來的。對于個(gè)推而言亚兄,當(dāng)點(diǎn)擊推送的通知欄混稽,打開app都會(huì)走上面的代碼,但由于app開啟后审胚,個(gè)推平臺(tái)有可能未能連接匈勋,會(huì)出現(xiàn)推送不出來,或者有時(shí)候一下好多條膳叨。所以洽洁,我對個(gè)推這個(gè)離線的隊(duì)列感到不可信。所以菲嘴,在離線的時(shí)候走APNS饿自,因此這樣寫的推送相關(guān)的代碼。
二龄坪、紅點(diǎn)昭雌,角標(biāo),通知欄
對于個(gè)推健田,角標(biāo)是由+ (void)setBadge:(NSUInteger)value這個(gè)方法來設(shè)置的城豁,而這個(gè)角標(biāo)就是在個(gè)推平臺(tái)計(jì)數(shù)的角標(biāo),所以當(dāng)使用+1的時(shí)候抄课,如果不把這個(gè)角標(biāo)設(shè)置的話,角標(biāo)都會(huì)+1的雳旅,所以當(dāng)再次來推送的時(shí)候跟磨,會(huì)在原有的基礎(chǔ)上+1,不會(huì)從0開始計(jì)數(shù)攒盈,所以抵拘,要在每個(gè)點(diǎn)擊通知欄后的代理方法里對個(gè)推的角標(biāo)設(shè)置
[GeTuiSdk setBadge:0];
而如果想把a(bǔ)pp圖標(biāo)角標(biāo)清除,需要用
[[UIApplication sharedApplication] setApplicationIconBadgeNumber:0];
但是使用這個(gè)的話型豁,通知欄也會(huì)完全清除掉僵蛛。當(dāng)然如果你需要清除所有通知欄,可以使用這個(gè)方法迎变,但是我們要求的是要保留通知欄充尉,可點(diǎn)擊app不是點(diǎn)擊通知欄的時(shí)候,角標(biāo)清除衣形。查看了許多網(wǎng)上的大家的處理方式驼侠,最后使用本地推送的折中方式來解決姿鸿。
在app進(jìn)入從后臺(tái)變?yōu)榍芭_(tái)的時(shí)候啟動(dòng)一條本地推送,并設(shè)置角標(biāo)為-1倒源,緊接著馬上取消本地推送苛预。
- (void)applicationDidBecomeActive:(UIApplication *)application {
//設(shè)置推送紅點(diǎn)取消
//1.設(shè)置本地推送
UILocalNotification *localNote = [[UILocalNotification alloc] init];
localNote.applicationIconBadgeNumber = -1;
[[UIApplication sharedApplication] scheduleLocalNotification:localNote];
[[UIApplication sharedApplication] cancelLocalNotification:localNote];
}