版權(quán)聲明 本文翻譯自:raywenderlich.com 原文作者: Jack Wu 譯者: JMStack 轉(zhuǎn)載請說明原文及譯文出處.
iOS開發(fā)者們喜歡想象他的用戶們會每時每刻使用他們所開發(fā)的APP,但是殘酷的事實是他們的用戶會有關(guān)閉APP來處理其它事情的時候.就像你洗好的衣服總要人去疊吧.
幸好,推送通知功能可以讓開發(fā)者與用戶建立連接并進(jìn)行簡單的交互即使用戶當(dāng)前并沒有使用APP!
從推送通知功能第一次問世到現(xiàn)在已經(jīng)變得越來越強(qiáng)大.在iOS9上,遠(yuǎn)程推送可以做到:
- 顯示短文本
- 播放通知提示音
- 設(shè)置APP圖標(biāo)的角標(biāo)
- 在不打開APP的情況下,允許用戶與APP交互
- 允許APP在后臺靜默喚醒來執(zhí)行任務(wù)
這份遠(yuǎn)程推送通知教程會告訴你遠(yuǎn)程推送的工作原理的并讓你了解它的一些特性.
在開始推送測試之前你需要具備以下條件:
- 一臺iOS設(shè)備.遠(yuǎn)程推送不能在摸擬器上運(yùn)行,所以你需要一臺真機(jī).
- 一個開發(fā)者帳號 從Xcode7開始,在真機(jī)上測試APP不再需要加入開發(fā)者計劃.但是為了配置遠(yuǎn)程推送,你需要有一個與APP ID對應(yīng)的推送證書,獲得這個證書你需要加開發(fā)者計劃.
開始
為了接收發(fā)送遠(yuǎn)程推送通知你必須完成以下3個主要的任務(wù):
- app必須正確配置并注冊APNS(Apple Push Notification Service),以便所有設(shè)置都完成時就能馬上接收到通知
- 服務(wù)端必須向APNS發(fā)送一條明確指向一個或多個設(shè)備的通知
- app必需接收服務(wù)端發(fā)送的通知;app可以執(zhí)行通知包含的任務(wù)或者在application的代理(delegate)回調(diào)方法內(nèi)處理用戶交互行為.
任務(wù)1和任務(wù)3是這份推送通知教程主要關(guān)注的內(nèi)容,因為這兩個任務(wù)是iOS開發(fā)者的工作.
任務(wù)2也會在這份教程中簡略的提及,并且多數(shù)情況僅僅是為了測試目的.發(fā)送一個遠(yuǎn)程通知是app服務(wù)端的工作,并且這部分內(nèi)部會因為App的不同而不同.大多數(shù)app都會使用第三方服務(wù)(比如Parse.com或者Google ColoudMessaging)推送通知,其它的app或使用定制化的解決方案或使用比較流行的框架(比如: Houston).
正式開始之,下載已經(jīng)準(zhǔn)備好的 WenderCast 開始工程.WenderCast是一個讓用戶獲取raywenderlich.com播客節(jié)目和時實消息的應(yīng)用.
在Xcode中打開WenderCast.xcodeproj簡單瀏覽一下.編繹運(yùn)行即可查看當(dāng)前最新播客節(jié)目:
這個app的存在的問題是當(dāng)有新的播客節(jié)目可以獲取時不能通知到用戶.并且也不能顯示任何最新的消息.接下來你將用遠(yuǎn)程推送功能修復(fù)這個問題!
為App配置遠(yuǎn)程推送功能
推送通知需要較高的安全性.這點是非常重要的,因為你不會想讓其它人給你的用戶發(fā)送通知.這也就意味著要實現(xiàn)遠(yuǎn)程推送功能你必需跳過一些坑.
打開遠(yuǎn)程推送服務(wù)
第一步是更改App ID.在Xcode中進(jìn)入 App Settings -> General 把 Bundle Identifier 改為任意唯一的字符串.
接下來你需要在你的開發(fā)者帳號下添加打開了推送通知功能的App ID.幸運(yùn)的是,Xcode有更簡單的方法實現(xiàn)這個步驟.進(jìn)入 App Settings -> Capabilities 把Push Notifications設(shè)置為 On.
在Xcode完成一些下載后,看起應(yīng)該會是下面的樣子
這個步驟背后的操作是: 如果你當(dāng)前的開發(fā)者帳號下沒有對應(yīng)的App ID就會主動創(chuàng)建App ID,并且打開推送通知功能.你可以登陸開發(fā)者中心確認(rèn)是否打開了這個功能:
如果這個過程中出現(xiàn)問題,可以手動創(chuàng)建App ID或者點擊開發(fā)者中心 + 或 Edit 按鈕開啟推送通知功能.
以上就是你目前需要的配置.
注冊遠(yuǎn)程推送
注冊遠(yuǎn)程推送需要兩步.第一步,你必需向用戶請求推送通知許可,獲得許可之后才能注冊遠(yuǎn)程推送.如果所有步驟進(jìn)行順利,系統(tǒng)將會向你提供一個 device token ,你可以把它認(rèn)為是當(dāng)前設(shè)備的"地址".
在WenderCast應(yīng)用中你需要用在應(yīng)用啟動后立即注冊遠(yuǎn)程推送.
打開AppDelegate.swift,添加以下代碼到AppDelegate末尾.
func registerForPushNotifications(application: UIApplication) {
let notificationSettings = UIUserNotificationSettings(
forTypes: [.Badge, .Sound, .Alert], categories: nil)
application.registerUserNotificationSettings(notificationSettings)
}
這個方法創(chuàng)建了一個 UIUserNotificationSettings 實例對象并把它作為參數(shù)傳給 registerUserNotificationSettings(_:) .
UIUserNotificationSettings 存儲你的應(yīng)用將到用到的通知類型設(shè)置.對于UIUserNotificationType的值你可以用下面幾個枚舉值的任意組合.
- .Badge 允許App在圖標(biāo)上顯示角標(biāo)數(shù)字
- .Sound 允許App播放聲音
- .Alert 允許App顯示文本
UIUserNotificationCategory 是Set類型參數(shù)當(dāng)前暫時傳 nil,以允許你指定你的app能夠處理的不同類型的通知.當(dāng)你需要實現(xiàn)可交互的通知時,這樣的設(shè)置是必需的.后面的部分你將會用到可交互通知.
在 application(_:didFinishLaunchingWithOptions:launchOptions:): 方法內(nèi)的第一行調(diào)用 registerForPushNotifications(_:) :
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
registerForPushNotifications(application)
//...
}
編繹運(yùn)行.當(dāng)App啟動時你會收到一個彈窗請求通知許可:
點擊 OK ,現(xiàn)在App可以顯示通知了.但是,如果用戶拒絕了發(fā)送通知的請求該應(yīng)怎么辦?
當(dāng)用戶接受或拒絕請求許可又或者之前做出過是否允許的選擇, UIApplicationDelegate 的一個代理方法將會被調(diào)用. 添加以下代碼到 AppDelegate :
func application(application: UIApplication, didRegisterUserNotificationSettings notificationSettings: UIUserNotificationSettings) {
}
在這個方法中,你會接收到另一個 UIUserNotificationSettings 實現(xiàn)對象.這個實例對象與之前你之前所傳入的不同.你之前傳入的是你所希望的設(shè)置,而當(dāng)前這個是用戶當(dāng)前授權(quán)的設(shè)置.
在App每次啟動時都調(diào)用 registerUserNotificationSettings(_:) 是相當(dāng)重要的.因為用戶在任何時候都有可能在設(shè)置應(yīng)用內(nèi)改變通知的授權(quán)許可. application(_:didRegisterUserNotificationSettings:) 方法會告訴你用戶當(dāng)前給你的App什么樣的授權(quán)許可.
現(xiàn)在第一步已經(jīng)完成,你可以注冊遠(yuǎn)程推送通知了.這一步相當(dāng)簡單,因為你不再需要向用戶請求什么許可了.用下面的代碼更新 application(_:didRegisterUserNotificationSettings:) 方法:
func application(application: UIApplication, didRegisterUserNotificationSettings notificationSettings: UIUserNotificationSettings) {
if notificationSettings.types != .None {
application.registerForRemoteNotifications()
}
}
在上面的方法中,首先檢查當(dāng)前用戶是否允許通知,如果允許直接調(diào)用 registerForRemoteNotifications().
其次, registerForRemoteNotifications() 的請求注冊的返回狀態(tài)會通過 UIApplicationDelegate協(xié)議中的某些方法通知你.
添加以下代碼到 AppDelegate :
func application(application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: NSData) {
let tokenChars = UnsafePointer<CChar>(deviceToken.bytes)
var tokenString = ""
for i in 0..<deviceToken.length {
tokenString += String(format: "%02.2hhx", arguments: [tokenChars[i]])
}
print("Device Token:", tokenString)
}
func application(application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: NSError) {
print("Failed to register:", error)
}
就像方法名所暗示的那樣,當(dāng)注冊通知成功后系統(tǒng)會調(diào)用 application(_:didRegisterForRemoteNotificationsWithDeviceToken:) 方法,否則將會調(diào)用 application(_:didFailToRegisterForRemoteNotificationsWithError:). 方法.
當(dāng)前 application(_:didRegisterForRemoteNotificationsWithDeviceToken:) 方法的實現(xiàn)看起來難以理解,其實它僅僅只是獲取 deviceToken 然后轉(zhuǎn)換成字符串.deviceToken的值就是這個過程得到的結(jié)果.它是由APNs服務(wù)器提供用來標(biāo)識當(dāng)前設(shè)備當(dāng)前App.當(dāng)發(fā)送時推送通知的時候,App用deviceToken作為"地址"傳遞到當(dāng)前設(shè)備.
注意 會有很多原因?qū)е伦允?最常碰到原因是程序運(yùn)行在模擬器上,或者App ID設(shè)置不正確.具體原因打印error值會提供更加詳細(xì)的信息.
到此,編繹運(yùn)行.確保你當(dāng)前運(yùn)行在真機(jī)上,你將會在控制臺看到打印出的device token.下面將會是你看到的結(jié)果:
把device token復(fù)制到某處保存.
在正式發(fā)送通知之前你還需要配置一點點,所以回到開發(fā)者中心.
創(chuàng)建一個SSL證書和PEM文件
在開發(fā)者中心進(jìn)入 Certificates, Identifiers & Profiles -> Identifiers -> App IDs 找到你應(yīng)用的App ID.在 Application Services 下面 Push Notifications 應(yīng)該為 Configurable :
點擊 Edit 滾動到 Push Notifications :
在 Development SSL Certificate 欄下,點擊 Create Certificate… 接下來的步驟就是創(chuàng)建 CSR 文件.創(chuàng)建好CSR文件后點擊 continue 和 Generate,這步會用你創(chuàng)建的CSR文件生成證書.最后下載并運(yùn)行生成好的證書,證書將被添加到你的鑰匙串應(yīng)用中,并與私鑰成對.
在開發(fā)者中心,你的App ID現(xiàn)在推送通知功能在development下應(yīng)該處于Enable狀態(tài).
在關(guān)閉鑰匙串應(yīng)用前還有最后一件事,右擊你剛才添加的證書,選擇 Export :
保存在桌面并命名為WenderCastPush.p12.
你會被提示要求為你的.p12文件設(shè)置密碼,你可以選擇不輸或者輸入一個你想設(shè)置的密碼.這里我用"WenderCastPush"作為密碼.接下來你需要輸入電腦登陸密碼來允許導(dǎo)出p12文件.
接下來,打開你的終端并執(zhí)行以下命令來從p12文件生成PEM文件:
$ cd ~/Desktop
$ openssl pkcs12 -in WenderCastPush.p12 -out WenderCastPush.pem -nodes -clcerts
如果你導(dǎo)出p12文件時輸入了密碼,在這里你必須輸入相同的密碼.
到此為止,你已經(jīng)艱難的躍過了很多坑,這一切都是值得的.接下來你將用你生成的WenderCastPush.pem文件發(fā)送第一個通知.
發(fā)送通知
之前下載的開始工程會包含一個WenderCastPush文件;里面包含兩個用于發(fā)送通知簡單腳本.你需要用到的是newspush.php.正如文件名所暗示的,這個腳本將會向你的用戶發(fā)送一個彈窗通知消息.
發(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)出文件時輸入的密碼 $passphrase
// Put your device token here (without spaces):
$deviceToken = '43e798c31a282d129a34d84472bbdd7632562ff0732b58a85a27c5d9fdf59b69';
// Put your private key's passphrase here:
$passphrase = 'WenderCastPush';
打開終端, cd 到 newspush.php 所在的文件夾,輸入:
ush.php 'Breaking News' 'https://raywenderlich.com'
如果進(jìn)行順利,你的終端將會顯示:
Connected to APNS
Message successfully delivered
現(xiàn)在,你應(yīng)該會收到你的第一條通知:
注意 如果你的App被打開并處于前臺運(yùn)行狀態(tài),你將看不到任何東西.通知已經(jīng)被投送但是App還不會處理這個通知.你只需要簡單的關(guān)閉App并重新發(fā)送通知即可.
常見問題
也許你會遇到以下問題:
只能接收到部分通知:如果你同時發(fā)送多個通知,只有部分通知將會被接收,不用擔(dān)心!這正是我們想要的結(jié)果.當(dāng)發(fā)送通知時APNS會為每一個開啟了推送通知的設(shè)備保持一個高質(zhì)量服務(wù)(Quality of Service)隊列.這個隊列的大小是1,所以如果你同時發(fā)送多個通知,最后一個通知才會被發(fā)送.
連接到APNS出現(xiàn)問題:出現(xiàn)這個問題的原因可能是你的防火墻阻塞了APNS所使用的端口.所以確保你的防火墻沒有阻塞住這些端口.另一個可能的原因是私鑰和CSR文件不正確.記住,每一個App ID有一個唯一的CSR和配對的私鑰.
解剖推送通知的基本原理
在進(jìn)行任務(wù)3之前,需要理解一下你推送的通知,打開 newspush.php 文件理解發(fā)送一個通知的基本概念應(yīng)該是怎么樣的.
注意第32-40行,這就是用JSON格式編碼的裝載體.這就是實際上發(fā)送給APNS的東西.在我們當(dāng)前的例子中,裝載體像下面一樣:
{
"aps":
{
"alert": "Breaking News!",
"sound": "default"
"link_url" : "https://raywenderlich.com,
}
}
對于一個不懂JSON數(shù)據(jù)的人來說,用{}括起來的塊相當(dāng)于一個字典類型的數(shù)據(jù).
這個裝載體是一個至少包含一項內(nèi)容的字典,這項內(nèi)容就是 aps, 它本身也是一個字典.在這個例子中"aps"包含"alert","sound"和"link_url"等字段.當(dāng)接收到一個通知,就會顯示一個包含"Breaking News!"文本的提醒視圖,并且有標(biāo)準(zhǔn)的提醒音效.
"link_url"實際上是一個自定義的字段.你可以添加類似的自定義字段到裝載體中,并且它會被投送到你的應(yīng)用.因為你并沒有在應(yīng)用中處理這個字段,所以當(dāng)前接收到這個鍵值對會什么都不做.
你可以在aps字典中添加以下5個鍵(key):
alert. 這個字段可以是一個字符串,就像當(dāng)前的例子.或是是一個字典.如果是一個字典,可以是本地化的文本或者通知的其它部分.查看蘋果文檔所支持的key.
badge. 這是一個將被顯示在應(yīng)用圖標(biāo)上的數(shù)字.你可以設(shè)置這個鍵為0來清除角標(biāo).
sound. 通過設(shè)置這個建,你可以播放存放在App本地定制的通知提示音來取代系統(tǒng)默認(rèn)的通知提示音.定制的通知提示音必須在30秒以內(nèi)并且還有一些其它的限制,你可以查看蘋果文檔了解更詳細(xì)信息.
content-available.設(shè)置這個鍵為1,當(dāng)前通知會變成靜默通知.這個部分會在這份教程的后面部分探索.
category. 這個鍵定義了通知的分類,用于顯示定制通知所包含的交互行為.同樣,接下來會探索這部分的內(nèi)容.
除此之外,你可以添加任意你想要添加的定制化數(shù)據(jù),只要裝載體不超過4096個字節(jié).
如果你玩夠了推送通知,接下來我們進(jìn)入到下一個章節(jié).
處理接收到的通知
在這個章節(jié),你將會學(xué)習(xí)當(dāng)App接收到通知后或者用戶點擊了通知應(yīng)該如何執(zhí)行什么樣的操作.
當(dāng)你接收到一個通知后會發(fā)生什么
當(dāng)你的app接收到一個通知, UIApplicationDelegate 的一個方法將會被調(diào)用.
需要根據(jù)接到收通知時App所處的狀態(tài)的進(jìn)行不同的處理.
如果你的應(yīng)用當(dāng)前不在運(yùn)行,并且用戶通過點擊推送通知啟動應(yīng)用,通知內(nèi)容會通過 application(_:didFinishLaunchingWithOptions:) 方法的 launchOptions 參數(shù)進(jìn)行傳遞.
如果你應(yīng)用當(dāng)前正運(yùn)行在前臺,推送通知將不會被顯示.但是 application(_:didReceiveRemoteNotification:) 會被立即調(diào)用.
如果你的應(yīng)用正在運(yùn)行,或者被掛起在后臺,并且用戶通過點擊通知使應(yīng)用進(jìn)入前臺 application(_:didReceiveRemoteNotification:) 方法會被調(diào)用.
在第一種情況下, WenderCast將到創(chuàng)建一個新的section,并直接打開以顯示到這個新建section.添加以下代碼到 application(_:didFinishLaunchingWithOptions:) 的末尾return語句之前.
// 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 鍵對應(yīng)的值是否存在,如果存在,這個值應(yīng)該就是你發(fā)送的通知裝載體.
如果存在,獲取 aps 對應(yīng)字典并傳給 createNewNewsItem(_:) 方法,這個方法根據(jù)接收的字典創(chuàng)建一個 NewItem,并刷新表格.
改變tab控制器當(dāng)前選中的tab索引值為1,也就是直接顯示新聞控制器視圖.
為了測試這部分代碼,你需要編輯WenderCast的scheme:
在 Run -> Info 下選擇 Wait for executable to be launched:
這個選項會使調(diào)試器等待應(yīng)用程序安裝直到應(yīng)用程序第一次被啟動。
編繹運(yùn)行,完成安裝后,發(fā)送一些新的動態(tài).點擊通知以啟動App,啟動之后app會顯示一些新消息.
注意 如果你突然接收不到通知,最有可能的原因是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)
}
這個方法直接創(chuàng)建了一個新的 NewsItem. 現(xiàn)在你可以把scheme設(shè)置回自動啟動App.
編繹運(yùn)行.保持App運(yùn)行在前臺,并選中新聞頁.發(fā)送一個通知,你可以看到消息奇跡般的顯示在視線內(nèi).
就是這樣!你的App現(xiàn)在可以處理基本的推送消息.
一些需要注意的事情:很多情況推送通知可能會被遺漏.對于WenderCast應(yīng)用來說是沒有問題的,因為裝滿消自己的列表對這個應(yīng)用來說并不是那么重要,但是一般來講你不應(yīng)該把推送通知做為傳遞內(nèi)容的唯一方式.作為備選項,推送通知應(yīng)該僅僅只是指示當(dāng)前有新的內(nèi)容可以獲取并讓App從服務(wù)器下載這些新的內(nèi)容.WenderCast應(yīng)用在這方有一些局限性,因為它并沒有合適的服務(wù)端.
可交互的通知
可交互的通知允許你添加定制化的按鈕在通知上.你也許注意到郵件通知或者Twitter消息通知有一個讓你回復(fù)或者點贊的部位.
可交互的通知是你通過注冊通知時設(shè)置 categories 定義的.每一個通知分類都可以有多個預(yù)先自定義的交互.
一旦完成注冊,就可以發(fā)送這個分類的通知.當(dāng)接收到通知相應(yīng)的交互就可以被用戶獲取.
對于 WenderCast 應(yīng)用,你將定義一個自定義"View"動作的"News"分類,自定義"View"允許用戶選擇查看,如果用戶選擇就會在App中直接顯示對應(yīng)的消息詳細(xì)文章.
添加以下代碼到 registerForPushNotifications(_:): 的開頭.
let viewAction = UIMutableUserNotificationAction()
viewAction.identifier = "VIEW_IDENTIFIER"
viewAction.title = "View"
viewAction.activationMode = .Foreground
這段代碼創(chuàng)建了一個按鈕標(biāo)題名為"View"的新交互通知,當(dāng)交互通知被用戶觸發(fā)時打開App并讓其進(jìn)入前臺.這個交互動作的標(biāo)識符是 VIEW_IDENTIFIER ,這個標(biāo)識符被用于區(qū)分同一通知的不同交互動作.
添加以下人碼片段至前面代碼之后:
let newsCategory = UIMutableUserNotificationCategory()
newsCategory.identifier = "NEWS_CATEGORY"
newsCategory.setActions([viewAction], forContext: .Default)
這段代碼定義了一個新通知分類,設(shè)置交互動作為之前定義的"View"動作,設(shè)置標(biāo)識符為" NEWS_CATEGORY",這個標(biāo)識符你是裝載體要包含的內(nèi)容以用其指示當(dāng)前通知屬于哪個分類.
最后,通過以下代碼,把新建分類傳遞給UIUserNotificationSettings構(gòu)造方法.
let notificationSettings = UIUserNotificationSettings(forTypes: [.Badge, .Sound, .Alert], categories: [newsCategory])
編繹運(yùn)行,應(yīng)用會注冊新通知設(shè)定.按Home鍵來退出當(dāng)前應(yīng)用,以使推送通知能夠顯示.
在你再次運(yùn)行 newspush.php 之前,首先對指定的分類做一個改動.打開 newspush.php 修改通知裝載體使它包含通知的分類標(biāo)識符:
$body['aps'] = array(
'alert' => $message,
'sound' => 'default',
'link_url' => $url,
'category' => 'NEWS_CATEGORY',
);
保存并關(guān)閉newspush.php,然后運(yùn)行以發(fā)送通知.如果一切進(jìn)展順利,你可以下拉并輕掃顯示的通知你會看到View按鈕被顯示.
非常好,點擊"View"按鈕將啟動WenderCast但不會做任何事情.為了獲取通知裝載體顯示新的內(nèi)容項,你需要在代理方法中做更多的操作.
處理通知交互動作事件
回到 AppDelegate.swift,添加另一個方法:
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)用戶通過通知的交互動作打開應(yīng)用時這個方法將會被調(diào)用.這看來起好像做了很多事,但是實際上沒有多少新的東西.這段代碼做了以下事情:
- 獲取 aps 字典
- 根據(jù)獲取到的字典創(chuàng)建 NewItem 并跳到新聞頁.
- 檢查以 identifier 為參數(shù)傳進(jìn)來的交互動作的標(biāo)識符.如果View交互動作的標(biāo)識符和鏈接有效則用 SFSafariViewController 顯示這個鏈接內(nèi)容.
- 在處理完用戶交互動用之后調(diào)用系統(tǒng)傳遞給你的 completionHandler 回調(diào).
編繹運(yùn)行,退出App,發(fā)送通知.但請確保下面的URL中有效的:
$ php newspush.php 'New Posts!' 'https://raywenderlich.com'
點擊通知的交互動作,在WenderCast應(yīng)用啟動后會立即展示Safari控制器.
恭喜,你剛剛已經(jīng)完成了可交互通知的實現(xiàn)!嘗試多發(fā)送幾次通知,并用不同的方法打開通知觀察通知的展現(xiàn)行為.
靜默推送通知
靜默推送通知可以靜默方式的喚醒你的app并讓它在后臺執(zhí)行任務(wù).WenderCast可以利用這個特性悄悄地刷新播客列表.
正如你所想象的,配合合適的服務(wù)端這個功能會非常有用.你不需要不斷的主動獲取數(shù)據(jù),當(dāng)有數(shù)據(jù)可獲取時僅僅只需要發(fā)送一個靜默通知.
開始之前進(jìn)入 App Settings -> Capabilites 并打開 WenderCast的 Background Modes. 檢查最后一個選項, Remote Notifications 是否勾選.
現(xiàn)在你的app接收到某個靜默通知就可以在后臺喚醒.
在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,以確定是否是靜默推送.
- 刷新播客列表,因為需要訪問網(wǎng)絡(luò)所以刷新列表是異步的.
- 當(dāng)刷新完列表,調(diào)用 completionHandler 回調(diào)方法,讓系統(tǒng)知道數(shù)據(jù)是否已經(jīng)下載.
- 如果不是靜默通知,假定它是消息并創(chuàng)建一個新的消息項.
必需要確保 completionHandler(_:) 方法被調(diào)用并傳遞真實的是否獲取到數(shù)據(jù)的結(jié)果.系統(tǒng)會根據(jù)回調(diào)計算耗電量和app在后臺的時間,系統(tǒng)會根據(jù)需要調(diào)節(jié)App的耗電量以及在后臺的時間.
以上就是這段代碼所做的事.現(xiàn)在你可以用 contentpush.php 給你的應(yīng)用發(fā)送一個靜默通知.請務(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
如果一切順利,什么事都不會發(fā)生.為了看到這段代碼的運(yùn)行結(jié)果,與之前設(shè)置的一樣結(jié)果必須把scheme設(shè)置為"Wait for executable to be launched"并在 application(_:didReceiveRemoteNotification:fetchCompletionHandler:) 方法旁邊打上斷點,以確認(rèn)這個方法會被調(diào)用.
路在何方?
恭喜你已經(jīng)完成了這份推送通知教程的內(nèi)容并且WenderCast應(yīng)用也有全部的推送功能!
你可以在這里下載完整的工程.記住為了能讓工程正常運(yùn)行你仍然需要更改Bundle ID和證書.
推送通知功能對于現(xiàn)在的App已經(jīng)是一個不可或缺的部分,但如果你發(fā)送的通知太頻繁用戶仍然會調(diào)整你的通知請求許可.對于一個深思熟慮的設(shè)計,推送通知會讓你的應(yīng)用保持足夠的用戶粘性!
這只貓接收到"推送通知"后它就會知道它的晚餐已經(jīng)準(zhǔn)備好了
我希望你能喜歡這份推送教程.如果你有任何問題,你可以在下面的評論中隨意提問.