最近因為公司的業(yè)務需求,對推送做了相應的修改。因為之前用的是極光的推送,對于推送也沒有太多的要求,來消息就在通知欄展示,有角標展示即可。可是因為最近需求變更,對于推送需求也有了詳細的要求。這也讓我從新來review遍關(guān)于推送方面的知識。尤其是iOS10之后,推送的細分化,有了更多的認識。特在此做一個總結(jié)。
這里不再對原理進行闡述。
一、遠程推送
iphone在接受到遠端推送的通知,打開App后,程序會運行appDelegate的代理,這里分三種狀態(tài)
1.APP在未運行,已殺死進程的狀態(tài),遠程推送過來消息
2.APP在已運行,但APP未在前臺,就是在后臺,APP展示的不是此時的這個程序,這個時候,遠程推送過來消息
3.APP已運行,此時程序在前臺,就是我們正在玩我們的APP時,遠程推送過來消息
此時我們點擊通知欄消息后,在AppDelegate.m文件中相應的代理(代碼中對應的是個推的一些特殊跳轉(zhuǎn)處理):
1.1下面是對應1這種情況,app首次打開會進入這個方法:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
//獲取 APNs(通知) 推送內(nèi)容(app未啟動時接受推送消息)
//推送的信息會含在launchOption的字典內(nèi),取出后,分析其對應的key值
NSDictionary *remoteDic = [launchOptions objectForKey: UIApplicationLaunchOptionsRemoteNotificationKey];
if (remoteDic)
{
//這里因為個推平臺有一個所謂的透傳消息,從平臺推送過來和我們自己服務器搭建后臺推送的時候有所不同,所以做了處理,以防止后面做跳轉(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這里對應2的情況,因為iOS10的原因所以,需要在兩個方法里都寫
//在iOS 10 以前,為處理 APNs 通知點擊事件,統(tǒng)計有效用戶點擊數(shù),需在AppDelegate.m里的didReceiveRemoteNotification回調(diào)方法中調(diào)用個推SDK統(tǒng)計接口
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
// 將收到的APNs信息傳給個推統(tǒng)計
[GeTuiSdk handleRemoteNotification:userInfo];
completionHandler(UIBackgroundFetchResultNewData);
//推送后臺跳轉(zhuǎn)
if (application.applicationState == UIApplicationStateActive) {
NSLog(@"active");
//程序當前正處于前臺
}
else if(application.applicationState == UIApplicationStateInactive)
{
[GeTuiSdk setBadge:0];
NSLog(@"inactive");
//程序處于后臺
[self jumpPage:userInfo];
}
}
// iOS 10: 點擊通知進入App時觸發(fā),在該方法內(nèi)統(tǒng)計有效用戶點擊數(shù)
- (void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void (^)())completionHandler {
NSLog(@"didReceiveNotification:%@", response.notification.request.content.userInfo);
// [ GTSdk ]:將收到的APNs信息傳給個推統(tǒng)計
[GeTuiSdk handleRemoteNotification:response.notification.request.content.userInfo];
completionHandler();
[GeTuiSdk setBadge:0];
//iOS10以上,點擊通知欄推送跳轉(zhuǎn)
NSDictionary *dic = response.notification.request.content.userInfo;
[self jumpPage:dic];
}
1.3第三種情況,這里要說下關(guān)于個推的透傳功能,個推的透傳功能說是為了補充APN的不穩(wěn)定的。但是在使用中,個推其實推送的到達率也并不是100%,而因為早期對個推透傳功能的理解不太深入,尤其是在線和離線的消息推送,走了不少坑?,F(xiàn)在先說下在app開啟運行的時候,程序會運行下面這個代理
- (void)GeTuiSdkDidReceivePayloadData:(NSData *)payloadData andTaskId:(NSString *)taskId andMsgId:(NSString *)msgId andOffLine:(BOOL)offLine fromGtAppId:(NSString *)appId {
//收到個推消息
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)
{
}
}
上面是當app不在前臺的時候個推處于離線狀態(tài),app走APNS過來的。對于個推而言,當點擊推送的通知欄,打開app都會走上面的代碼,但由于app開啟后,個推平臺有可能未能連接,會出現(xiàn)推送不出來,或者有時候一下好多條。所以,我對個推這個離線的隊列感到不可信。所以,在離線的時候走APNS,因此這樣寫的推送相關(guān)的代碼。
二、紅點,角標,通知欄
對于個推,角標是由+ (void)setBadge:(NSUInteger)value這個方法來設置的,而這個角標就是在個推平臺計數(shù)的角標,所以當使用+1的時候,如果不把這個角標設置的話,角標都會+1的,所以當再次來推送的時候,會在原有的基礎上+1,不會從0開始計數(shù),所以,要在每個點擊通知欄后的代理方法里對個推的角標設置
[GeTuiSdk setBadge:0];
而如果想把app圖標角標清除,需要用
[[UIApplication sharedApplication] setApplicationIconBadgeNumber:0];
但是使用這個的話,通知欄也會完全清除掉。當然如果你需要清除所有通知欄,可以使用這個方法,但是我們要求的是要保留通知欄,可點擊app不是點擊通知欄的時候,角標清除。查看了許多網(wǎng)上的大家的處理方式,最后使用本地推送的折中方式來解決。
在app進入從后臺變?yōu)榍芭_的時候啟動一條本地推送,并設置角標為-1,緊接著馬上取消本地推送。
- (void)applicationDidBecomeActive:(UIApplication *)application {
//設置推送紅點取消
//1.設置本地推送
UILocalNotification *localNote = [[UILocalNotification alloc] init];
localNote.applicationIconBadgeNumber = -1;
[[UIApplication sharedApplication] scheduleLocalNotification:localNote];
[[UIApplication sharedApplication] cancelLocalNotification:localNote];
}