一癌蚁、證書(shū)相關(guān)
? ? 1幻梯、首先我們要配置兩個(gè)證書(shū):推送測(cè)試證書(shū)、推送正式證書(shū)努释。 ? 先打開(kāi)AppID的推送功能
? ? 在配置證書(shū)界面礼旅,Certificates-Development(這是開(kāi)發(fā)證書(shū)即測(cè)試用,Production這是生產(chǎn)證書(shū)即正式)
? ? ? ? <1.測(cè)試證書(shū):選擇 Apple Push Notification service SSL (Sandbox) ? 選擇 App ID ? 選擇 創(chuàng)建mac的csr文件(csr創(chuàng)建步? ? ? ? 驟:選擇鑰匙串訪(fǎng)問(wèn)工具-- 證書(shū)助理--從證書(shū)頒發(fā)機(jī)構(gòu)請(qǐng)求證書(shū)--存到磁盤(pán))
? ? 下載并安裝測(cè)試證書(shū)
? ? ? ? <2.正式證書(shū):選擇 App Store and Ad Hoc ? 其他與測(cè)試證書(shū)步驟一致
? ? ? 2.為后臺(tái)服務(wù)方提供p12文件
? ? ? ? 不論是使用第三方(極光友盟等)還是后端人員自己寫(xiě)的推送洽洁,都需要將安裝的證書(shū)導(dǎo)出為P12文件:在mac的鑰匙串中,選擇安裝的推送證書(shū)菲嘴,右鍵選擇導(dǎo)出饿自,選擇.p12
(一定要是創(chuàng)建證書(shū)的電腦才可以導(dǎo)出為p12)。 有的推送第三方需要.pem文件龄坪,則需要對(duì)p12文件進(jìn)行轉(zhuǎn)換昭雌,具體:http://www.reibang.com/p/cc952ea07a08?mType=Group
二、代碼
? ? 1.打開(kāi)項(xiàng)目中的推送開(kāi)關(guān)
? ? ? ? Capabilities--Push Notifications 若AppID的推送打開(kāi)健田,且證書(shū)安裝好烛卧,則Push Notifications下的兩步都會(huì)打鉤,證明準(zhǔn)備步驟都已就緒
? ? ? 2.各種方法的作用,Appdelegate要遵守UNUserNotificationCenterDelegate協(xié)議
? ? ? ? ? ? ? ? 首先是啟動(dòng)方法didFinishLaunchingWithOptions妓局,在這里注冊(cè)推送服務(wù)
// 程序第一次啟動(dòng)的時(shí)候調(diào)用(點(diǎn)擊通知啟動(dòng) 和 點(diǎn)擊app圖標(biāo)啟動(dòng) 都會(huì)走這個(gè)方法总放,所以這種情況下 要在這里獲取推送的內(nèi)容)
-(BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
? ? self.isFirstLaunch = YES;
//這里是獲取推送內(nèi)容
? ? NSDictionary* remoteNotification = [launchOptions objectForKey:UIApplicationLaunchOptionsRemoteNotificationKey];
? ? if (remoteNotification) {
? ? ? ? //點(diǎn)擊通知框進(jìn)入app可以在此接收通知(只在殺死狀態(tài)下可以接收到),之后會(huì)調(diào)用didReceiveRemoteNotification,因?yàn)榇朔椒ㄕ{(diào)用時(shí),控制器已經(jīng)創(chuàng)建完畢,可以跳轉(zhuǎn)
? ? }else{
? ? ? ? //點(diǎn)擊圖標(biāo)進(jìn)入app
? }
//這里要注冊(cè)推送服務(wù)
? if (kOS >= 10.0) { // 設(shè)置能夠接收通知 的類(lèi)型
? ? ? UNUserNotificationCenter * center = [UNUserNotificationCenter currentNotificationCenter];? ? ? ? ? ? ? ?
? ? ? ? [center setDelegate:self];
? ? ? UNAuthorizationOptions type = UNAuthorizationOptionBadge|UNAuthorizationOptionSound|UNAuthorizationOptionAlert;
? ? ? [center requestAuthorizationWithOptions:type completionHandler:^(BOOL granted, NSError * _Nullable error) {
? ? ? ? ? if (granted) {
? ? ? ? ? ? ? Log(@"注冊(cè)成功");
? ? ? ? ? ? ? [center getNotificationSettingsWithCompletionHandler:^(UNNotificationSettings * _Nonnull settings) {
? ? ? ? ? ? ? ? ? ? Log(@"%@",settings);
? ? ? ? ? ? ? ? }];
? ? ? ? ? }else{
? ? ? ? ? ? ? Log(@"注冊(cè)失敗");
? ? ? ? ? }
? ? ? }];
? } else if (kOS >= 8.0){
? ? ? UIUserNotificationType notificationTypes = UIUserNotificationTypeBadge |
? ? ? UIUserNotificationTypeSound |
? ? ? UIUserNotificationTypeAlert;
? ? ? UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:notificationTypes categories:nil];
? ? ? [application registerUserNotificationSettings:settings];
? }
? // 注冊(cè)通知
? ? [application registerForRemoteNotifications];
? return YES;
}
? ? ? ? 接下來(lái)這是獲得deviceToken的方法(deviceToken好爬,是apns服務(wù)給每個(gè)設(shè)備的標(biāo)示局雄,通過(guò)這個(gè)標(biāo)示才能推送到指定設(shè)備,且deviceToken是變化的存炮,一般在應(yīng)用卸載重裝炬搭,或者系統(tǒng)升級(jí)才會(huì)改變)
// 1 每次程序啟動(dòng)都會(huì)調(diào)用
- (void)application:(UIApplication *)application
didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
{
? ? //在這里把token傳給后臺(tái)
? ? NSString *deviceTokenStr = [[[[deviceToken description]
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? stringByReplacingOccurrencesOfString:@"<" withString:@""]
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? stringByReplacingOccurrencesOfString:@">" withString:@""]
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? stringByReplacingOccurrencesOfString:@" " withString:@""];
? Log(@"deviceTokenStr:\n%@",deviceTokenStr);
? ? NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
? ? [defaults setObject:deviceTokenStr forKey:@"deviceToken"];
? ? [defaults synchronize];
//這個(gè)方法 是我向后端數(shù)據(jù)庫(kù)更新token的請(qǐng)求蜈漓,如果用第三方推送可忽略
? ? [PushService updateDeviceToken];
}
? ? ? ? didFailToRegisterForRemoteNotificationsWithError這個(gè)方法就不多說(shuō)了,是token獲取失敗調(diào)用宫盔,我們可以在這里向后臺(tái)注銷(xiāo)這個(gè)用戶(hù)的token
? ? ? ? willPresentNotification這個(gè)方法在iOS10才有的融虽,用來(lái)設(shè)置應(yīng)用在前臺(tái)運(yùn)行時(shí),收到通知的提醒模型
#pragma mark- UNUserNotificationCenterDelegate(iOS10以上)
//在前臺(tái)收到通知(程序運(yùn)行時(shí)走此方法)
- (void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions))completionHandler{
? // 需要執(zhí)行這個(gè)方法灼芭,選擇是否提醒用戶(hù)有额,有Badge、Sound姿鸿、Alert三種類(lèi)型可以設(shè)置
? ? //如果加上這三個(gè)枚舉谆吴,則用戶(hù)即使在前臺(tái)收到通知也會(huì)出現(xiàn),有聲音和角標(biāo)苛预。如果去掉在前臺(tái)則不會(huì)收到
? ? completionHandler(UNNotificationPresentationOptionBadge|
? ? ? ? ? ? ? ? ? ? UNNotificationPresentationOptionSound|
? ? ? ? ? ? ? ? ? ? UNNotificationPresentationOptionAlert);
}
? ? ? ? didReceiveNotificationResponse是應(yīng)用處于任何狀態(tài)下句狼,用戶(hù)點(diǎn)擊了推送通知的彈框,就會(huì)調(diào)用
// iOS 10之后 任何狀態(tài)用戶(hù)點(diǎn)擊了通知 (用戶(hù)點(diǎn)擊了通知時(shí)走此方法)
- (void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void (^)())completionHandler{
? ? NSDictionary *userInfo = response.notification.request.content.userInfo;
//這里可以處理收到的推送消息
? ? ? ? if (userInfo[@"aps"][@"url"]) {
? ? ? ? ? ? [ToolsHelper receiveMessageAndPushcontroller:userInfo[@"aps"][@"url"]];
? ? ? ? }
? ? }
? completionHandler();
? ? return;
}
? ? didReceiveRemoteNotification? 這個(gè)方法在iOS10以下热某,應(yīng)用在前臺(tái)的時(shí)候腻菇,有推送來(lái),會(huì)直接來(lái)到這個(gè)方法昔馋,但通知欄不會(huì)有提示筹吐,角標(biāo)也不會(huì)有,應(yīng)用如果在后臺(tái)后者關(guān)閉狀態(tài)秘遏,點(diǎn)擊推送來(lái)的消息也會(huì)來(lái)到這個(gè)方法丘薛,我們可以在這里處理業(yè)務(wù)邏輯(由于要處理iOS10以前設(shè)備在前臺(tái)收到通知的提醒,所以要將通知轉(zhuǎn)為本地通知進(jìn)行彈窗提示)
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
? Log(@"userInfo: %@", userInfo.description);
? if ( application.applicationState == UIApplicationStateActive) {
? ? ? ? // 程序在運(yùn)行過(guò)程中收到推送通知,轉(zhuǎn)換成一個(gè)本地通知邦危,顯示到通知欄
? ? ? ? UILocalNotification *localNotification = [[UILocalNotification alloc] init];
? ? ? ? localNotification.userInfo = userInfo;
? ? ? ? localNotification.soundName = UILocalNotificationDefaultSoundName;
? ? ? ? localNotification.alertBody = [[userInfo objectForKey:@"aps"]objectForKey:@"alert"];
? ? ? ? localNotification.fireDate = [NSDate date];
? ? ? ? [[UIApplication sharedApplication] scheduleLocalNotification:localNotification];
? } else {
? ? ? //在后臺(tái)或者關(guān)閉狀態(tài)收到推送通知
? ? }
? completionHandler(UIBackgroundFetchResultNewData);
}
以上就是常規(guī)推送需要處理的方法
在iOS10洋侨,推送已經(jīng)可以推圖片,git圖倦蚪,短視頻了希坚,也可以自定義彈窗的操作按鈕。接下來(lái)就看一下陵且,怎么推送簡(jiǎn)單的圖片裁僧,這種推送有自己的UI和方法,也相當(dāng)于一個(gè)target了慕购。所以創(chuàng)建方法也跟普通推送不太一樣聊疲。
? ? 選擇File-New-Target
創(chuàng)建后,系統(tǒng)會(huì)生成一個(gè)PushServiceEx的文件夾沪悲,里面有一個(gè)NotificationService的類(lèi)售睹,同時(shí)也會(huì)有一個(gè)PushServiceEx的target生成,如果未找到這個(gè)target? 就在manger Schemes里面勾上可训。
下面是NotificationService類(lèi)中的代碼昌妹,這個(gè)類(lèi)的方法會(huì)在手機(jī)接收到帶圖片的推送時(shí)調(diào)用捶枢,且負(fù)責(zé)下載這個(gè)圖片,然后保存展示飞崖。(imageUrl是推送時(shí)烂叔,定義圖片url的字段)
- (void)didReceiveNotificationRequest:(UNNotificationRequest *)request withContentHandler:(void (^)(UNNotificationContent * _Nonnull))contentHandler {
? ? self.contentHandler = contentHandler;
? ? self.bestAttemptContent = [request.content mutableCopy];
? ? NSDictionary *dict =? self.bestAttemptContent.userInfo;
? ? NSDictionary *notiDict = dict[@"aps"];
? ? NSString *imgUrl = [NSString stringWithFormat:@"%@",notiDict[@"imageUrl"]];
? if (!imgUrl.length) {
? ? ? self.contentHandler(self.bestAttemptContent);
? }else{
//這是下載推片的方法
? ? ? ? [self loadAttachmentForUrlString:imgUrl withType:@"image" completionHandle:^(UNNotificationAttachment *attach) {
? ? ? ? ? if (attach) {
? ? ? ? ? ? ? ? self.bestAttemptContent.attachments = [NSArray arrayWithObject:attach];
? ? ? ? ? ? }
? ? ? ? ? ? self.contentHandler(self.bestAttemptContent);
? ? ? ? }];
? ? }
}
- (void)loadAttachmentForUrlString:(NSString *)urlStr
? ? ? ? ? ? ? ? ? ? ? ? ? withType:(NSString *)type
? ? ? ? ? ? ? ? ? completionHandle:(void(^)(UNNotificationAttachment *attach))completionHandler{
? __block UNNotificationAttachment *attachment = nil;
? ? NSURL *attachmentURL = [NSURL URLWithString:urlStr];
? ? NSString *fileExt = [self fileExtensionForMediaType:type];
? NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]];
? ? [[session downloadTaskWithURL:attachmentURL
? ? ? ? ? ? ? ? completionHandler:^(NSURL *temporaryFileLocation, NSURLResponse *response, NSError *error) {
? ? ? ? ? ? ? ? ? ? if (error != nil) {
? ? ? ? ? ? ? ? ? ? ? ? NSLog(@"%@", error.localizedDescription);
? ? ? ? ? ? ? ? ? ? } else {
? ? ? ? ? ? ? ? ? ? ? ? NSFileManager *fileManager = [NSFileManager defaultManager];
? ? ? ? ? ? ? ? ? ? ? ? NSURL *localURL = [NSURL fileURLWithPath:[temporaryFileLocation.path stringByAppendingString:fileExt]];
? ? ? ? ? ? ? ? ? ? ? ? [fileManager moveItemAtURL:temporaryFileLocation toURL:localURL error:&error];
? ? ? ? ? ? ? ? ? ? ? NSError *attachmentError = nil;
? ? ? ? ? ? ? ? ? ? ? ? attachment = [UNNotificationAttachment attachmentWithIdentifier:@"" URL:localURL options:nil error:&attachmentError];
? ? ? ? ? ? ? ? ? ? ? ? if (attachmentError) {
//? ? ? ? ? ? ? ? ? ? ? ? ? ? log(@"%@", attachmentError.localizedDescription);
? ? ? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? completionHandler(attachment);
? ? ? ? ? ? ? ? }] resume];
}
- (NSString *)fileExtensionForMediaType:(NSString *)type {
? ? NSString *ext = type;
? if ([type isEqualToString:@"image"]) {
? ? ? ? ext = @"jpg";
? ? }
? if ([type isEqualToString:@"video"]) {
? ? ? ? ext = @"mp4";
? ? }
? if ([type isEqualToString:@"audio"]) {
? ? ? ? ext = @"mp3";
? ? }
? return [@"." stringByAppendingString:ext];
}
要完成這個(gè)圖片推送? PushServiceEx? target有幾個(gè)要注意的點(diǎn):
? ? 第一個(gè):測(cè)試一定要選擇這個(gè)target進(jìn)行安裝。
? ? 第二個(gè):這個(gè)target支持的development target 版本一定要填對(duì)固歪,我之前就因?yàn)樘盍薸OS11蒜鸡,但是用10的機(jī)子測(cè)了半天都只是普通推送沒(méi)有圖片。
? ? 第三個(gè):target的版本不能小于項(xiàng)目的版本牢裳,否則會(huì)在提交應(yīng)用到appstore的時(shí)候逢防,有警告
? ? 第四個(gè): "mutable-content" : 1? 推送時(shí)一定要有這個(gè)參數(shù),不然就會(huì)被手機(jī)認(rèn)為是普通推送蒲讯。推送的json應(yīng)該像這樣 忘朝。? ?
{
? ? "aps" : {
? ? ? ? "alert" : "Your message here.",
? ? ? ? "badge" : 9,
? ? ? ? "sound" : "default",
? ? ? ? "mutable-content" : 1,
? ? ? ? "imageUrl" : "https://www.xxxxxxxx.png"
? ? },
}
三、測(cè)試
? ? 1.推送工具
? ? ? ? 如果后臺(tái)的小伙伴沒(méi)時(shí)間跟我們測(cè)試推送判帮,就可以自己用推送小工具局嘁,只需要我們下載的推送證書(shū)(后綴為cer的文件),自己進(jìn)行推送測(cè)試晦墙,這里是工具地址:https://itunes.apple.com/cn/app/easy-apns-provider/id989622350?mt=12
注意悦昵,推送只能進(jìn)行真機(jī)測(cè)試,模擬器是沒(méi)有token的晌畅。 我們需要添加要推送設(shè)備的token但指,然后選擇證書(shū),如果是正式就選連接至sandbox那個(gè)選項(xiàng)抗楔。然后就可以開(kāi)始推送了
? ? 2.推送的環(huán)境說(shuō)明
? ? 不論是這個(gè)小工具還是服務(wù)器推送棋凳,如果APP是生產(chǎn)環(huán)境(Appstore下載的或Adhoc環(huán)境),則選擇正式證書(shū)谓谦。我們自己開(kāi)發(fā)安裝的則選擇測(cè)試證書(shū)。所以我們是沒(méi)辦法用生產(chǎn)證書(shū)進(jìn)行上線(xiàn)前測(cè)試的(Adhoc除外)