原文:A Beginner’s Guide to Push Notifications in Swift
作者:GABRIEL THEODOROPOULOS
译者:kmyhy
“推送通知?噢,不!”當我被告知需要在一個 iOS App 中實現推送通知時,我下意識就叫了一声,我相信你也會有和我一樣的反應。不是因為推送通知有多難,而是因為它超多的準備步驟,哪怕只想測試一條推送通知,幾乎每個開發者都会头大如斗。但是,在正式開始之前,先讓我們弄清幾件事情。
當 App 不運行的時候,如果有某些事情发生时需要提醒用戶关注,那就需要用到某種通知技術。作為一個 iOS 開發者,我們知道 iOS 支持兩種通知:本地通知和推送(或者遠程)通知。前者是由 App 自己註冊和发起的,實現起來要相对簡單。實際上,我們可以在這裡 和 這裡找到一堆較早的教程,是關於本地通知的。
推送通知則不是由 App 自己发起的。它由另外的服務(叫做提供者)發起,這個服務通常是指某個 web 服務器,它通常會同時發給多台設備。通過推送通知,編寫 App 的人可以向用戶發送信息,可以隨機發送,也可以有計劃地發送,可以定制消息體,也可以使用默認的消息體。请看這裡,你会對蘋果推送通知有一个很好的了解。
從一個提供者發送一條消息到一個或多個設備,需要使用一個強制的通道。那就是蘋果推送通知服務器,或APN 服务器。由這些服務器將推送通知按指定路線發送到正確的設備,在提供者提交后幾秒,這些消息就會被送達。簡而言之,遠程通知的生命週期可以簡化為:
提供者 >> APN 服務器 >> 目標設備
我建議你看一下官方文檔,这里介绍了推送通知的工作機制。
一個 App 要想接收到推送通知,需要經過幾個步驟。這些步驟可以分為兩部分:編碼部分以及各種證書、設備描述文件的制作。編碼部分很簡單,只是一些模式化的代碼。困難的是第二部分,這裡有許多額外的工作需要到不同的地方完成,比如 Mac OS 鑰匙串、項目设置以及蘋果開發者成員中心。
此外,遠程通知有兩種:沙盒環境的遠程通知,用於開發階段進行測試,以及生產環境的遠程通知,用於生產階段。如果你在沙盒環境中發出的通知成功被 App 收到,並且你前面經歷的步驟都是正確的,那么就可以確認生產環境也基本 OK。自然,蘋果的測試服務器只能用來發送沙盒通知,它不能用於生產目的。
本教程的目的很簡單:我們將在一個示例 App 中啟用推送通知,然後用沙盒環境發送幾條通知以確認其工作正常。希望在你下一次準備將推送通知特性添加到 App 中時,這篇教程能給你提供一些助力。最主要的是,本教程能幫你解決在使用推送通知的過程中遇到的種種困惑和煩惱。
我在正式進入教程之前的第一件事情,總是先介紹將在教程中實現的示例 App。很多時候,我還會提供一個開始項目,但這次例外。
對於這個教程中的示例 App,你需要做的就是用 Xcode 創建一個新的 iOS 項目,然後就完了。完全不需要加入任何東西或者控件。因為我們不會用這個 App 來測試 App 的內部功能,只是用它來接收推送通知而已。
無所謂項目名稱是什麼,你輸入任何名字都可以。對於我來說,我喜歡將項目命名為PNDemo。
創建好新項目,我們就可以暫時把它拋到一邊。
重要提示:
在開始進入本教程的具體內容之前,我假設你已經具備所需的前提條件,并進行一些簡單約定。它們是:
示例項目已經建好,先把它扔到一邊,準備進入整個準備過程的第一個環節。在這一步,我們將創建一個證書簽名請求(CSR)文件,後面我們創建推送通知專用的 SSL 證書時會用到這個文件。
這裡我們會使用鑰匙串Mac App,你可以通過 Lanuchpad 或者 Spotlight 搜索找到并啟動它。如果你不熟悉鑰匙串,操作時不要刪除其中的任何東西。
在鑰匙串中,打開Keychain Access > Certificate Assistant > Request a Certificate From a Certificate Authority… 菜單,如下圖所示:
在彈出的窗口中,User Email Address 和 Common Name 字段是必須填寫的。填完后選中Saved to disk 選項,這樣可以將 CSR 文件保存到磁盤,這個文件會在後面的蘋果開發者網站中用到。
點擊Continue并選擇 CSR 文件保存的文件路徑。我創建了一個單獨的文件夾,將所有本教程中用到的文件都放在一起(叫做PNDemo Files,建議你也這樣做),文件名則保持默認的文件名不變。
當你看到創建成功的消息后,點擊Done按鈕。這個 CSR 文件將保存到磁盤,我們將在蘋果開發者網站中用它來對其它證書進行簽名。
第二步是在蘋果開發者網站中創建新的App ID。App ID 是我們的 App 區別于其他 App 的唯一標識,它讓 APN 服務器能夠正確將通知發送到目的地。正如你將會看到的,我們將 App ID 和許多東西綁定在一起:推送通知證書、設備描述文件(讓我們的 App 能在測試設備上運行)。
首先,來到蘋果開發者成員中心。輸入你的賬號密碼進行登錄。然後點擊Certificates, Identifiers & Profiles鏈接,進入正確的頁面。
頁面顯示后,點擊位於iOS Apps下的Identifiers鏈接:
這時App IDs 會自動展開 (在左邊菜單的 Identifiers 下),同時所有 App ID 都會顯示在列表中。新的 App ID 創建好后也會添加到這個列表中。首先,點擊列表右上角的加號按鈕:
接著為我們的示例 App 創建一個新的 App ID。我們先填寫這兩欄:
如圖所示,在這兩欄之間還有別的內容。比如App ID Prefix,一般這個值不需要改動,保持默認,除非你想選擇另外的前綴。在本教程中,我們保留默認值。
有一個地方需要注意:當你想啟用推送通知時,explicit App ID必須選中。因為推送通知要求 App ID 必須和某個 App 的 Bundle ID 進行綁定。在這種情況下你不能在 App ID 中使用通配符(即以 * 號結尾的 App ID)。而且我覺得使用 explicit App ID 要比通配符 App ID 要好,不管這個 App 要使用什麼特性。使用 explicit App ID 后,在 IDs 列表頁中,你很容易就能發現新加的 App ID。
填完上面的信息后,將頁面拉到最下,有一個App Services。在服務列表底部,找到Push Notifications選項,勾選它,你可以多點幾下以確保該項被選中。
然後點擊Continue按鈕,會跳到一個確認頁面。如果一切 OK,點擊Submit 按鈕。如果某些地方填錯了,你可以又返回去修改。
最後會看到一個Registration Complete頁面。點擊Done按鈕,在 App ID 列表中會列出新的 App ID。
在上一步中,你可能注意到了,Development 和 Distribution 模式下的 Push Notifications 一項仍然是Configurable而不是Enabled,哪怕我們在創建 App ID 時明明勾選(啟用)了 Push Notifications 服務。也就是說我們還需要另外進行一些配置,以使狀態顯示正確。
注意因為僅僅是出於教學的目的,我們只配置開發模式的 Push Notifications 選項。我們不會對生產模式的推送通知進行測試,因此不需要設置生產模式的 Push Notifications。當然,二者並無不同。在真實 App 中,你當然還需要對生產模式進行配置,否則 App 上線后推送通知就無法使用了。
從 App ID 列表中點擊新建的 App ID 使其展開。在所有的服務後面都會有一個Edit按鈕。點擊它可以進入配置頁面。
拉動頁面,找到Push Notifications一項。這裡有兩個按鈕,分別用於創建開發模式和生產模式下的SSL 證書。我們只想創建開發模式的證書,因此點擊第一個按鈕:
這裡需要用到我們先一步在鑰匙串中創建的 CSR 文件。根據提示操作,在第一步,點擊Continue按鈕。在这个頁面會介紹如何創建 CSR,如果你沒有做的話可以參考一下。
點擊Choose File…按鈕,找到第一步中創建的 CSR 文件。如果你使用默認的文件名,你應該找到一個名為CertificateSigningRequest.certSigningRequest
的文件。
最後,點擊下圖所示中的Generate藍色按鈕:
好了,你已經創建好一個新的證書,同時它在開發(沙盒)模式下的推送通知特性已被開啟。現在,我們需要下載它,并將它導到鑰匙串中去(Mac 中的鑰匙串 App)。因此,請點擊Download按鈕。
下載后的文件名為aps_development.cer
,從你的下載文件夾中找到并雙擊它,它將導入到鑰匙串的證書列表中。
[ecko_alert color=”gray”]重要提示:
雙擊.cer文件將導致鑰匙串 App 自動打開,請確認新的證書是否被導入到登錄鑰匙串中。這對我們的下一步來說很重要。
[/ecko_alert]
一旦在鑰匙串中找到新證書,右鍵點擊它,然後點擊Export “…”選項。
確認文件格式為.p12,然後點擊Save按鈕。
在下一個窗口中,可以不設置密碼直接點擊OK按鈕。如果你設置了密碼,請牢記它或者把它保存到妥當的地方,因為一旦你忘記密碼,這個文件就不能使用了。
注意,本教程不會用到剛剛導出的文件。當然,如果你要在某些服務器(比如 Parse)上進行測試時,你就需要這個.p12文件了。因此,現在暫時把這個文件扔到一邊。重要的是你必須知道如何生成一個開發模式的.p12文件,生產模式下也是同樣的步驟。
事先申明,這一步只在測試推送通知(沙盒模式)時有用,生產模式下不需要。在這一步,我們需要在蘋果開發者網站上註冊要運行這個 App 的測試設備(可能是多個設備)。如果你已經事先註冊過你的設備了,則可以跳過此步。
假設你是第一次註冊你的設備,則你需要將它連接到你的 Mac 上并打開 Xcode。打開Window>Devices菜單,會顯示一個窗口,列出所有的設備和模擬器。
點擊位於左側的你的設備名稱,你可以在右側主窗口中看到設備的信息。注意其中的Identifier欄包含了一個由字母和數字組成的字符串。雙擊這個字符串,然後拷貝。
返回蘋果開發者網站,在Devices下,點擊All链接。主窗口中將列出所有已經註冊過的設備。要添加新設備,請點擊右上角的加號按鈕。
然後會顯示一個表單,先填寫Name欄,輸入你的設備名稱(例如Gabriel’s iPhone 6S或者My lovely iPad)。然後,將前面拷貝的設備 ID 粘貼到UDID欄。
點擊Continue,接下來是確認你剛才輸入的信息,點擊Register按鈕,完成註冊步驟。
你可以再次點擊Devices下面的All來檢查你的設備是否列到了已註冊設備列表中。遍歷整個列表,找出你剛剛註冊的設備。
在蘋果開發者網站進行的步驟還剩最後一步。我們需要創建一個開發模式下使用的設備描述文件,這樣我們才可以對我們的 APP 進行代碼簽名。注意,在你將 App 通過 iTunesConnect 上傳到應用商店或者用在 TestFlight 之前,你需要用同樣的步驟創建一個部署模式下使用的設備描述文件。
在蘋果開發者網站,點擊Provisioning Profiles下的Development鏈接。主窗口中將列出所有已有的描述文件,稍後,我們創建的新文件也會被添加到這裡。
要創建新描述文檔,點擊主窗口右上角的加號按鈕。這會顯示一個表單,出於演示的目的,我們就選擇iOS App Development(第一個)了。注意,如果你想創建一個用於部署的描述文檔,請選擇位於第二節(下面)的App Store。
然後點擊Continue,進入下一步。
現在將描述文檔和我們創建的 App ID 進行綁定。在下拉控件中找到正確的 App ID,然後點擊它。
接著,要將你的iOS 開發證書(假設你已經有了)包含進設備描述文件中。如果你像下圖一樣,列表中有不止一個證書,同時你也不知道該選哪一個,那就乾脆勾上Select All好了。
然後,準備要運行這個 App 進行測試的設備。確認一下,你沒有遺漏任何準備測試推送通知的設備。然後點擊Continue。
最後,為你的描述文檔命名,以便區別于其它描述文檔。我會將它命名為PNDemo Development Profile,你也可以另外取一個名字。
點擊Generate,進到下一個頁面。當新描述文檔就緒,你就可以下載了:
接下來就是照著頁面中顯示的步驟去做。雙擊剛剛下好的文件,文件將會自動安裝。如果使用了我的命名方式,則文件名可能叫PNDemo_Development_Profile.mobileprovision。
從這一步開始,我們就不用再在蘋果開發者網站里操作了,你可以將注意力放回到示例項目中來。我們將完成兩個目標:
打開 Xcode,在項目導航窗口中選擇示例項目。確保General標籤頁已打開。在Team下拉框,正確選擇準備用於簽名的 team。
如果在 Team 下拉框中沒有任何選項,你必須進到Xcode>Preferences…菜單,在Accounts標籤頁添加一個新的Apple ID。輸入和你的開發者賬號匹配的 App ID 和密碼,然後點擊Add按鈕就可以了。這不是我們要討論的範疇。如果你不清楚怎麼做,請參考這個鏈接。在成功添加 Apple ID 之後,關閉 Preferences 窗口,回到 General 標籤頁,你就可以選擇 team 了。
然後點擊Capabilities標籤頁,找到Push Notifications 一欄。然後將開關拖到 ON。
正如上圖中所顯示的文本所說,開啟推送通知能力將會在Info.plist文件中加入相應的權限。
現在打開Build Settings標籤,找到Code Signing處,展開Provisioning Profile項,在Debug一欄,點擊Automatic ,會顯示一個在你的開發者賬號中所包含的所有設備描述文檔。選擇我們剛剛下載并安裝的那個描述文檔。
目前不需要設置Release下的描述文檔,因為我們并沒有創建用於部署條件下的描述文檔。這個文檔需要等你從蘋果開發者中心創建并下載了之後,再用同樣的方法進行設置。
就在 Provisioning Profile 上面,還有一個Code Signing Identity項。點擊左邊的箭頭展開它,就像剛才一樣,點擊Debug一行的iOS Developer (or iPhone Developer),選擇一個正確的 ID,如下圖所示:
同樣,在真正的 App 中,與部署環境綁定的 ID 則是在Release中設置。
接著,點擊General標籤左邊的Target下拉按鈕,從列表中選中Project下的 PNDemo:
找到Code Signing一節,重複前面的步驟。首先為Debug模式設定正確的設備描述文檔,然後設定正確的Code Signing Identity。
所需項目設置都已經配置完了,該編寫代碼了。我們將讓 App 向 iOS 進行註冊并指定它所支持的通知類型(例如標記、聲音、提醒)。
在一開始我們會使用全部通知類型。打開AppDelegate.swift
文件,找到application(_:didFinishLaunchingWithOptions:)
方法。在 return 語句前加入兩行代碼:
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool { // Override point for customization after application launch. let notificationTypes: UIUserNotificationType = [UIUserNotificationType.Alert, UIUserNotificationType.Badge, UIUserNotificationType.Sound] let pushNotificationSettings = UIUserNotificationSettings(forTypes: notificationTypes, categories: nil) return true }
第一句我們指定了 App 所支持的通知類型,然後創建一個UIUserNotificationSettings
對象, 這個對象將在註冊推送通知時用到。如果你不想使用全部通知類型,你可以從數組中移除不想要的部分。
然後,我們要將想接收的通知類型告訴給系統,并註冊推送通知:
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool { ... application.registerUserNotificationSettings(pushNotificationSettings) application.registerForRemoteNotifications() return true }
儘管兩行代碼都是同樣重要,但只有最後一行才真正使我們能夠接收到推送通知。我們總共寫了四行代碼,這些代碼基本上是模式化的,你可以用在幾乎所有的項目中。我說幾乎,是因為有時候通知類型會有所不同而已。
註冊推送通知是重要的,但這只是代碼編寫工作的一半。另一半工作是實現委託方法,使你的 App 能夠正確處理所收到的通知。讓我們一步一步展示一下。
我們要實現的第一個委託方法是:
application(_: didRegisterForRemoteNotificationsWithDeviceToken:)
當 App 註冊推送通知成功后會調用這個方法。一般說來,第二個參數最為關鍵,它包含了針對這個設備的唯一 key,即device token。在真正的 App 中,你應該將這個 key 發送給最早發出推送通知的那個服務器。這個服務器(即提供者)用它和所有其他信息一起將消息推給蘋果推送通知服務器,因此 APN 服務器才能知道這個通知是發送給那個設備的。
device token 的形式類似于< XXXX XXXX XXXX XXXX XXXX >。通常在將它發送給服務器之前需要對它進行格式化。例如,你需要將“<”、“>”字符和中間的空格去掉,當然最終的格式跟服務器處理它們的方式有關。如果你使用了某種類型的提供者,它會提供給你一個框架讓你集成到 App 中(比如 Parse 就是這樣),在框架的手冊中會作具體的說明。
當然,在本教程中,我們并不會使用真正的服務器提供者,上面介紹的內容需要根據你的實際情況來進行調整。現在,我們只是在控制台中顯示一下 device token 而已。我們需要用這個 token 來測試推送通知,因此要將它打印出來。這個實現如下:
func application(application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: NSData) { print("DEVICE TOKEN = \(deviceToken)") }
雖然我們確信我們的推送通知是會註冊成功的,但某些時候也會註冊失敗。因此我們需要實現下面這個方法,這樣我們就可以處理註冊失敗的情況:
func application(application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: NSError) { print(error) }
當然,真正的錯誤處理應該根據 App 的實際需求和業務邏輯而定。
我們知道,推送通知在 App 進入後台時才會顯示,但是,在 App 處於前台時,也經常會收到一些推送通知,作為一個開發者,你也必須在這時進行相應的處理。在我們的示例中,我們只用簡單地在控制台中打印收到的消息。在真正的 App 中,你無論如何都不該這樣做。
下面是這個委託方法:
func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject]) { print(userInfo) }
注意你還可以有更多的委託方法可用,這取決於你想讓你的 App 做什麼,當然,這不是本文討論的範疇。你可以參考這裡 ,這是 UIApplicationDelegate 協議文檔,你可以在這裡找到更多的與遠程通知有關的協議方法。本文只討論推送通知的準備工作,上面三個方法就足夠了。
測試推送通知在過去曾經比較麻煩,因為那時我們僅有一種測試方法,要麼是自己從頭寫一個腳本,要麼下載一個現成的腳本進行修改。這種辦法仍然可用,但現在 Mac App Store 中已經有大量的 App 幫我們做這個工作了。這也是我們即將採用的方法。
使用 Mac App 進行測試的好處是,它會提供一個用戶界面,你可以填寫幾個信息(比如 device token 和推送通知證書)就可以工作了,所有“繁瑣的”工作,比如連接 APN 服務器的代碼都被封裝起來了。實際上,使用這些 App,大部分時候只需要你干三件事情:
這裡我會演示兩個 App,但我絕不是為這兩個 App 打廣告或者故意誘導你。我認為它們只是一個簡單的工具,能降低我的工作難度,節省我的工作時間,同時在 Mac App Store 中有許多類似的 App。講完這個,就讓我們來開始發送第一條推送通知吧!
第一個 App 叫做APN Tester Free,你可以在這裡找到它。它是免費軟件,你可以立即就下載它來測試推送通知。
正如上圖所示,你需要粘貼 device token 到Device Token 字段 (去掉 “<” 和 “>” 字符)。獲取 device token 很簡單,運行我們的示例 App,控制台立馬會打印 device token,類似如下畫面:
注意第一次運行 App 時,會問你是否允許接收遠程通知。當然,為了進行測試,你必須允許。
在Payload字段,你需要輸入推送通知的內容。如果你想收到一條帶文本提醒、數字標記和默認聲音的消息,你可以這樣輸入:
{"aps":{"alert":"Hello from AppCoda!","badge":1, "sound": "default"}}
關於載體(Payload)的細節,以及你可以設置的值,可以參考官方文檔。
在Certificate字段,你可以用Browse按鈕在文件系統中瀏覽開發環境下的 SSL 證書路徑(當然,記得勾上Gateway一節中的Development選項)。再提醒你一下,這個證書文件叫做aps_development.cer (如果你沒有修改它的名字的話)。因此,在瀏覽窗口中找到它,你會看到當證書被成功導入后,控制台中會顯示 .cer 文件已被加載)。
當這些都設好后,就可以發送一條推送通知到沙盒環境了。你只需要點擊Push按鈕就可以了。在控制台中,你會看到發送過程中的信息,如果發送失敗,你會看到用紅色顯示的字樣。
如果你嚴格按照教程的每一個步驟進行,沒有任何地方搞錯的話,你現在就已經收到你的第一條推送通知了。
反復 Push 推送通知,你可以看到當設備被鎖定后,這些通知是如何顯示的,當你打開通知中心又是如何顯示的,當 App 運行時又是什麼樣子。在最後一種情況下,你會在控制台中看到如下輸出:
改變標記數字,或者關閉/打開聲音,測試每件事情是否都如我們所想。
第二個工具叫做Easy APNs Provider,你可以在這裡找到它。它也是一個免費 App,它還會提供一些額外的選項,允許測試一些更高級的功能(比如附加數據)。
首先點擊Add tokens…按鈕,添加 device token。在彈出窗口中,將 device token 粘貼到第一個字段,但空格和 “<” 、 “>” 字符需要去掉。否則 device token 被認為是無效的。然後點擊Add按鈕,這樣 device token 就會追加到列表當中。另外,你可以為 device token 設置一個名字,在列表中點擊 device token 左邊的空白就可以設置。最後點擊Confirm按鈕。
然後是瀏覽aps_development.cer 文件,將證書導入到 App 中。點擊2. Choose Certificate file按鈕,你會看到文件名會顯示到按鈕后邊。
確認下面的下拉框中選中的是gateway.sandbox.push.apple.com,然後點擊3. Connect to:按鈕。你將在 App 中看到連接到蘋果推送服務器后的連接狀態。
現在,來準備通知載體。在右上角的地方,選中你想測試的類型。為了測試,你可以選擇Content, badge and sound。然後在下面的表單中填入相應的值:標題、內容和標記。如果你想以原始格式(JSON)查看載體,點擊Raw 標籤欄,否則載體是以表單這種更容易處理的形式呈現的。
最後,點擊5. Send APN 按鈕,開始發送。幾秒鐘之後,你將收到推送通知。
正如我前面說過的,你可能不想使用這兩個工具。你可以在 Mac App Store 中查找其他 App,直到發現其它更稱心如意的 App。
在這個教程中,我們分成了很多步驟,以及各種不同的實現方式。如果你看到這裡,你已經能夠在沙盒模式下發送推送通知了,那麼幾乎可以確定你在生產模式下也是 OK 的。你需要做的就是將本文的步驟照搬到發佈模式,并進行我們沒有做的那部分工作。例如,比如在編輯 App ID 中創建一個發佈模式的 SSL 證書,并把這個證書用於 Build Settings 中的代碼簽名。無論如何,我希望通過本文,讓你對整個推送通知的準備步驟有一個清晰的認知并提高你的工作效率。再見!