推送-遠(yuǎn)程通知推送教程

前言

本文是一篇轉(zhuǎn)載文章懂傀,在這一篇實(shí)用的文章里,你可以按照上面的步驟實(shí)現(xiàn)不借助第三方和服務(wù)器端痹届,自己給自己的設(shè)備發(fā)推送通知。真的好棒打月,從中你可以領(lǐng)悟一些推送的核心用法队腐。


本文翻譯自:raywenderlich.com,原文作者:Jack Wu奏篙,譯者:JMStack

iOS開發(fā)者們喜歡想象他的用戶們會(huì)每時(shí)每刻使用他們所開發(fā)的APP柴淘,但是殘酷的事實(shí)是他們的用戶會(huì)有關(guān)閉APP來處理其它事情的時(shí)候。就像你洗好的衣服總要人去疊吧报破。
幸好,推送通知功能可以讓開發(fā)者與用戶建立連接并進(jìn)行簡(jiǎn)單的交互千绪,即使用戶當(dāng)前并沒有使用APP充易!
從推送通知功能第一次問世到現(xiàn)在已經(jīng)變得越來越強(qiáng)大。在iOS 9上荸型,遠(yuǎn)程推送可以做到:

  • 顯示短文本

  • 播放通知提示音

  • 設(shè)置APP圖標(biāo)的角標(biāo)

  • 在不打開APP的情況下,允許用戶與APP交互

  • 允許APP在后臺(tái)靜默喚醒來執(zhí)行任務(wù)

這份遠(yuǎn)程推送通知教程會(huì)告訴你遠(yuǎn)程推送的工作原理的并讓你了解它的一些特性盹靴。
在開始推送測(cè)試之前你需要具備以下條件:

  • 一臺(tái)iOS設(shè)備。遠(yuǎn)程推送不能在摸擬器上運(yùn)行,所以你需要一臺(tái)真機(jī)。

  • 一個(gè)開發(fā)者帳號(hào)稿静。從Xcode7開始梭冠,在真機(jī)上測(cè)試APP不再需要加入開發(fā)者計(jì)劃。但是為了配置遠(yuǎn)程推送改备,你需要有一個(gè)與APP ID對(duì)應(yīng)的推送證書控漠,獲得這個(gè)證書你需要加開發(fā)者計(jì)劃。

開始

為了接收發(fā)送遠(yuǎn)程推送通知你必須完成以下3個(gè)主要的任務(wù):

1悬钳、App必須正確配置并注冊(cè)APNS(Apple Push Notification Service)盐捷,以便所有設(shè)置都完成時(shí)就能馬上接收到通知。

2默勾、服務(wù)端必須向APNS發(fā)送一條明確指向一個(gè)或多個(gè)設(shè)備的通知碉渡。

3、App必需接收服務(wù)端發(fā)送的通知母剥,App可以執(zhí)行通知包含的任務(wù)或者在application的代理(delegate)回調(diào)方法內(nèi)處理用戶交互行為滞诺。

任務(wù)1和任務(wù)3是這份推送通知教程主要關(guān)注的內(nèi)容,因?yàn)檫@兩個(gè)任務(wù)是iOS開發(fā)者的工作环疼。

任務(wù)2也會(huì)在這份教程中簡(jiǎn)略的提及习霹,并且多數(shù)情況僅僅是為了測(cè)試目的。發(fā)送一個(gè)遠(yuǎn)程通知是App服務(wù)端的工作秦爆,并且這部分內(nèi)部會(huì)因?yàn)锳pp的不同而不同序愚。大多數(shù)App都會(huì)使用第三方服務(wù)(比如Parse。com或者Google ColoudMessaging)推送通知等限,其它的App或使用定制化的解決方案或使用比較流行的框架(比如: Houston)爸吮。

正式開始之,下載已經(jīng)準(zhǔn)備好的WenderCast開始工程望门。WenderCast是一個(gè)讓用戶獲取raywenderlich.com播客節(jié)目和時(shí)實(shí)消息的應(yīng)用形娇。

在Xcode中打開WenderCast.xcodeproj簡(jiǎn)單瀏覽一下。編繹運(yùn)行即可查看當(dāng)前最新播客節(jié)目:


1463988997846298.jpg

這個(gè)App的存在的問題是當(dāng)有新的播客節(jié)目可以獲取時(shí)不能通知到用戶筹误。并且也不能顯示任何最新的消息桐早。接下來你將用遠(yuǎn)程推送功能修復(fù)這個(gè)問題!

為App配置遠(yuǎn)程推送功能

推送通知需要較高的安全性厨剪。這點(diǎn)是非常重要的,因?yàn)槟悴粫?huì)想讓其它人給你的用戶發(fā)送通知哄酝。這也就意味著要實(shí)現(xiàn)遠(yuǎn)程推送功能你必需跳過一些坑。

打開遠(yuǎn)程推送服務(wù)

第一步是更改App ID祷膳。在Xcode中進(jìn)入 App Settings -> General 把 Bundle Identifier 改為任意唯一的字符串陶衅。


1463989038763395.png

接下來你需要在你的開發(fā)者帳號(hào)下添加打開了推送通知功能的App ID。幸運(yùn)的是直晨,Xcode有更簡(jiǎn)單的方法實(shí)現(xiàn)這個(gè)步驟搀军。進(jìn)入 App Settings -> Capabilities 把Push Notifications設(shè)置為 On膨俐。
在Xcode完成一些下載后,看起應(yīng)該會(huì)是下面的樣子


1463989064930009.png

這個(gè)步驟背后的操作是罩句,如果你當(dāng)前的開發(fā)者帳號(hào)下沒有對(duì)應(yīng)的App ID就會(huì)主動(dòng)創(chuàng)建App ID焚刺,并且打開推送通知功能。你可以登陸開發(fā)者中心確認(rèn)是否打開了這個(gè)功能:


1463989123284236.jpg

如果這個(gè)過程中出現(xiàn)問題,可以手動(dòng)創(chuàng)建App ID或者點(diǎn)擊開發(fā)者中心 + 或 Edit 按鈕開啟推送通知功能门烂。
以上就是你目前需要的配置乳愉。

注冊(cè)遠(yuǎn)程推送

注冊(cè)遠(yuǎn)程推送需要兩步。第一步诅福,你必需向用戶請(qǐng)求推送通知許可匾委,獲得許可之后才能注冊(cè)遠(yuǎn)程推送。如果所有步驟進(jìn)行順利氓润,系統(tǒng)將會(huì)向你提供一個(gè) device token赂乐,你可以把它認(rèn)為是當(dāng)前設(shè)備的”地址”。
在WenderCast應(yīng)用中你需要用在應(yīng)用啟動(dòng)后立即注冊(cè)遠(yuǎn)程推送咖气。
打開AppDelegate.swift挨措,添加以下代碼到AppDelegate末尾。

 此處崩溪,我換成OC版本浅役,原文是Swift代碼
 UIUserNotificationSettings *set =[UIUserNotificationSettings settingsForTypes:(UIUserNotificationTypeAlert|UIUserNotificationTypeBadge|UIUserNotificationTypeSound) categories:nil];
[[UIApplication sharedApplication]registerUserNotificationSettings:set];
[[UIApplication sharedApplication]registerForRemoteNotifications];

這個(gè)方法創(chuàng)建了一個(gè) UIUserNotificationSettings 實(shí)例對(duì)象并把它作為參數(shù)傳給 registerUserNotificationSettings(_:) 。UIUserNotificationSettings 存儲(chǔ)你的應(yīng)用將到用到的通知類型設(shè)置伶唯。

對(duì)于UIUserNotificationType的值你可以用下面幾個(gè)枚舉值的任意組合觉既。

  • .Badge 允許App在圖標(biāo)上顯示角標(biāo)數(shù)字

  • .Sound 允許App播放聲音

  • .Alert 允許App顯示文本

UIUserNotificationCategory 是Set類型參數(shù)當(dāng)前暫時(shí)傳 nil,以允許你指定你的App能夠處理的不同類型的通知。當(dāng)你需要實(shí)現(xiàn)可交互的通知時(shí)乳幸,這樣的設(shè)置是必需的瞪讼。后面的部分你將會(huì)用到可交互通知。

在 application(:didFinishLaunchingWithOptions:launchOptions:): 方法內(nèi)的第一行調(diào)用 registerForPushNotifications(:) :

func application(application: UIApplication,didFinishLaunchingWithOptions launchOptions:[NSObject: AnyObject]?) -> Bool {
    registerForPushNotifications(application)
    //...
}

編繹運(yùn)行粹断,當(dāng)App啟動(dòng)時(shí)你會(huì)收到一個(gè)彈窗請(qǐng)求通知許可:

1463989267324436.jpg

點(diǎn)擊 OK符欠,現(xiàn)在App可以顯示通知了。但是瓶埋,如果用戶拒絕了發(fā)送通知的請(qǐng)求該應(yīng)怎么辦希柿?

當(dāng)用戶接受或拒絕請(qǐng)求許可又或者之前做出過是否允許的選擇, UIApplicationDelegate 的一個(gè)代理方法將會(huì)被調(diào)用. 添加以下代碼到 AppDelegate:

func application(application: UIApplication,didRegisterUserNotificationSettings notificationSettings: UIUserNotificationSettings) {

}

在這個(gè)方法中养筒,你會(huì)接收到另一個(gè) UIUserNotificationSettings 實(shí)現(xiàn)對(duì)象曾撤。這個(gè)實(shí)例對(duì)象與之前你之前所傳入的不同。你之前傳入的是你所希望的設(shè)置晕粪,而當(dāng)前這個(gè)是用戶當(dāng)前授權(quán)的設(shè)置挤悉。

在App每次啟動(dòng)時(shí)都調(diào)用 registerUserNotificationSettings(:) 是相當(dāng)重要的。因?yàn)橛脩粼谌魏螘r(shí)候都有可能在設(shè)置應(yīng)用內(nèi)改變通知的授權(quán)許可兵多。 application(:didRegisterUserNotificationSettings:) 方法會(huì)告訴你用戶當(dāng)前給你的App什么樣的授權(quán)許可尖啡。

現(xiàn)在第一步已經(jīng)完成,你可以注冊(cè)遠(yuǎn)程推送通知了。這一步相當(dāng)簡(jiǎn)單剩膘,因?yàn)槟悴辉傩枰蛴脩粽?qǐng)求什么許可了衅斩。用下面的代碼更新 application(_:didRegisterUserNotificationSettings:) 方法:

func application(application: UIApplication,didRegisterUserNotificationSettings notificationSettings: UIUserNotificationSettings) {
  if   notificationSettings.types != .None {
          application.registerForRemoteNotifications()
  }
}

在上面的方法中,首先檢查當(dāng)前用戶是否允許通知怠褐,如果允許直接調(diào)用registerForRemoteNotifications()畏梆。

其次,registerForRemoteNotifications()的請(qǐng)求注冊(cè)的返回狀態(tài)會(huì)通過 UIApplicationDelegate協(xié)議中的某些方法通知你奈懒。

添加以下代碼到 AppDelegate :


1463994202124520.png

就像方法名所暗示的那樣,當(dāng)注冊(cè)通知成功后系統(tǒng)會(huì)調(diào)用 application(:didRegisterForRemoteNotificationsWithDeviceToken:) 方法奠涌,否則將會(huì)調(diào)用 application(:didFailToRegisterForRemoteNotificationsWithError:)方法。

當(dāng)前 application(_:didRegisterForRemoteNotificationsWithDeviceToken:) 方法的實(shí)現(xiàn)看起來難以理解,其實(shí)它僅僅只是獲取 deviceToken 然后轉(zhuǎn)換成字符串磷杏。deviceToken的值就是這個(gè)過程得到的結(jié)果溜畅。它是由APNs服務(wù)器提供用來標(biāo)識(shí)當(dāng)前設(shè)備當(dāng)前App。當(dāng)發(fā)送時(shí)推送通知的時(shí)候极祸,App用deviceToken作為“地址”傳遞到當(dāng)前設(shè)備慈格。

# 打印出 deviceToken
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken;
{
    NSString *deviceTokenString2 = [[[[deviceToken description] stringByReplacingOccurrencesOfString:@"<"withString:@""]
                                     stringByReplacingOccurrencesOfString:@">" withString:@""]
                                    stringByReplacingOccurrencesOfString:@" " withString:@""];
    NSLog(@"方式2:%@", deviceTokenString2);
}

注意:會(huì)有很多原因?qū)е伦?cè)失敗。最常碰到原因是程序運(yùn)行在模擬器上遥金,或者App ID設(shè)置不正確浴捆。具體原因打印error值會(huì)提供更加詳細(xì)的信息。

- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error ;
{
     NSLog(@"%@",error);
}

到此,編繹運(yùn)行稿械。確保你當(dāng)前運(yùn)行在真機(jī)上选泻,你將會(huì)在控制臺(tái)看到打印出的device token。下面將會(huì)是你看到的結(jié)果:


1463989410955146.png

把device token復(fù)制到某處保存美莫。

在正式發(fā)送通知之前你還需要一點(diǎn)點(diǎn)配置,所以回到開發(fā)者中心页眯。

創(chuàng)建一個(gè)SSL證書和PEM文件

在開發(fā)者中心進(jìn)入 Certificates, Identifiers & Profiles -> Identifiers -> App IDs 找到你應(yīng)用的App ID.在 Application Services 下面 Push Notifications 應(yīng)該為 Configurable :

1463989437850933.png

點(diǎn)擊 Edit 滾動(dòng)到 Push Notifications:


1463989449361471.png

在 Development SSL Certificate 欄下,點(diǎn)擊 Create Certificate… 接下來的步驟就是創(chuàng)建 CSR 文件茂嗓。創(chuàng)建好CSR文件后點(diǎn)擊 continue 和 Generate餐茵,這步會(huì)用你創(chuàng)建的CSR文件生成證書。最后下載并運(yùn)行生成好的證書述吸,證書將被添加到你的鑰匙串應(yīng)用中忿族,并與私鑰成對(duì)。


1463989539559130.png

在開發(fā)者中心,你的App ID現(xiàn)在推送通知功能在development下應(yīng)該處于Enable狀態(tài)蝌矛。


1463989559290885.png

在關(guān)閉鑰匙串應(yīng)用前還有最后一件事道批,右擊你剛才添加的證書,選擇 Export :


1463989597273139.png

保存在桌面并命名為WenderCastPush.p12入撒。


1463989632581691.png

你會(huì)被提示要求為你的.p12文件設(shè)置密碼隆豹,你可以選擇不輸或者輸入一個(gè)你想設(shè)置的密碼。這里我用”WenderCastPush”作為密碼茅逮。接下來你需要輸入電腦登陸密碼來允許導(dǎo)出p12文件璃赡。

接下來,打開你的終端并執(zhí)行以下命令來從p12文件生成PEM文件:

$ cd ~/Desktop
$ openssl pkcs12 -in WenderCastPush.p12 -out WenderCastPush.pem -nodes -clcerts

如果你導(dǎo)出p12文件時(shí)輸入了密碼,在這里你必須輸入相同的密碼判哥。

到此為止,你已經(jīng)艱難的躍過了很多坑,這一切都是值得的碉考。接下來你將用你生成的WenderCastPush.pem文件發(fā)送第一個(gè)通知塌计。

發(fā)送通知

之前下載的開始工程會(huì)包含一個(gè)WenderCastPush文件;里面包含兩個(gè)用于發(fā)送通知簡(jiǎn)單腳本。你需要用到的是newspush.php侯谁。正如文件名所暗示的锌仅,這個(gè)腳本將會(huì)向你的用戶發(fā)送一個(gè)彈窗通知消息。

發(fā)送推送通知需要和APNS建立SSL連接墙贱,SSL連接是用之前創(chuàng)建的證書進(jìn)行加密热芹。這就是為什么要生成 WenderCastPush.pem 文件。重命名 WenderCastPush.pem 為 ck.pem惨撇,并且替換掉當(dāng)前已經(jīng)存在于 WenderCastPush 文件夾下的 ck.pem 文件伊脓。

打開 newspush.php 并更新之前接收到的 $deviceToken 和導(dǎo)出文件時(shí)輸入的密碼 $passphrase

// Put your device token here (without spaces):

$deviceToken = '43e798c31a282d129a34d84472bbdd7632562ff0732b58a85a27c5d9fdf59b69'

// Put your private key's passphrase here:
$passphrase = 'WenderCastPush'

打開終端,cd 到 newspush.php 所在的文件夾魁衙,輸入:

php newspush.php 'Breaking News' 'https://raywenderlich.com'

如果進(jìn)行順利丽旅,你的終端將會(huì)顯示:

Connected to APNS
Message successfully delivered

現(xiàn)在,你應(yīng)該會(huì)收到你的第一條通知:


1463989700574992.jpg

注意:如果你的App被打開并處于前臺(tái)運(yùn)行狀態(tài),你將看不到任何東西纺棺。通知已經(jīng)被投送但是App還不會(huì)處理這個(gè)通知榄笙。你只需要簡(jiǎn)單的關(guān)閉App并重新發(fā)送通知即可。

常見問題
也許你會(huì)遇到以下問題:

  • 只能接收到部分通知:如果你同時(shí)發(fā)送多個(gè)通知祷蝌,只有部分通知將會(huì)被接收茅撞,不用擔(dān)心!這正是我們想要的結(jié)果巨朦。當(dāng)發(fā)送通知時(shí)APNS會(huì)為每一個(gè)開啟了推送通知的設(shè)備保持一個(gè)高質(zhì)量服務(wù)(Quality of Service)隊(duì)列米丘。這個(gè)隊(duì)列的大小是1,所以如果你同時(shí)發(fā)送多個(gè)通知糊啡,最后一個(gè)通知才會(huì)被發(fā)送拄查。

  • 連接到APNS出現(xiàn)問題:出現(xiàn)這個(gè)問題的原因可能是你的防火墻阻塞了APNS所使用的端口。所以確保你的防火墻沒有阻塞住這些端口棚蓄。另一個(gè)可能的原因是私鑰和CSR文件不正確堕扶。記住,每一個(gè)App ID有一個(gè)唯一的CSR和配對(duì)的私鑰梭依。

解剖推送通知的基本原理

在進(jìn)行任務(wù)3之前稍算,需要理解一下你推送的通知,打開 newspush役拴。php 文件理解發(fā)送一個(gè)通知的基本概念應(yīng)該是怎么樣的糊探。
注意第32-40行,這就是用JSON格式編碼的裝載體。這就是實(shí)際上發(fā)送給APNS的東西科平。在我們當(dāng)前的例子中褥紫,裝載體像下面一樣:

Paste_Image.png

對(duì)于一個(gè)不懂JSON數(shù)據(jù)的人來說,用{}括起來的塊相當(dāng)于一個(gè)字典類型的數(shù)據(jù)瞪慧。

這個(gè)裝載體是一個(gè)至少包含一項(xiàng)內(nèi)容的字典,這項(xiàng)內(nèi)容就是 aps, 它本身也是一個(gè)字典故源。在這個(gè)例子中”aps”包含”alert”,”sound”和”link_url”等字段。當(dāng)接收到一個(gè)通知,就會(huì)顯示一個(gè)包含”Breaking News!”文本的提醒視圖,并且有標(biāo)準(zhǔn)的提醒音效汞贸。

“l(fā)ink_url”實(shí)際上是一個(gè)自定義的字段。你可以添加類似的自定義字段到裝載體中,并且它會(huì)被投送到你的應(yīng)用印机。因?yàn)槟悴]有在應(yīng)用中處理這個(gè)字段,所以當(dāng)前接收到這個(gè)鍵值對(duì)會(huì)什么都不做矢腻。

你可以在aps字典中添加以下5個(gè)鍵(key):

  • alert。這個(gè)字段可以是一個(gè)字符串射赛,就像當(dāng)前的例子多柑。或是是一個(gè)字典楣责。如果是一個(gè)字典,可以是本地化的文本或者通知的其它部分竣灌。查看蘋果文檔所支持的key。

  • badge秆麸。這是一個(gè)將被顯示在應(yīng)用圖標(biāo)上的數(shù)字初嘹。你可以設(shè)置這個(gè)鍵為0來清除角標(biāo)。

  • sound沮趣。通過設(shè)置這個(gè)建屯烦,你可以播放存放在App本地定制的通知提示音來取代系統(tǒng)默認(rèn)的通知提示音。定制的通知提示音必須在30秒以內(nèi)并且還有一些其它的限制房铭,你可以查看蘋果文檔了解更詳細(xì)信息驻龟。

  • content-available。設(shè)置這個(gè)鍵為1缸匪,當(dāng)前通知會(huì)變成靜默通知翁狐。這個(gè)部分會(huì)在這份教程的后面部分探索。

  • category凌蔬。這個(gè)鍵定義了通知的分類露懒,用于顯示定制通知所包含的交互行為。同樣,接下來會(huì)探索這部分的內(nèi)容砂心。

除此之外隐锭,你可以添加任意你想要添加的定制化數(shù)據(jù),只要裝載體不超過4096個(gè)字節(jié)。

如果你玩夠了推送通知计贰,接下來我們進(jìn)入到下一個(gè)章節(jié)钦睡。

處理接收到的通知

在這個(gè)章節(jié),你將會(huì)學(xué)習(xí)當(dāng)App接收到通知后或者用戶點(diǎn)擊了通知應(yīng)該如何執(zhí)行什么樣的操作躁倒。

當(dāng)你接收到一個(gè)通知后會(huì)發(fā)生什么

當(dāng)你的App接收到一個(gè)通知荞怒,UIApplicationDelegate 的一個(gè)方法將會(huì)被調(diào)用洒琢。

需要根據(jù)接到收通知時(shí)App所處的狀態(tài)的進(jìn)行不同的處理。

  • 如果你的應(yīng)用當(dāng)前不在運(yùn)行,并且用戶通過點(diǎn)擊推送通知啟動(dòng)應(yīng)用,通知內(nèi)容會(huì)通過 application(_:didFinishLaunchingWithOptions:) 方法的 launchOptions 參數(shù)進(jìn)行傳遞褐桌。

  • 如果你應(yīng)用當(dāng)前正運(yùn)行在前臺(tái),推送通知將不會(huì)被顯示衰抑。但是 application(_:didReceiveRemoteNotification:) 會(huì)被立即調(diào)用。

  • 如果你的應(yīng)用正在運(yùn)行荧嵌,或者被掛起在后臺(tái)呛踊,并且用戶通過點(diǎn)擊通知使應(yīng)用進(jìn)入前臺(tái) application(_:didReceiveRemoteNotification:) 方法會(huì)被調(diào)用。

在第一種情況下啦撮,WenderCast將到創(chuàng)建一個(gè)新的section,并直接打開以顯示到這個(gè)新建section谭网。添加以下代碼到 application(_:didFinishLaunchingWithOptions:) 的末尾return語(yǔ)句之前。

// Check if launched from notification

// 1

if  let notification = launchOptions?[UIApplicationLaunchOptionsRemoteNotificationKey] as? [String: AnyObject] {

// 2 
let aps = notification[  "aps"  ] as! [String: AnyObject]
createNewNewsItem(aps)

// 3
(window?.rootViewController as? UITabBarController)?.selectedIndex = 1
}

這段代碼做了以下3件事:

檢查 UIApplicationLaunchOptionsRemoteNotificationKey 鍵對(duì)應(yīng)的值是否存在赃春,如果存在愉择,這個(gè)值應(yīng)該就是你發(fā)送的通知裝載體。

如果存在织中,獲取 aps 對(duì)應(yīng)字典并傳給 createNewNewsItem(_:) 方法锥涕,這個(gè)方法根據(jù)接收的字典創(chuàng)建一個(gè) NewItem,并刷新表格狭吼。

改變tab控制器當(dāng)前選中的tab索引值為1层坠,也就是直接顯示新聞控制器視圖。

為了測(cè)試這部分代碼刁笙,你需要編輯WenderCast的scheme:


1463990007399456.png

在 Run -> Info 下選擇 Wait for executable to be launched:


1463990002675410.png

這個(gè)選項(xiàng)會(huì)使調(diào)試器等待應(yīng)用程序安裝直到應(yīng)用程序第一次被啟動(dòng)舵鳞。
編繹運(yùn)行,完成安裝后歹嘹,發(fā)送一些新的動(dòng)態(tài)。點(diǎn)擊通知以啟動(dòng)App,啟動(dòng)之后App會(huì)顯示一些新消息逛揩。
1463990027360933.jpg

注意 如果你突然接收不到通知焚挠,最有可能的原因是device token被改了制肮。如果你刪除應(yīng)用再重新安裝就有可能出現(xiàn)這種情況讽挟。確保你的device token是正確的。

為了處理另外兩種情況烦租,添加以下代碼到 AppDelegate:

func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject]) {

let aps = userInfo["aps"] as! [String: AnyObject]
createNewNewsItem(aps)
}

這個(gè)方法直接創(chuàng)建了一個(gè)新的 NewsItem⊙佣模現(xiàn)在你可以把scheme設(shè)置回自動(dòng)啟動(dòng)App。
編繹運(yùn)行叉橱。保持App運(yùn)行在前臺(tái)挫以,并選中新聞頁(yè)。發(fā)送一個(gè)通知,你可以看到消息奇跡般的顯示在視線內(nèi)窃祝。

1463990072111969.jpg

就是這樣掐松!你的App現(xiàn)在可以處理基本的推送消息。

一些需要注意的事情:很多情況推送通知可能會(huì)被遺漏。對(duì)于WenderCast應(yīng)用來說是沒有問題的大磺,因?yàn)檠b滿消自己的列表對(duì)這個(gè)應(yīng)用來說并不是那么重要抡句,但是一般來講你不應(yīng)該把推送通知做為傳遞內(nèi)容的唯一方式。作為備選項(xiàng)杠愧,推送通知應(yīng)該僅僅只是指示當(dāng)前有新的內(nèi)容可以獲取并讓App從服務(wù)器下載這些新的內(nèi)容待榔。WenderCast應(yīng)用在這方有一些局限性,因?yàn)樗]有合適的服務(wù)端流济。

可交互的通知

可交互的通知允許你添加定制化的按鈕在通知上锐锣。你也許注意到郵件通知或者Twitter消息通知有一個(gè)讓你回復(fù)或者點(diǎn)贊的部位。

可交互的通知是你通過注冊(cè)通知時(shí)設(shè)置 categories 定義的.每一個(gè)通知分類都可以有多個(gè)預(yù)先自定義的交互绳瘟。

一旦完成注冊(cè)雕憔,就可以發(fā)送這個(gè)分類的通知.當(dāng)接收到通知相應(yīng)的交互就可以被用戶獲取。

對(duì)于 WenderCast 應(yīng)用稽荧,你將定義一個(gè)自定義”View”動(dòng)作的”News”分類,自定義”View”允許用戶選擇查看工腋,如果用戶選擇就會(huì)在App中直接顯示對(duì)應(yīng)的消息詳細(xì)文章姨丈。

添加以下代碼到 registerForPushNotifications(_:): 的開頭。

let viewAction = UIMutableUserNotificationAction()

viewAction.identifier = "VIEW_IDENTIFIER"
viewAction.title = "View"
viewAction.activationMode = .Foreground

這段代碼創(chuàng)建了一個(gè)按鈕標(biāo)題名為”View”的新交互通知,當(dāng)交互通知被用戶觸發(fā)時(shí)打開App并讓其進(jìn)入前臺(tái).這個(gè)交互動(dòng)作的標(biāo)識(shí)符是 VIEW_IDENTIFIER ,這個(gè)標(biāo)識(shí)符被用于區(qū)分同一通知的不同交互動(dòng)作.
添加以下人碼片段至前面代碼之后:

let newsCategory = UIMutableUserNotificationCategory()
newsCategory.identifier = "NEWS_CATEGORY"
newsCategory.setActions([viewAction], forContext: .Default)

這段代碼定義了一個(gè)新通知分類,設(shè)置交互動(dòng)作為之前定義的”View”動(dòng)作,設(shè)置標(biāo)識(shí)符為” NEWS_CATEGORY”,這個(gè)標(biāo)識(shí)符你是裝載體要包含的內(nèi)容以用其指示當(dāng)前通知屬于哪個(gè)分類.

最后,通過以下代碼,把新建分類傳遞給UIUserNotificationSettings構(gòu)造方法擅腰。

let notificationSettings = UIUserNotificationSettings(forTypes: [.Badge, .Sound, .Alert], categories: [newsCategory])

編繹運(yùn)行,應(yīng)用會(huì)注冊(cè)新通知設(shè)定蟋恬。按Home鍵來退出當(dāng)前應(yīng)用,以使推送通知能夠顯示趁冈。

在你再次運(yùn)行 newspush.php 之前歼争,首先對(duì)指定的分類做一個(gè)改動(dòng)。打開 newspush.php 修改通知裝載體使它包含通知的分類標(biāo)識(shí)符:

$body['aps'] = array(
  'alert'  => $message,
  'sound' => 'default', 
  'link_url' => $url,
  'category' => NEWS_CATEGORY', 
);

保存并關(guān)閉newspush.php渗勘,然后運(yùn)行以發(fā)送通知沐绒。如果一切進(jìn)展順利,你可以下拉并輕掃顯示的通知你會(huì)看到View按鈕被顯示旺坠。

1463990140648178.jpg

非常好乔遮,點(diǎn)擊”View”按鈕將啟動(dòng)WenderCast但不會(huì)做任何事情。為了獲取通知裝載體顯示新的內(nèi)容項(xiàng)取刃,你需要在代理方法中做更多的操作蹋肮。

處理通知交互動(dòng)作事件

回到 AppDelegate.swift,添加另一個(gè)方法:

  func application(application: UIApplication, handleActionWithIdentifier identifier: String?, forRemoteNotification userInfo: [NSObject : AnyObject], completionHandler: () -> Void) {

// 1 
let aps = userInfo["aps"] as! [String: AnyObject]

// 2
if  let newsItem = createNewNewsItem(aps) {

(window?.rootViewController as? UITabBarController)?.selectedIndex = 1

// 3   
if   identifier == "VIEW_IDENTIFIER",
 let url = NSURL(string: newsItem.link) {
let safari = SFSafariViewController(URL: url)

window?.rootViewController?.presentViewController(safari, animated: true, completion: nil)    

}
}

// 4
completionHandler()
}

當(dāng)用戶通過通知的交互動(dòng)作打開應(yīng)用時(shí)這個(gè)方法將會(huì)被調(diào)用.這看來起好像做了很多事,但是實(shí)際上沒有多少新的東西.這段代碼做了以下事情:

  • 獲取 aps 字典。
  • 根據(jù)獲取到的字典創(chuàng)建 NewItem 并跳到新聞頁(yè)璧疗。
  • 檢查以 identifier 為參數(shù)傳進(jìn)來的交互動(dòng)作的標(biāo)識(shí)符坯辩。如果View交互動(dòng)作的標(biāo)識(shí)符和鏈接有效則用。SFSafariViewController 顯示這個(gè)鏈接內(nèi)容崩侠。
  • 在處理完用戶交互動(dòng)用之后調(diào)用系統(tǒng)傳遞給你的 completionHandler 回調(diào)漆魔。
  • 編繹運(yùn)行,退出App。發(fā)送通知有送。但請(qǐng)確保下面的URL中有效的:
  $ php newspush.php  'New Posts!'   'https://raywenderlich.com'

點(diǎn)擊通知的交互動(dòng)作淌喻,在WenderCast應(yīng)用啟動(dòng)后會(huì)立即展示Safari控制器。

1463990244582650.jpg

恭喜雀摘,你剛剛已經(jīng)完成了可交互通知的實(shí)現(xiàn)裸删!嘗試多發(fā)送幾次通知,并用不同的方法打開通知觀察通知的展現(xiàn)行為阵赠。

靜默推送通知

靜默推送通知可以靜默方式的喚醒你的App并讓它在后臺(tái)執(zhí)行任務(wù)涯塔。WenderCast可以利用這個(gè)特性悄悄地刷新播客列表。

正如你所想象的清蚀,配合合適的服務(wù)端這個(gè)功能會(huì)非常有用匕荸。你不需要不斷的主動(dòng)獲取數(shù)據(jù),當(dāng)有數(shù)據(jù)可獲取時(shí)僅僅只需要發(fā)送一個(gè)靜默通知枷邪。

開始之前進(jìn)入 App Settings -> Capabilites 并打開 WenderCast的 Background Modes. 檢查最后一個(gè)選項(xiàng)榛搔,Remote Notifications 是否勾選。

1463990284465137.png

現(xiàn)在你的App接收到某個(gè)靜默通知就可以在后臺(tái)喚醒.

在AppDelegate內(nèi)东揣,用下面更強(qiáng)大的版本替換 application(_:didReceiveRemoteNotification:) 方法:

func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject], fetchCompletionHandler completionHandler: (UIBackgroundFetchResult) -> Void) {

let aps = userInfo["aps"] as! [String: AnyObject]

// 1
if (aps["content-available"] as? NSString)?.integerValue == 1 {

// Refresh Podcast

// 2  
let podcastStore = PodcastStore.sharedStore
podcastStore.refreshItems { didLoadNewItems  in

 // 3      
  completionHandler(didLoadNewItems ? .NewData : .NoData)
    } 
} 
else
{
    // News
    // 4
  createNewNewsItem(aps)
  completionHandler(.NewData)

    }
}

這段代碼:

  • 檢查 content-available 是否為1,以確定是否是靜默推送践惑。
  • 刷新播客列表,因?yàn)樾枰L問網(wǎng)絡(luò)所以刷新列表是異步的嘶卧。
  • 當(dāng)刷新完列表尔觉,調(diào)用 completionHandler 回調(diào)方法,讓系統(tǒng)知道數(shù)據(jù)是否已經(jīng)下載芥吟。
  • 如果不是靜默通知侦铜,假定它是消息并創(chuàng)建一個(gè)新的消息項(xiàng)。

必需要確保 completionHandler(_:) 方法被調(diào)用并傳遞真實(shí)的是否獲取到數(shù)據(jù)的結(jié)果钟鸵。系統(tǒng)會(huì)根據(jù)回調(diào)計(jì)算耗電量和App在后臺(tái)的時(shí)間,系統(tǒng)會(huì)根據(jù)需要調(diào)節(jié)App的耗電量以及在后臺(tái)的時(shí)間钉稍。

以上就是這段代碼所做的事。現(xiàn)在你可以用 contentpush.php 給你的應(yīng)用發(fā)送一個(gè)靜默通知棺耍。請(qǐng)務(wù)必確認(rèn)以下設(shè)置腳本的正確性:

// Put your device token here (without spaces):
  $deviceToken = '43e798c31a282d129a34d84472bbdd7632562ff0732b58a85a27c5d9fdf59b69'
;
// Put your private key's passphrase here:
$passphrase = 'WenderCastPush'  ;

在終端直接運(yùn)行:

$ php contentpush.php

如果一切順利嫁盲,什么事都不會(huì)發(fā)生。為了看到這段代碼的運(yùn)行結(jié)果,與之前設(shè)置的一樣結(jié)果必須把scheme設(shè)置為”Wait for executable to be launched”并在 application(_:didReceiveRemoteNotification:fetchCompletionHandler:) 方法旁邊打上斷點(diǎn),以確認(rèn)這個(gè)方法會(huì)被調(diào)用烈掠。

路在何方羞秤?

恭喜你已經(jīng)完成了這份推送通知教程的內(nèi)容并且WenderCast應(yīng)用也有全部的推送功能!

你可以在這里下載完整的工程左敌。記住為了能讓工程正常運(yùn)行你仍然需要更改Bundle ID和證書瘾蛋。

推送通知功能對(duì)于現(xiàn)在的App已經(jīng)是一個(gè)不可或缺的部分,但如果你發(fā)送的通知太頻繁用戶仍然會(huì)調(diào)整你的通知請(qǐng)求許可矫限。對(duì)于一個(gè)深思熟慮的設(shè)計(jì)哺哼,推送通知會(huì)讓你的應(yīng)用保持足夠的用戶粘性佩抹!

這只貓接收到“推送通知”后它就知道晚餐已經(jīng)準(zhǔn)備好了。

我希望你能喜歡這份推送教程取董。如果你有任何問題棍苹,你可以在下面的評(píng)論中隨意提問。


原文鏈接
iOS 10 之前的推送之遠(yuǎn)程推送(iOS Notification Of Remote Notification)這篇文章也不錯(cuò)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末茵汰,一起剝皮案震驚了整個(gè)濱河市枢里,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌蹂午,老刑警劉巖栏豺,帶你破解...
    沈念sama閱讀 206,311評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異豆胸,居然都是意外死亡奥洼,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門晚胡,熙熙樓的掌柜王于貴愁眉苦臉地迎上來灵奖,“玉大人,你說我怎么就攤上這事估盘〈苫迹” “怎么了?”我有些...
    開封第一講書人閱讀 152,671評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵忿檩,是天一觀的道長(zhǎng)尉尾。 經(jīng)常有香客問我爆阶,道長(zhǎng)燥透,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,252評(píng)論 1 279
  • 正文 為了忘掉前任辨图,我火速辦了婚禮班套,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘故河。我一直安慰自己吱韭,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,253評(píng)論 5 371
  • 文/花漫 我一把揭開白布鱼的。 她就那樣靜靜地躺著理盆,像睡著了一般。 火紅的嫁衣襯著肌膚如雪凑阶。 梳的紋絲不亂的頭發(fā)上猿规,一...
    開封第一講書人閱讀 49,031評(píng)論 1 285
  • 那天,我揣著相機(jī)與錄音宙橱,去河邊找鬼姨俩。 笑死蘸拔,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的环葵。 我是一名探鬼主播调窍,決...
    沈念sama閱讀 38,340評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼张遭!你這毒婦竟也來了邓萨?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,973評(píng)論 0 259
  • 序言:老撾萬榮一對(duì)情侶失蹤帝璧,失蹤者是張志新(化名)和其女友劉穎先誉,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體的烁,經(jīng)...
    沈念sama閱讀 43,466評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡褐耳,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,937評(píng)論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了渴庆。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片铃芦。...
    茶點(diǎn)故事閱讀 38,039評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖襟雷,靈堂內(nèi)的尸體忽然破棺而出刃滓,到底是詐尸還是另有隱情,我是刑警寧澤耸弄,帶...
    沈念sama閱讀 33,701評(píng)論 4 323
  • 正文 年R本政府宣布咧虎,位于F島的核電站,受9級(jí)特大地震影響计呈,放射性物質(zhì)發(fā)生泄漏砰诵。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,254評(píng)論 3 307
  • 文/蒙蒙 一捌显、第九天 我趴在偏房一處隱蔽的房頂上張望茁彭。 院中可真熱鬧,春花似錦扶歪、人聲如沸理肺。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,259評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)妹萨。三九已至,卻和暖如春炫欺,著一層夾襖步出監(jiān)牢的瞬間乎完,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評(píng)論 1 262
  • 我被黑心中介騙來泰國(guó)打工竣稽, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留囱怕,地道東北人霍弹。 一個(gè)月前我還...
    沈念sama閱讀 45,497評(píng)論 2 354
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像娃弓,于是被迫代替她去往敵國(guó)和親典格。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,786評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容

  • 版權(quán)聲明 本文翻譯自:raywenderlich.com 原文作者: Jack Wu 譯者: JMStack 轉(zhuǎn)載...
    jmstack閱讀 6,960評(píng)論 6 30
  • 極光推送: 1.JPush當(dāng)前版本是1.8.2台丛,其SDK的開發(fā)除了正常的功能完善和擴(kuò)展外也緊隨蘋果官方的步伐耍缴,SD...
    Isspace閱讀 6,696評(píng)論 10 16
  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 171,506評(píng)論 25 707
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn)挽霉,斷路器防嗡,智...
    卡卡羅2017閱讀 134,599評(píng)論 18 139
  • Day26 170703 教皇
    蝸?zhàn)?/span>閱讀 110評(píng)論 0 0