iOS推送通知

轉自:http://www.raywenderlich.com/3443/apple-push-notification-services-tutorial-part-12

很好很詳細的推送通知流程, 本人就按照這個實現.


Learn how to add Push Notifications into your iPhone app!

Learn how to add Push Notifications into your iPhone app

在iOS系統中,在後臺運行的程序能夠進行的操作是非常有限的。這種限制是爲了節省手機電池。
但是,如果你需要在用戶沒有使用你的程序的情況下給他們推送消息該怎麼辦呢?

打個比方,用戶收到了一個來自推特的信息,他喜歡的球隊在比賽中取勝,或者他的晚飯準備好了。因爲現在用戶並沒有在使用我們的程序,程序本身無法聽取這些事件。

幸運的是,蘋果系統對此已有了解決辦法。你並不需要讓程序不停地聽取事件或者在後臺跑運算。你只需要編寫一個服務器組件來完成這個任務。

在一個特定的事件發生時,那個服務器的組件就可以給我們的程序發一個推送信息!推送信息可以做如下三件事:

  • 顯示一條信息
  • 播放一小段提示音樂
  • 在程序的小圖標邊上放置一個數量標誌

你可以隨意組合這些選項;比如你可以播放提示音並放置數量標誌,而不顯示任何信息。

在這個有兩部分的教程中,你會用蘋果推送服務器(APNS)來完成一個有消息推送功能的簡單的程序。

在第一部分,你會學習如何接收推送的信息。

這篇教程針對的是中級或者高級的iOS開發者。如果你對iOS還處於入門階段,你應該先看看這個網站上一些初級教程. 並且,我也建議你可以先看看下面這兩篇教程(或者有類似的經驗):

那就讓我們開始吧!

文章概略

爲你的app加入信息推送是需要付出很多努力的。這個任務有很多個部分。下面是一個概要:

Apple Push Notification Services (APNS) Overview

  1. 程序啓用消息推送功能。用戶必須確認他希望接受這些推送信息。
  2. 那個程序接收一個“設備標記碼”。你可以把這個設備標記碼理解爲推送信息的地址。
  3. 那個程序將這個設備標記碼發送到服務器。
  4. 每當任何關於你的程序的事件發生時,那個服務器會將信息發送到蘋果的推送信息服務(APNS)。
  5. APNS 將這個信息再推送到用戶的設備上

用戶的設備收到這個信息時,會有提示窗口,播放提示音或者更新app的數量標誌。用戶可以在提示窗口中直接開啓這個app。我們的app從這裏接過推送信息的內容並能自定義處理這個信息的邏輯。

有人會問,iOS4中已經有了本地提示以及多重任務執行,那推送信息提示還有用嗎?答案:“當然啦”!

本地提示僅能用於定時的事件。無限制的後臺運算也僅限用於網絡通話,導航和背景音樂類的app。如果在程序已經進入後臺運行還想給用戶信息提示,那我們仍然需要使用推送信息提示。

在這個教程中,我會詳細解釋推送信息提示是怎麼實現的,以及如何在你的app中使用它。需要學的東西很多,讓我們現在開始吧!

推送信息提示準備工作

在你的app中加入推送信息提示,你需要:

一臺 iPhone 或者 iPad。 你需要真實的設備因爲推送信息提示在模擬器中不能用。

你必須是註冊的iOS開發者。 每個要加入推送信息的app的需要一個新的App ID,provisioning profile 和SSL證書。你可以在iOS Provisioning Portal來完成這些所需操作。

如果你想跟着這個教程中的例子,那你就需要創建新的provisioning profile和SSL 證書;你不能用我的。因爲獲取正確的證書很重要,我會一步步解釋如何獲取這個證書。

一個連接到網上的服務器。 推送信息是由這個服務器發送出來的。開發期間你可以用你的蘋果電腦作爲服務器(我們在這個教程中就會這樣做),但是在app上線後,你至少需要一個VPS(虛擬私人服務器)。

一個簡單的共享的服務器賬號是不夠的。你需要能夠在服務器上跑後臺線程,安裝SSL證書以及對外在特定端口建立TLS鏈接。

大多數共享服務器的提供者是不會讓你這麼做的。所以,我強烈建議你用 Linode類型的服務器.

解析消息推送服務/h2>

你的服務器負責創建被推送的消息,所以我們應該來了解一下這個服務器是怎麼做到的。

一個推送消息會包含設備標記碼,信息負載和一些其他的字節。那個信息負載就是我們要發到設備上的推送消息。

你的服務器提供的這個信息負載應該是JSON字典的格式。一個簡單的推送信息負載應該是這樣的:

{
	"aps":
	{
		"alert": "Hello, world!",
		"sound": "default"
	}
}

如果你不瞭解JSON,你只需要知道用“{}”符號分割出來的一個代碼塊代表了一個鍵與值對應的字典(和NSDictionary相似)。

我們的信息就是這樣的一個字典。這個字典裏至少要有一個物件,“aps”。在這裏,“aps”本身又是一個字典。“aps”包含了“alert”和“sound”兩個鍵。當設備收到這個消息時,程序應該顯示一個彈出消息:“Hello,world!”並且發出標準的提示音。

你還可以在“aps”字典中加入其他物件來設置那個消息。比如:

{
	"aps":
	{
		"alert":
		{
			"action-loc-key": "Open",
			"body": "Hello, world!"
		},
		"badge": 2
	}
}

注意“alert”本身也變成了一個字典。彈出信息欄的查看按鈕的標籤會變換成“action-lock-key”的值。“badge”鍵所對應的數字值會成爲程序圖標的數量標記。這個消息不會發出提示音。

這個JSON格式的信息負載還有很多可以設置的選項。你可以改變提示音的聲音,提供翻譯過的標籤,你也可以加入自定義的鍵值對。如果有興趣深入瞭解,你可以看看蘋果公司提供的 本地和推送信息編程指南.

推送信息應該很簡潔;那個信息負載不應該超過256個字節。這樣一般有足夠的空間傳送一個SMS信息或者一個推特消息。正確的服務器不會浪費寶貴的負載空間了傳送換行符和空格,所以你的服務其應該發送這樣的信息:

{"aps":{"alert":"Hello, world!","sound":"default"}}

這個對於人來說比較難讀懂,但是卻更節省空間。蘋果APNS不會接受超過256個字節的推送消息。

推送消息的易錯點

推送消息不可靠!

推送消息不可靠!

太不可靠了! 就算在APNS服務器接收了信息的情況下,推送消息也不一定會成功地傳到用戶設備上。

你的服務器在發射推送消息到APNS後,沒有任何辦法可以獲取消息的狀態。消息實際被推送的時間也不一定,可能幾秒鐘,也可能要半個小時。

並且,用戶的iPhone並不是隨時都能接收推送信息。他們可能在一個無法接收蘋果推送服務的無線網絡中,原因可能是相應的網絡端口被封閉了;或者用戶的手機關機了。

蘋果推送服務會在手機重新上線後試着重試沒有傳遞的信息,但是這是有時限的。時限一過,我們就永遠失去那個信息提示了!

在看到蘋果推送服務的賬單後

在看到蘋果推送服務的賬單後

好貴啊! 如果有很多用戶,或者所推送的信息需要從其他地方不斷獲取,那這個服務的費用可能會很高。

打個比方,如果你控制了RSS源。因爲你會清楚知道什麼時候會有新的RSS,你可以輕鬆直接地在適當的時候給用戶推送信息。
但是,如果你的程序允許用戶輸入自定義的RSS網址怎麼辦?在這種情況下你需要有自己的一套方案來探測是否有心的RSS信息。

事實上,你的服務器需要不停地訪問這些地址來探測新的RSS信息。如果你有很多用戶,那你就需要不斷增加新的服務器來探測和發送信息。這很快就會變得非常昂貴。

理論問題討論完了,那我們就開始實踐吧。 但是在做有趣的事情–編程,之前, 我們還需要在iOS開發者門戶網站上完成一些無聊的設置。

Provisioning Profiles以及各類證書

蘋果推送服務需要一個證書!

蘋果推送服務需要一個證書!

爲了使你的程序能使用推送服務,我們需要建立一個特別用來進行這個服務的provisioning profile。另外,你的服務器還需要通過SSL證書來和蘋果的推送服務器建立聯繫。

provisioning profile和SSL證書是一一對應的,並且只有在有一個有效的App ID的情況下才能用。這是爲了保證你的服務器只能將推送信息發到這一個特定的程序中,而不能發到其他任何程序。

值得注意的是,一個程序在開發時和發佈時需要用不同的provisioning profile。同時也有兩種服務器證書:

  • 開發時. 如果你的程序是在Debug模式下運行,並且使用的是開發階段的provisioning profile(Code Signing Identity屬性的值是”iPhone Developer”),那你的服務器必須使用開發階段的證書。
  • 生產時. 程序如果已經在蘋果商店上發佈(Code Signing Identity屬性的值是”iPhone Distribution”),那服務器必須使用生產階段的證書。如果這兩個被弄混了,推送的提示信息就無法到達你的程序。

在這個叫教程裏,我們將只會使用開發時的profile和證書。

生成Certificate Signing Request(證書申請)

還記得你如何在iOS開發者網站上註冊iOS開發計劃並獲取開發證書的嗎?我們下面要做的和那個類似。但我還是建議你一步一步跟着我來完成這個操作。因爲大多數問題都出在證書上。

電子證書都是基於公共和私有密鑰加密的。你並不需要知道這個加密的過程,但你需要知道那個證書必須和一個私有密鑰一起用纔會有效。

那個證書是這組密鑰的公共部分。所以把這部分隨便給別人是沒有問題的,在你用SSL來通訊時就需要這麼做。但是那個私有密鑰卻需要保密。這個祕密不能讓任何別人知道。如果你沒有這個密鑰,那證書就失效了。

在你申請一個電子證書時,你需要提交一份Certificate Signing Request(證書申請),縮寫爲CSR。在你生成CSR時,會生成一個新的私有密鑰並被放到你電腦的keychain中。然後你把這個CSR發到一個證書的認證網站(在我們的情況下,這個網站就是蘋果的開發者門戶網站)。這個網站會用CSR生成相應的SSL證書。

在你的Mac上打開Keychain Access程序(在Applications/Utilities子目錄下),然後在菜單中選擇 Request a Certificate from a Certificate Authority…,意思是從證書權威獲取證書。

Requesting a certificate with Keychain Access

如果你在菜單裏找不到需要的選項,或者選項的標籤是“Request a Certificate from a Certificate Authority with key”, 那你就需要先下載並且安裝WWDR Intermediate Certificate。 還需要注意的是,在Keychain Access主窗口中,千萬不要選擇任何的私有密鑰。

然後你應該看到類似下面的窗口:

用Keychain Access來申請證書

輸入你的郵箱。我曾聽有人說你應該用和你申請iOS開發者計劃時一樣的郵箱,但是應該任何郵箱都是可以的。

在Common Name(公用名)一欄輸入”PushChat”. 你可以輸入任何名字作爲公用名,但最好選擇一些有代表性的名字。這樣我們以後才能很快的找到這個私有密鑰。

Saved to disk(保存到硬盤)邊上打鉤。將它保存爲”PushChat.certSigningRequest”。

如果你現在來到Keychain Access的Keys部分,你應該看到一個新的,你剛剛生成的私有密鑰。右鍵點擊並將它匯出。

用keychain access匯出私有密鑰

將匯出文件命名爲“PushChatKey.p12”然後輸入一個加密碼。

爲了方便,我的加密碼就是“pushchat”。但爲了更好地保護這個p12文件,你應該選擇一些更難猜到的加密碼。私有密鑰必須是祕密的,不是嗎?但是你一定要記得住這個加密碼,否則私有密鑰還是不能用。

創建App ID和獲取SSL證書

登陸iOS置備門戶網站.

首先,我們需要創建一個新的App ID。每一個用推送信息服務的app都需要一個特有的ID,因爲只有這樣,被推送的信息提示才能被髮送到正確的程序上。(在這裏,你不能使用通配符ID。)

在邊上的目錄欄中選擇“App IDs”,然後點擊“New App ID”按鈕。

生成新的App ID

我填寫內容如下:

  • Description: PushChat
  • Bundle Seed ID: Generate New
  • Bundle Identifier: com.hollance.PushChat

你最好是選擇一個你自己的Bundle Identifier,而不是用我的,例如“com.你的網站.PushChat”。你之後在Xcode中還要使用這個Bundle Identifier。

很快,我們會生成一個SSL證書。你的服務器就是用這個證書來和蘋果的推送服務器建立安全連接。這個證書和你的App ID綁定在一起,這樣你的服務器就只能給這一個app發送推送信息提示了。

在你創建好App ID後,你應該看到類似如下的列表:

List of App IDs in the iOS Provisioning Portal

在“Apple Push Notification service”(蘋果推送信息服務)一欄裏,有兩個橘黃色的標誌分別寫着“Configurable for Development”(開發設置)和“Configurable for Production”(發佈生產設置)。這意味着我們的App ID已經可以用來進行推送了,只是還需要我們做相應的設置。點擊那個寫着“Configure”的鏈接來打開設置App ID的界面。

Configuring your App ID in the iOS Provisioning Portal

“Enable for Apple Push Notification service”(啓用蘋果推送服務)旁打鉤然後點擊對應“Development Push SSL Certificate”的Configure 按鈕。蘋果推送服務SSL證書助手界面就出現了:

Uploading your CSR with the SSL Assistant

它首先要你生成一個證書籤署請求。我們已經完成這一步了。點擊Continue。在下一步你需要上傳已經生成的證書籤署請求(CSR)。選擇那個CSR文件,然後點擊Generate

Generating a Certificate with the SSL Assistant

生成SSL證書需要幾分鐘時間,完成後點擊Continue

Downloading a certificate with the SSL assistant

點擊“Download” 來下載證書 – 名字應該叫 “aps_developer_identity.cer”. 點擊 “Done” 來關閉助手界面並回到設置App ID的界面。

Screenshot after the SSL Assistant is Complete

如你所見,我們現在有一個有效的證書了,可以開始給App推送證書了。如果需要,你可以在剛纔的地方重新下載證書。開發證書的有效期是3個月。

當你的App準備可以正式使用時,重複上述步驟來獲取生產時用的證書。步驟是一樣的。

注意: 生產時用的證書有效期是1年。但你需要提前更新它以確保你的App的推送服務不會中斷。

創建PEM文件

現在我們總共有三個文件:

  • CSR
  • 私有密鑰(PushChatKey.p12)
  • SSL證書(aps_developer_identity.cer)

將這三個文件好好保存起來。你可以選擇不再用那個CSR文件了。但是在你更新證書時,你可以使用同一個CSR或者獲取一個新的。如果你獲取新的CSR,你同時會生成一個新的私有密鑰。如果使用同一個CSR,那就只有SSL證書需要改變了。

我們需要將證書和私有密鑰轉換成另外一個更方便的格式。我們在服務器的推送部分會用PHP來寫,所以我們現在可以把證書和私有密鑰合併成一個PEM格式的文件。

PEM文件是怎麼運作的並不重要(說實話我也不知道),但是這樣我們能更容易地在PHP裏使用這個證書。如果你準備用其他語言來寫這個服務器部分,那下面的步驟可能會不配套。

我們將使用命令行OpengSSL的工具來完成這項任務。打開一個Terminal並輸入以下指令。

“cd”到你下載證書,密鑰文件的文件夾,對於我是桌面文件夾:

$ cd /Users/matthijs/Desktop

將那個.cer文件轉換成.pem文件:

$ openssl x509 -in aps_developer_identity.cer -inform der 
    -out PushChatCert.pem

將那個密鑰.p12文件轉換成.pem文件:

$ openssl pkcs12 -nocerts -out PushChatKey.pem -in PushChatKey.p12
Enter Import Password: <輸入你導出密鑰時用的那個密碼>
MAC verified OK
Enter PEM pass phrase: <輸入一個新的密碼>
Verifying - Enter PEM pass phrase: <重複密碼>

你首先需要輸入.p12文件的密碼,這樣openssl才能讀取這個文件。然後你需要你個新的密碼來對pem文件進行加密。在這個教程中我用的還是“pushchat”。但你自己應該選擇一個更加保險的密碼。

注意:如果你不輸入PEM的密碼,openssl不會給你任何的錯誤信息。但是生成的.pem文件裏就不會有那個密鑰。

最後,將那個證書和密鑰合併爲一個文件:

$ cat PushChatCert.pem PushChatKey.pem > ck.pem

我們應該測試一下這個證書是否能用。執行如下指令:

$ telnet gateway.sandbox.push.apple.com 2195
Trying 17.172.232.226...
Connected to gateway.sandbox.push-apple.com.akadns.net.
Escape character is '^]'.

我們試着與APNS服務器建立一個一般的,沒有加密的連接。如果你看到類似上面的回覆,那說明你的Mac能連上APNS。按Ctrl+C切斷連接。如果你得到一個錯誤信息,那你應該確保你的防火牆允許對外2195端口的連接。

讓我們再次試着連接。這次,我們會使用那個SSL證書和密鑰來建立一個加密連接:

$ openssl s_client -connect gateway.sandbox.push.apple.com:2195 
    -cert PushChatCert.pem -key PushChatKey.pem
Enter pass phrase for PushChatKey.pem: 

你應該看到一大竄回覆內容。那是openssl的運行信息。

如果連接成功建立,你應該可以鍵入幾個字符,然後當你點回車時,服務器就會和你斷開連接。如果建立連接過程出現問題,openssl會給出錯誤信息,但你可能需要在那一大竄信息中找出錯誤信息。

值得注意的是,APNS其實有兩個不同的服務器:那個沙盒服務器使用來測試的。還有一個正式的服務器是在你的程序投入生產後使用的。我們上面用的是測試用的服務器。因爲我們的證書是開發時才能用的。

生成Provisioning Profile

我們還需要用Provisioning門戶網頁來生成一個新的Provisioning Profile。在左邊的目錄欄中點擊“Provisioning”,選擇“Development”來生成一個新的profile。
Creating a Provisioning Profile in the iOS Provisioning Portal

填寫表格如下:

  • Profile Name: PushChat Development
  • Certificates: 在你的證書旁打鉤
  • App ID: PushChat
  • Devices: 選擇你的設備

我們需要一個新的profile因爲每個有推送信息的app都需要和它App ID相對應的一個profile。

點擊Submit,你的profile就會被生成。那個profile的狀態一開始會是“Pending”。刷新頁面直到它的狀態變成“Active”,這時你就可以下載那個文件了(給它取名爲PushChat_Development.mobileprovision)。

雙擊那個文件或者將這個文件拖到Xcode的圖標上,這樣就能將這個profile添加到Xcode中了。

在你將程序投入生產時,你需要重複上述步驟來生成Ad Hoc或者distribution profile。

一個非常基礎的APP

到現在爲止我們做的準備工作都比較枯燥,但卻是必要的。我們詳細的學習了生成各種證書的過程因爲我們不會經常坐這件事,但是推送信息沒有這些就無法運作。

通過連接到沙盒服務器,我們確認了證書是可用的。現在我們要測試一下我們是否確實可以推送提示信息!

啓動Xcode並建立一個新的項目。 選擇View-based Application作爲這個項目的模版然後點擊進入下一步。

Creating a View-Based Application with Xcode 4

我是這樣填寫各個空格的:

  • Product Name: PushChat
  • Company Identifier: com.hollance
  • Device Family: iPhone

那個Product Name(產品名字)和Company Identifier(公司代碼)合在一起就是Bundle ID。我的是“com.hollance.PushChat”。 你應該選擇和你在蘋果的Provisioning Portal上註冊的App ID相對應的產品名字和公司代碼(com.yourname.PushChat)。

完成創建項目並打開PushChatAppDelegate.m文件。將didFinishLaunchingWithOptions改爲如下:

[objc] view plaincopy
  1. <span style="font-family:inherit;color:#0220;margin:0px; padding:0px; border:0px; outline:0px; font-style:inherit; vertical-align:baseline;">-</span> <span style="font-family:inherit;color:#0220;margin:0px; padding:0px; border:0px; outline:0px; font-style:inherit; vertical-align:baseline;">(</span><span style="font-family:inherit;color:#a61390;margin:0px; padding:0px; border:0px; outline:0px; font-style:inherit; vertical-align:baseline;">BOOL</span><span style="font-family:inherit;color:#0220;margin:0px; padding:0px; border:0px; outline:0px; font-style:inherit; vertical-align:baseline;">)</span>application<span style="font-family:inherit;color:#0220;margin:0px; padding:0px; border:0px; outline:0px; font-style:inherit; vertical-align:baseline;">:</span><span style="font-family:inherit;color:#0220;margin:0px; padding:0px; border:0px; outline:0px; font-style:inherit; vertical-align:baseline;">(</span>UIApplication <span style="font-family:inherit;color:#0220;margin:0px; padding:0px; border:0px; outline:0px; font-style:inherit; vertical-align:baseline;">*</span><span style="font-family:inherit;color:#0220;margin:0px; padding:0px; border:0px; outline:0px; font-style:inherit; vertical-align:baseline;">)</span>application didFinishLaunchingWithOptions<span style="font-family:inherit;color:#0220;margin:0px; padding:0px; border:0px; outline:0px; font-style:inherit; vertical-align:baseline;">:</span><span style="font-family:inherit;color:#0220;margin:0px; padding:0px; border:0px; outline:0px; font-style:inherit; vertical-align:baseline;">(</span><a target="_blank" href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSDictionary_Class/" style="margin:0px; padding:0px; border:0px; outline:0px; font-style:inherit; font-family:inherit; vertical-align:baseline; color:rgb(0,104,55); text-decoration:none"><span style="font-family:inherit;color:#40080;margin:0px; padding:0px; border:0px; outline:0px; font-style:inherit; vertical-align:baseline;">NSDictionary</span></a> <span style="font-family:inherit;color:#0220;margin:0px; padding:0px; border:0px; outline:0px; font-style:inherit; vertical-align:baseline;">*</span><span style="font-family:inherit;color:#0220;margin:0px; padding:0px; border:0px; outline:0px; font-style:inherit; vertical-align:baseline;">)</span>launchOptions  
  2. <span style="font-family:inherit;color:#0220;margin:0px; padding:0px; border:0px; outline:0px; font-style:inherit; vertical-align:baseline;">{</span>  
  3.     self.window.rootViewController <span style="font-family:inherit;color:#0220;margin:0px; padding:0px; border:0px; outline:0px; font-style:inherit; vertical-align:baseline;">=</span> self.viewController;  
  4.     <span style="font-family:inherit;color:#0220;margin:0px; padding:0px; border:0px; outline:0px; font-style:inherit; vertical-align:baseline;">[</span>self.window makeKeyAndVisible<span style="font-family:inherit;color:#0220;margin:0px; padding:0px; border:0px; outline:0px; font-style:inherit; vertical-align:baseline;">]</span>;  
  5.    
  6.     <span style="font-family:inherit;color:#1174a;margin:0px; padding:0px; border:0px; outline:0px; vertical-align:baseline;"><em>// 讓手機知道我們想接收推送信息提示。</em></span>  
  7.     <span style="font-family:inherit;color:#0220;margin:0px; padding:0px; border:0px; outline:0px; font-style:inherit; vertical-align:baseline;">[</span><span style="font-family:inherit;color:#0220;margin:0px; padding:0px; border:0px; outline:0px; font-style:inherit; vertical-align:baseline;">[</span>UIApplication sharedApplication<span style="font-family:inherit;color:#0220;margin:0px; padding:0px; border:0px; outline:0px; font-style:inherit; vertical-align:baseline;">]</span> registerForRemoteNotificationTypes<span style="font-family:inherit;color:#0220;margin:0px; padding:0px; border:0px; outline:0px; font-style:inherit; vertical-align:baseline;">:</span>  
  8.         <span style="font-family:inherit;color:#0220;margin:0px; padding:0px; border:0px; outline:0px; font-style:inherit; vertical-align:baseline;">(</span>UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeSound | UIRemoteNotificationTypeAlert<span style="font-family:inherit;color:#0220;margin:0px; padding:0px; border:0px; outline:0px; font-style:inherit; vertical-align:baseline;">)</span><span style="font-family:inherit;color:#0220;margin:0px; padding:0px; border:0px; outline:0px; font-style:inherit; vertical-align:baseline;">]</span>;  
  9.    
  10.     <span style="font-family:inherit;color:#a61390;margin:0px; padding:0px; border:0px; outline:0px; font-style:inherit; vertical-align:baseline;">return</span> <span style="font-family:inherit;color:#a61390;margin:0px; padding:0px; border:0px; outline:0px; font-style:inherit; vertical-align:baseline;">YES</span>;  
  11. <span style="font-family:inherit;color:#0220;margin:0px; padding:0px; border:0px; outline:0px; font-style:inherit; vertical-align:baseline;">}</span>  

我們調用registerForRemoteNotificationTypes方法來告訴OS我們的程序想接收推送信息。

編譯並運行你的程序。你應該在真正的蘋果設備上運行因爲模擬器不支持推送信息提示。Xcode應該會自動選擇那個新的provisioning profile。如果你得到一個關於“code sign”的錯誤,那你需要確保已經選擇了正確的profile。 你可以在“build settings”中的“Code Sign”設置部分對其修改。

當啓動你的程序時,系統應該會彈出一個選擇菜單來詢問用戶是否允許當前程序推送提示信息。

A Simple iPhone App Requesting Permission to Deliver Notifications

你的程序只會向用戶詢問一次然後記住用戶的選擇。用戶只有選擇“OK”之後你的程序才能接收推送提示信息。用戶也可以在iPhone系統設置菜單中更改推送信息的設置。

Viewing Push Notification Permissions in iPhone Settings

你app的名稱會出現在手機的提示設置界面裏。用戶可以在這裏設置是否允許你的app推送信息提示,顯示數量圖標以及發出提示音。

A single app's Push Notification Settings

你的app也可以通過如下的代碼來探測用戶啓用了哪一種提示方式:

[objc] view plaincopy
  1. UIRemoteNotificationType enabledTypes <span style="font-family:inherit;color:#0220;margin:0px; padding:0px; border:0px; outline:0px; font-style:inherit; vertical-align:baseline;">=</span> <span style="font-family:inherit;color:#0220;margin:0px; padding:0px; border:0px; outline:0px; font-style:inherit; vertical-align:baseline;">[</span><span style="font-family:inherit;color:#0220;margin:0px; padding:0px; border:0px; outline:0px; font-style:inherit; vertical-align:baseline;">[</span>UIApplication sharedApplication<span style="font-family:inherit;color:#0220;margin:0px; padding:0px; border:0px; outline:0px; font-style:inherit; vertical-align:baseline;">]</span> enabledRemoteNotificationTypes<span style="font-family:inherit;color:#0220;margin:0px; padding:0px; border:0px; outline:0px; font-style:inherit; vertical-align:baseline;">]</span>;  

要讓我們的app開始接收推送提示,我們還需要將下面的代碼加入PushChatAppDelegate.m文件中:

[objc] view plaincopy
  1. <span style="font-family:inherit;color:#0220;margin:0px; padding:0px; border:0px; outline:0px; font-style:inherit; vertical-align:baseline;">-</span> <span style="font-family:inherit;color:#0220;margin:0px; padding:0px; border:0px; outline:0px; font-style:inherit; vertical-align:baseline;">(</span><span style="font-family:inherit;color:#a61390;margin:0px; padding:0px; border:0px; outline:0px; font-style:inherit; vertical-align:baseline;">void</span><span style="font-family:inherit;color:#0220;margin:0px; padding:0px; border:0px; outline:0px; font-style:inherit; vertical-align:baseline;">)</span>application<span style="font-family:inherit;color:#0220;margin:0px; padding:0px; border:0px; outline:0px; font-style:inherit; vertical-align:baseline;">:</span><span style="font-family:inherit;color:#0220;margin:0px; padding:0px; border:0px; outline:0px; font-style:inherit; vertical-align:baseline;">(</span>UIApplication<span style="font-family:inherit;color:#0220;margin:0px; padding:0px; border:0px; outline:0px; font-style:inherit; vertical-align:baseline;">*</span><span style="font-family:inherit;color:#0220;margin:0px; padding:0px; border:0px; outline:0px; font-style:inherit; vertical-align:baseline;">)</span>application didRegisterForRemoteNotificationsWithDeviceToken<span style="font-family:inherit;color:#0220;margin:0px; padding:0px; border:0px; outline:0px; font-style:inherit; vertical-align:baseline;">:</span><span style="font-family:inherit;color:#0220;margin:0px; padding:0px; border:0px; outline:0px; font-style:inherit; vertical-align:baseline;">(</span><a target="_blank" href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSData_Class/" style="margin:0px; padding:0px; border:0px; outline:0px; font-style:inherit; font-family:inherit; vertical-align:baseline; color:rgb(0,104,55); text-decoration:none"><span style="font-family:inherit;color:#40080;margin:0px; padding:0px; border:0px; outline:0px; font-style:inherit; vertical-align:baseline;">NSData</span></a><span style="font-family:inherit;color:#0220;margin:0px; padding:0px; border:0px; outline:0px; font-style:inherit; vertical-align:baseline;">*</span><span style="font-family:inherit;color:#0220;margin:0px; padding:0px; border:0px; outline:0px; font-style:inherit; vertical-align:baseline;">)</span>deviceToken  
  2. <span style="font-family:inherit;color:#0220;margin:0px; padding:0px; border:0px; outline:0px; font-style:inherit; vertical-align:baseline;">{</span>  
  3.     NSLog<span style="font-family:inherit;color:#0220;margin:0px; padding:0px; border:0px; outline:0px; font-style:inherit; vertical-align:baseline;">(</span><span style="font-family:inherit;color:#1174a;margin:0px; padding:0px; border:0px; outline:0px; vertical-align:baseline;"><em>@</em></span><span style="font-family:inherit;color:#bf1d1a;margin:0px; padding:0px; border:0px; outline:0px; font-style:inherit; vertical-align:baseline;">"My token is: %@"</span>, deviceToken<span style="font-family:inherit;color:#0220;margin:0px; padding:0px; border:0px; outline:0px; font-style:inherit; vertical-align:baseline;">)</span>;  
  4. <span style="font-family:inherit;color:#0220;margin:0px; padding:0px; border:0px; outline:0px; font-style:inherit; vertical-align:baseline;">}</span>  
  5.    
  6. <span style="font-family:inherit;color:#0220;margin:0px; padding:0px; border:0px; outline:0px; font-style:inherit; vertical-align:baseline;">-</span> <span style="font-family:inherit;color:#0220;margin:0px; padding:0px; border:0px; outline:0px; font-style:inherit; vertical-align:baseline;">(</span><span style="font-family:inherit;color:#a61390;margin:0px; padding:0px; border:0px; outline:0px; font-style:inherit; vertical-align:baseline;">void</span><span style="font-family:inherit;color:#0220;margin:0px; padding:0px; border:0px; outline:0px; font-style:inherit; vertical-align:baseline;">)</span>application<span style="font-family:inherit;color:#0220;margin:0px; padding:0px; border:0px; outline:0px; font-style:inherit; vertical-align:baseline;">:</span><span style="font-family:inherit;color:#0220;margin:0px; padding:0px; border:0px; outline:0px; font-style:inherit; vertical-align:baseline;">(</span>UIApplication<span style="font-family:inherit;color:#0220;margin:0px; padding:0px; border:0px; outline:0px; font-style:inherit; vertical-align:baseline;">*</span><span style="font-family:inherit;color:#0220;margin:0px; padding:0px; border:0px; outline:0px; font-style:inherit; vertical-align:baseline;">)</span>application didFailToRegisterForRemoteNotificationsWithError<span style="font-family:inherit;color:#0220;margin:0px; padding:0px; border:0px; outline:0px; font-style:inherit; vertical-align:baseline;">:</span><span style="font-family:inherit;color:#0220;margin:0px; padding:0px; border:0px; outline:0px; font-style:inherit; vertical-align:baseline;">(</span><a target="_blank" href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSError_Class/" style="margin:0px; padding:0px; border:0px; outline:0px; font-style:inherit; font-family:inherit; vertical-align:baseline; color:rgb(0,104,55); text-decoration:none"><span style="font-family:inherit;color:#40080;margin:0px; padding:0px; border:0px; outline:0px; font-style:inherit; vertical-align:baseline;">NSError</span></a><span style="font-family:inherit;color:#0220;margin:0px; padding:0px; border:0px; outline:0px; font-style:inherit; vertical-align:baseline;">*</span><span style="font-family:inherit;color:#0220;margin:0px; padding:0px; border:0px; outline:0px; font-style:inherit; vertical-align:baseline;">)</span>error  
  7. <span style="font-family:inherit;color:#0220;margin:0px; padding:0px; border:0px; outline:0px; font-style:inherit; vertical-align:baseline;">{</span>  
  8.     NSLog<span style="font-family:inherit;color:#0220;margin:0px; padding:0px; border:0px; outline:0px; font-style:inherit; vertical-align:baseline;">(</span><span style="font-family:inherit;color:#1174a;margin:0px; padding:0px; border:0px; outline:0px; vertical-align:baseline;"><em>@</em></span><span style="font-family:inherit;color:#bf1d1a;margin:0px; padding:0px; border:0px; outline:0px; font-style:inherit; vertical-align:baseline;">"Failed to get token, error: %@"</span>, error<span style="font-family:inherit;color:#0220;margin:0px; padding:0px; border:0px; outline:0px; font-style:inherit; vertical-align:baseline;">)</span>;  
  9. <span style="font-family:inherit;color:#0220;margin:0px; padding:0px; border:0px; outline:0px; font-style:inherit; vertical-align:baseline;">}</span>  

當你的app註冊遠程推送提示時,它會獲取一個設備代碼(device toke)。這是一個32字節的獨特數字來辨別用戶的設備。你可以把這個代碼看做是用戶設備的地址。APNS用這個地址來推送信息提示。

在你用來測試的蘋果設備上運行你的app。你應該在Xcode的控制檯窗口中看到:

My token is: 
<740f4707 bebcf74f 9b7c25d4 8e335894 5f6aa01d a5ddb387 462c7eaf 61bb78ad>

那個代碼是一個NSDatat對象,擁有某種二進制數據結構。我們不應該對它進行任何修改。我們只用知道它有32個字節,可以用64個十六進制的字符表示。我們會直接用這種表示方式(去掉那括弧和中間的空格)。

如果你在模擬器裏運行你的程序,didFailToRegisterForRemoteNotificationsWithError:方法應該會被調用因爲模擬器不支持推送信息提示。

我們的app就暫時寫完了。但要真的開始推送信息,我們還需要完成最後的一步!

推送第一個信息提示

我曾說過,你需要有一個服務器來把信息推送到你的app上。但爲了測試,我們還不需要一個服務器。你可以用下面這個簡單的PHP腳本來和APNS建立連接並將信息推送到指定的設備上。你可以直接在你的Mac上運行這個腳本。

下載這個叫“SimplePush”代碼包 並解壓縮. 你需要對simplepush.php文件進行如下修改.

  1. <span style="margin:0px; padding:0px; border:0px; outline:0px; font-family:inherit; vertical-align:baseline; color:rgb(102,102,102)"><em>// 把你的設備代碼放在這裏(不要空格): </em></span>  
  2. <span style="margin:0px; padding:0px; border:0px; outline:0px; font-style:inherit; font-family:inherit; vertical-align:baseline; color:rgb(0,0,136)">$deviceToken</span> <span style="margin:0px; padding:0px; border:0px; outline:0px; font-style:inherit; font-family:inherit; vertical-align:baseline; color:rgb(51,153,51)">=</span> <span style="margin:0px; padding:0px; border:0px; outline:0px; font-style:inherit; font-family:inherit; vertical-align:baseline; color:rgb(0,0,255)">'0f744707bebcf74f9b7c25d48e3358945f6aa01da5ddb387462c7eaf61bbad78'</span><span style="margin:0px; padding:0px; border:0px; outline:0px; font-style:inherit; font-family:inherit; vertical-align:baseline; color:rgb(51,153,51)">;</span>  
  3.    
  4. <span style="margin:0px; padding:0px; border:0px; outline:0px; font-family:inherit; vertical-align:baseline; color:rgb(102,102,102)"><em>// 把你密鑰的密碼放在這裏:</em></span>  
  5. <span style="margin:0px; padding:0px; border:0px; outline:0px; font-style:inherit; font-family:inherit; vertical-align:baseline; color:rgb(0,0,136)">$passphrase</span> <span style="margin:0px; padding:0px; border:0px; outline:0px; font-style:inherit; font-family:inherit; vertical-align:baseline; color:rgb(51,153,51)">=</span> <span style="margin:0px; padding:0px; border:0px; outline:0px; font-style:inherit; font-family:inherit; vertical-align:baseline; color:rgb(0,0,255)">'pushchat'</span><span style="margin:0px; padding:0px; border:0px; outline:0px; font-style:inherit; font-family:inherit; vertical-align:baseline; color:rgb(51,153,51)">;</span>  
  6.    
  7. <span style="margin:0px; padding:0px; border:0px; outline:0px; font-family:inherit; vertical-align:baseline; color:rgb(102,102,102)"><em>// 把你的提示信息放在這裏:</em></span>  
  8. <span style="margin:0px; padding:0px; border:0px; outline:0px; font-style:inherit; font-family:inherit; vertical-align:baseline; color:rgb(0,0,136)">$message</span> <span style="margin:0px; padding:0px; border:0px; outline:0px; font-style:inherit; font-family:inherit; vertical-align:baseline; color:rgb(51,153,51)">=</span> <span style="margin:0px; padding:0px; border:0px; outline:0px; font-style:inherit; font-family:inherit; vertical-align:baseline; color:rgb(0,0,255)">'My first push notification!'</span><span style="margin:0px; padding:0px; border:0px; outline:0px; font-style:inherit; font-family:inherit; vertical-align:baseline; color:rgb(51,153,51)">;</span>  

你應該把設備代碼從app裏拷貝粘貼到$deviceToken變量。請確保你去掉空格和括弧。把$passphrase的值設爲你密鑰的密碼, $message的值設爲你要推送的信息字符串。

把你的ck.pem文件拷貝到SimplePush文件夾中。記住,ck.pem包含你的證書和密鑰。

打開終端並打入:

$ php simplepush.php

如果一切順利,那個腳本應該回應:

Connected to APNS
Message successfully delivered

然後幾秒之後,你應該收到app的第一個推送信息提示:

Simple app receiving a Push Notification

注意,如果你的app是開着的,你就看不到推送的信息。這是因爲我們還沒有寫代碼在app裏接收推送的信息。你應該關掉app然後重試。

如果simplepush.php腳本因錯誤退出,那你因該確保你的PEM文件是正確生成的,並且確保你可以連接到蘋果的沙盒服務器(請看上面的詳細步驟)。

我們並不用急着知道這個腳本到底做了什麼,因爲這是這個教程的下一部分的內容。在下一部分,我們將學習如何編寫一個真正的推送服務器。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章