概述
現(xiàn)在市面上大多數(shù)app白粉,都有根據(jù)某種條件传泊,服務(wù)端主動向用戶推送消息的需求。面對這個需求鸭巴,首先想到的是長鏈接眷细,如果服務(wù)端集成了HTTP/2的話,還可以用Server Push鹃祖。安卓在處理類似業(yè)務(wù)時就是這么干的溪椎,美其名曰透傳消息。但是我們期望的是恬口,無論是app退后臺還是被結(jié)束進(jìn)程校读,都可以正常收到消息。這就需要用到系統(tǒng)集的推送祖能。而在iOS平臺或者說蘋果全系統(tǒng)平臺歉秫,就是偉大的Apple Push Notification service 簡稱APNs。
開啟app的推送通知能力
在工程的Capability標(biāo)簽下养铸,打開 Push Notifications 開關(guān)
然后它會在你的AppId下
增加下圖的配置,你需要根據(jù)要求配置相關(guān)的推送證書(這塊就不說了)
以上就是配置推送環(huán)境的步驟雁芙,下面就可以寫代碼了
獲取推送權(quán)限
代碼如下,最好在 AppDelegate
的 didFinishLaunchingWithOptions
這個方法里面且做
if (@available(iOS 10.0, *)) {
UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
center.delegate = self; // 注意這里 不設(shè)置代理不會走推送的兩個代理方法
[center requestAuthorizationWithOptions:(UNAuthorizationOptionBadge | UNAuthorizationOptionSound | UNAuthorizationOptionAlert) completionHandler:^(BOOL granted, NSError * _Nullable error) {
if (granted) {
NSLog(@"iOS 10后 - 用戶授權(quán)通知權(quán)限");
}else {
NSLog(@"iOS 10后 - 用戶拒絕通知權(quán)限");
}
}];
[center getNotificationSettingsWithCompletionHandler:^(UNNotificationSettings * _Nonnull settings) {
NSLog(@"%@", settings);
}];
}else {
UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeBadge | UIUserNotificationTypeAlert | UIUserNotificationTypeSound categories:nil];
[[UIApplication sharedApplication] registerUserNotificationSettings:settings];
}
注冊完成之后我們還需要執(zhí)行[[UIApplication sharedApplication] registerForRemoteNotifications];
獲取推送的DeviceToken
系統(tǒng)就會去獲取揭厚,然后在didRegisterForRemoteNotificationsWithDeviceToken
這個代理方法中返回
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
{
if (@available(iOS 13.0, *)) {
NSMutableString *deviceTokenString = [NSMutableString string];
const char *bytes = deviceToken.bytes;
NSInteger count = deviceToken.length;
for (int i = 0; i < count; i++) {
[deviceTokenString appendFormat:@"%02x", bytes[i]&0x000000FF];
}
NSLog(@"iOS13 deviceToken:%@", deviceTokenString);
} else {
NSString *deviceTokenStr = [[[[deviceToken description]
stringByReplacingOccurrencesOfString:@"<" withString:@""]
stringByReplacingOccurrencesOfString:@">" withString:@""]
stringByReplacingOccurrencesOfString:@" " withString:@""];
NSLog(@"iOS13-Pre deviceToken:%@", deviceTokenStr);
}
}
獲取到token后給服務(wù)器却特,執(zhí)行推送指令扶供。
服務(wù)器推送格式:
注意:body和title必須要有一個才行筛圆,不然推送不彈窗。
{
"aps" : {
"alert" : {
"title" : "Test-Push",
"body" : "Your message Here"
},
}
}
這個時候我們還不能收到推送椿浓,因為我們還沒實現(xiàn) UNUserNotificationCenter
的代理方法
代碼如下
/// 收到推送后太援,會先調(diào)用這個方法闽晦,它可以設(shè)置推送要顯示的方式是啥 常用的配置如代碼所示
- (void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions options))completionHandler
{
NSLog(@"willPresentNotification");
UNNotificationPresentationOptions options = UNNotificationPresentationOptionAlert | UNNotificationPresentationOptionSound | UNNotificationPresentationOptionBadge;
completionHandler(options);
}
// 上面的代理方法走了之后,會在用戶與你推送的通知進(jìn)行交互時被調(diào)用提岔,包括用戶通過通知打開了你的應(yīng)用仙蛉,或者點(diǎn)擊或者觸發(fā)了某個 action
- (void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void(^)(void))completionHandler
{
UNNotificationContent *content = response.notification.request.content;
//NSLog(@"didReceiveNotificationResponse %@", content);
NSDictionary *responseDict = content.userInfo;
NSLog(@"didReceiveNotificationResponse %@", responseDict);
completionHandler();
}
靜默推送
就是實現(xiàn)下面的代理方法
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler
這里有個注意點(diǎn):如果你實現(xiàn)了這個方法且運(yùn)行在iOS10以下的設(shè)備的時候,所有的遠(yuǎn)程推送都是走這個方法的碱蒙,iOS10之前的didReceiveRemoteNotification
這個代理方法是不會走的荠瘪。除非你沒實現(xiàn)上面的代理方法
當(dāng)我們不請求推送權(quán)限,或者用戶拒絕或者主動關(guān)閉了推送權(quán)限赛惩,推送還是可以正常到達(dá)設(shè)備的哀墓。但是沒有橫幅也沒有聲音,是以靜默形式呈現(xiàn)喷兼。如果跟常規(guī)的推送混合著使用篮绰,場景會復(fù)雜一些。
必須打開后臺模式季惯,并勾選Remote notification吠各,我們之前介紹的那些方法才會被觸發(fā)。
我們在payload中不包含alert勉抓、sound贾漏、badge,無論app推送權(quán)限是否打開琳状,都屬于靜默推送磕瓷。
原則上,后臺模式的推送應(yīng)該是靜默推送念逞。在iOS13以后困食,需要在請求頭中apns-push-type字段設(shè)置為backgroud。而如果不是真正的靜默推送翎承,有被APNs丟棄的危險硕盹。
在服務(wù)推送的時候需要在payload中包含content-available并且值為1 這樣才會走上面的代理方法
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler
這里補(bǔ)充下iOS10以下的設(shè)備如果實現(xiàn)了上面的代理方法,所有推送都會走那里不會走原來的- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
方法
遠(yuǎn)程推送格式為:(大小限制好像是5kb
)
{
"aps" : {
"alert" : {
"title" : "Test-Push",
"body" : "Your message Here"
},
"content-available" : 1
}
}
靜默推送和UNUserNotificationCenter同時使用的情況下
注意:
fetchCompletionHandler 代表下面的代理方法
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler
didReceiveNotificationResponse 代表下面的代理方法
- (void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void(^)(void))completionHandler
推送模式如下圖表格所示:
設(shè)置 "content-available" = 1 | 是否實現(xiàn)代理方法 | 是否彈窗 | 是否需要點(diǎn)擊彈窗 | 執(zhí)行的方法 | |
---|---|---|---|---|---|
App前臺 | 是 | 是 | 是 | 否 | fetchCompletionHandler |
否 | 是 | 是 | 是 | didReceiveNotificationResponse | |
是 | 否 | 否 | 否 | fetchCompletionHandler | |
否 | 否 | 否 | 否 | fetchCompletionHandler | |
App后臺 | 是 | 是 | 是 | 否 | fetchCompletionHandler |
否 | 是 | 是 | 是 | didReceiveNotificationResponse | |
是 | 否 | 是 | 否 | fetchCompletionHandler | |
否 | 否 | 是 | 是 | fetchCompletionHandler | |
App殺死 | 是 | 是 | 是 | 否 | fetchCompletionHandler |
否 | 是 | 是 | 是 | didReceiveNotificationResponse | |
是 | 否 | 是 | 否 | fetchCompletionHandler | |
否 | 否 | 是 | 是 | fetchCompletionHandler |
iOS10以下設(shè)備的推送模式如下
// iOS 9 遠(yuǎn)程推送和后臺推送都走這里 app殺死的情況需要點(diǎn)擊彈窗 后臺模式也會彈窗(需要點(diǎn)擊)前臺不彈窗 直接執(zhí)行 走fetchCompletionHandler方法
// 前臺模式設(shè)置了"content-available" = 1; 與否 前臺不彈窗 直接執(zhí)行
// 后臺模式設(shè)置了"content-available" = 1; 彈窗 直接執(zhí)行 不設(shè)置 彈窗 需要點(diǎn)擊執(zhí)行
// App殺死設(shè)置了"content-available" = 1; 與否 彈窗 都需要點(diǎn)擊執(zhí)行
推送調(diào)試
- 在
didReceiveIncomingPushWithPayload
這個代理方法中獲取的token 添加到Easy APNs Provider
中 - 選擇推送的證書
- 點(diǎn)擊開始連接
gateway.sanbox.push.apple.com
對應(yīng)的是開發(fā)證書叨咖,gateway.push.apple.com
對應(yīng)的是生產(chǎn)證書 - 然后就可以點(diǎn)擊發(fā)送推送即可
軟件不太好找 這里給你們分享下
鏈接: https://pan.baidu.com/s/16INLhg3V6CuVU5pJjDqptQ 提取碼: wc6h 復(fù)制這段內(nèi)容后打開百度網(wǎng)盤手機(jī)App瘩例,操作更方便哦