當 App 不運行的時候,如果有某些事情發生时需要提醒用戶關注,那就需要用到某種通知技術。作為一個 iOS 開發者,我們知道 iOS 支持兩種通知:本地通知和推送(或者遠程)通知。前者是由 App 自己註冊和發起的,實現起來要相对簡單。實際上,我們可以在這裡 和 這裡找到一堆較早的教程,是關於本地通知的。
推送通知則不是由 App 自己發起的。它由另外的服務(叫做提供者)發起,這個服務通常是指某個 web 服務器,它通常會同時發給多台設備。通過推送通知,編寫 App 的人可以向用戶發送信息,可以隨機發送,也可以有計劃地發送,可以定制消息體,也可以使用默認的消息體。請看這裡,你會對蘋果推送通知有一個很好的了解。
從一個提供者發送一條消息到一個或多個設備,需要使用一個強制的通道。那就是蘋果推送通知服務器,或APN 服務器。由這些服務器將推送通知按指定路線發送到正確的設備,在提供者提交後幾秒,這些消息就會被送達。簡而言之,遠程通知的生命週期可以簡化為:
提供者 >> APN 服務器 >> 目標設備
我建議你看一下官方文檔,这里介紹了推送通知的工作機制。
一個 App 要想接收到推送通知,需要經過幾個步驟。這些步驟可以分為兩部分:編碼部分以及各種證書、設備描述文件的制作。編碼部分很簡單,只是一些模式化的程式碼。困難的是第二部分,這裡有許多額外的工作需要到不同的地方完成,比如 Mac OS 鑰匙串、項目设置以及蘋果開發者成員中心。
此外,遠程通知有兩種:沙盒環境的遠程通知,用於開發階段進行測試,以及生產環境的遠程通知,用於生產階段。如果你在沙盒環境中發出的通知成功被 App 收到,並且你前面經歷的步驟都是正確的,那麼就可以確認生產環境也基本 OK。自然,蘋果的測試服務器只能用來發送沙盒通知,它不能用於生產目的。
本教程的目的很簡單:我們將在一個範例 App 中啟用推送通知,然後用沙盒環境發送幾條通知以確認其工作正常。希望在你下一次準備將推送通知特性添加到 App 中時,這篇教程能給你提供一些助力。最主要的是,本教程能幫你解決在使用推送通知的過程中遇到的種種困惑和煩惱。
範例 App
我在正式進入教程之前的第一件事情,總是先介紹將在教程中實現的範例 App。很多時候,我還會提供一個開始項目,但這次例外。
對於這個教程中的範例 App,你需要做的就是用 Xcode 創建一個新的 iOS 項目,然後就完了。完全不需要加入任何東西或者控件。因為我們不會用這個 App 來測試 App 的內部功能,只是用它來接收推送通知而已。
無所謂項目名稱是什麼,你輸入任何名字都可以。對於我來說,我喜歡將項目命名為PNDemo
。
創建好新項目,我們就可以暫時把它拋到一邊。
重要提示:
在開始進入本教程的具體內容之前,我假設你已經具備所需的前提條件,並進行一些簡單約定。它們是:
- 你已經擁有了一個付費的開發者賬號,或者能夠訪問這個賬號。
- 你已經在蘋果開發者成員中心擁有一個iOS 開發證書。如果沒有,請看這裡。如果要用到「證書簽名請求(CSR)」文件,後面一部分內容專門介紹了如何創建證書簽名請求。
- 在本文中,當提到「推送通知」,你應該知道它就是指「蘋果推送通知」。
- 當提到「蘋果開發者網站」,你應該知道就是指「蘋果開發者成員中心」。
- 你已經了解什麼是通知載體(內容、標記、聲音、附加數據)以及它的用法。你可以參考這裡。
第一步: 證書簽名請求
範例項目已經建好,先把它扔到一邊,準備進入整個準備過程的第一個環節。在這一步,我們將創建一個證書簽名請求(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 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 的描述。在我們的例子中,輸入什麼無關緊要。當然在實際工作中,還是輸入一個精準的描述要好一些。
- App 的 Bundle ID。從我們的 Xcode 項目中將它拷貝進來,粘貼到這裡。
如圖所示,在這兩欄之間還有別的內容。比如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。
第三步: 配置 App ID 的 Push Notifications 選項
在上一步中,你可能注意到了,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
,從你的下載文件夾中找到並雙擊它,它將導入到鑰匙串的證書列表中。
雙擊.cer文件將導致鑰匙串 App 自動打開,請確認新的證書是否被導入到登錄鑰匙串中。這對我們的下一步來說很重要。
一旦在鑰匙串中找到新證書,右鍵點擊它,然後點擊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。
第六步: 項目設置
從這一步開始,我們就不用再在蘋果開發者網站里操作了,你可以將注意力放回到範例項目中來。我們將完成兩個目標:
- 首先,我們必須打開項目的推送通知能力,這樣才能在設備上接收到通知。這是一個基本步驟,這個步驟雖然簡單,但仍然有許多開發者會忘記將打開這個開關來激活推送通知能力。
- 我們需要正確地設置code signing和 App 使用的 provisioning profiles。請注意,這里是以開發模式為例進行演示,而不是生產模式。當然,二者是非常類似的,因此當 App 處於即將上線的部署階段時,你可以使用相同的步驟。
打開 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,大部分時候只需要你干三件事情:
- 填寫目標設備的 device token
- 指定推送通知證書的文件路徑
- 填寫通知載體(提醒、標記、聲音)
這裡我會演示兩個 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 中的程式碼簽名。無論如何,我希望通過本文,讓你對整個推送通知的準備步驟有一個清晰的認知並提高你的工作效率。