googleAPNS:https://code.google.com/p/apns-php/wiki/CertificateCreationphp
推送證書建立:html
1,登錄官網:iPhone Developer Program Portaljava
2,選擇APP IDs。 (or click here)node
3,建立一個app id,注意不要選擇Explicit,不要選擇Wildcard。ios
4,繼續向下進行。直至完成建立。--->建立PUSH SSL CER(Apple Documentation: Creating the SSL Certificate and Keys)編程
5,生成SSL證書後,雙擊加入Keychain中(建立成功的話,證書下方會有私鑰)。json
6,在keychain中,右擊證書,導出證書爲**.p12(不要注入密碼)。安全
7,開啓終端,更改目錄到p12文件所在處,用命令將PKCS12證書更改成PEM格式文件,命令:服務器
openssl pkcs12 -in **.p12 -out **.pem -nodes -clcerts
8,在後臺ApnsPHP中應用PEM文件。網絡
APP中APNS的實現:ObjectiveC page
推送通知至某設備,DeviceToken是依據DeviceID和APPlicationID,經由apple生成。故是惟一的(per device and per application)。
code demo: http://code.google.com/p/apns-php/source/browse/trunk/Objective-C%20Demo
----------------------------------------------------------------------------------------------------
簡述:
想讓應用程序的推送功能正常工做,你須要至關多的努力,這個過程很是繁瑣。如下是這個過程的概述圖:
1.應用程序須要激活推送通知功能。在使用以前,用戶須要確認他是否願意接受這些推送功能。
2.應用程序接到一個「device token」。你能夠認爲「device token」是推送通知發送信息的目的地址。
3.應用程序會將「device token」發送給你的服務器
4.當你的應用程序發生了有趣的事情,你的服務器向 「×××送通知的服務器(Apple Push Notification Service,縮寫,APSN)」發送通知。
5.APSN再向用戶的設備(例如,iPhone,iPad等)發送通知。
當用戶的設備接受到推送通知,將會顯示提醒框,播放提示聲音,更新圖標的未讀信息數目。用戶能夠經過點擊提醒框來加載應用程序,蘋果公司給推送通知加入了可選內容,你能夠根據需求來操做推送通知。
當iOS4實現了本地通知和多任務,蘋果的推送通知是否還有使用價值?固然有!
本地通知被定時事件調度限制,而且只有VOIP、導航、後臺音頻播放這些應用在後臺沒有被限制。若是當應用程序處於關閉狀態時,你想將外部事件的發生通知給你的應用程序用戶,仍然須要推送通知。
在這篇教程中,我將解釋推送通知系統實現的細節以及如何在應用中創建推送。這裏有不少要解釋的,這須要(您)花點兒時間去明白。
你須要爲推送作些什麼
在你的應用中添加推送通知,你須要:
一臺iPhone或者iPad 推送通知不能在模擬器上實現,因此你須要在設備上測試。
一個iOS開發者證書 你須要一個新的AppID和每一個應用程序使用的推送證書,推送服務器須要的「SSL 」證書,你可在iOS開發網站上作這些。
若是你想跟隨這篇教程的例子學習,你將須要建立你本身的推送證書和SSL證書,你不可使用個人這些證書。由於得到正確的證書是很重要的,我將詳細解釋如何獲得一個推送證書。
一個聯網的服務器 推送通知一般是由服務器來發送的。對於開發,你可使用一個Mac來代替服務器(咱們將在教程中這樣作),可是發佈的產品,你至少須要相似VPS( Virtual Private Server )的服務器。
一個廉價的共享虛擬主機帳戶不能知足發佈產品的須要。你須要在服務器的後臺啓動一個進程,安裝一個SSL證書,而且可以在某個端口中可以外聯TLS。
大部分的共享虛擬主機並不讓你實現這些功能,即便若是申請的這些需求經過了。不管怎麼樣,我真的建議你使用一個VPS主機,像Linode。
解析一個推送通知
你的服務器負責建立一個推送通知消息,因此瞭解一個推送通知消息的構成是有必要的。
一個推送通知是一個短信息,由「device token」,「payload–負載內容」,和其餘的一些字節組成。「payload–負載內容」是咱們感興趣的部分,由於它包含着咱們實際想發送出去的數據。
你的服務器必須提供「payload–負載內容」,它是以JSON的字典的數據格式來組織數據的。下面是一個很簡單的推送消息payload:
{ "aps": { "alert": "Hello, world!", "sound": "default" } }
對於不瞭解JSON的人,一個block的劃分由一對花括號「{}」包裹,其中包含一個由「鍵/值 (key/value)」對組成的「字典」,(就像NSDictionary)。
「payload–負載內容」就是一個「字典」,包含了至少一個「aps」項,「aps」自己也是一個「字典」。在咱們的例子中,「aps」包含 「alert」和「sound」字段。當這個推送通知被接收後,它將顯示一個包含「Hello, world!」內容的提醒框,而且播放標準的提示音。
你能夠向「aps」添加另外的選項,來配置通知,例如
{ "aps": { "alert": { "action-loc-key": "Open", "body": "Hello, world!" }, "badge": 2 } }
如今「alert」是一個字典。」action-loc-key」 對應的value替代了「View」按鈕上的文本內容,」badge」字段包含的數字將被顯示在應用圖標上,這個通知不會播放提示音。
有不少途徑去設置JSON的「payload–負載」內容,你能夠改變播放聲音,你能夠提供本地化的文本,而且添加本身的字段。更多信息,請詳見官方Local and Push Notification Programming Guide。
推送通知的目標就是精短;「payload–負載內容」的大小不能超過256個字節。這樣留給你的空間和一條短消息或者一個tweet消息的大小同樣。一個小型的推送服務不會在換行符和空格上浪費空間,這樣一條推送就像下面所顯示的:
{「aps」:{「alert」:」Hello, world!」,」sound」:」default」}}
上面這條消息可讀性比較低,可是它節省了足夠的字節,因此犧牲可讀性是值得的。若是一個推送通知的payload超過了256個字節,那麼這個推送就不會被「APNS」接受。
關於推送通知常見的錯誤
推送通知是不可靠的
推送通知是不可靠的!即便APNS(Apple Push Notification Service×××送通知服務)服務器接受了推送通知,仍然沒法保證該通知最終會被送達。
就你的服務器而言,推送通知會被髮出而且遺忘掉;當你將通知發送到APNS後,沒有辦法查出它所處的狀態。通知送達的時間也從幾秒到半小時不等。
一樣,用戶的iPhone不是全部時間均可以收到推送通知。好比,由於指定的端口被封,手機處於一個不容許和APNS鏈接的WIFI網絡。或者手機已經關機了。
APNS將會在手機鏈接到可用網絡後下發從該機器收到的最後一條通知,可是隻會嘗試有限的時間。一旦發送超時,此條通知就會永遠丟失!
After looking at the APNS Server Bill
推送通知會使開銷很大!若是你掌控了須要推送的內容,在你的應用中加入推送功能至關容易和廉價,可是當你有好多用戶和數據須要輪詢的時候,這個功能就會使得服務器開銷龐大(譯者注:不必定指價格,包括是資源消耗)。
好比,你打算在本身的RSS訂閱更新的時候通知用戶,這樣作沒問題。由於你控制着RSS訂閱,而且知道它什麼時候發生變化——當你更新網站內容時——因而你的服務器能夠在合適的時候發出通知。
可是若是你的應用是一款RSS閱讀器,容許用戶添加自定義的連接呢?這種狀況下,你須要構建一些機制去檢測那些訂閱的更新。
實際上,這意味着你的服務器爲了檢查那些訂閱的變化,須要不停的輪詢它們。若是你擁有不少用戶,你可能不得不安裝一堆新服務器去處理這些工做和知足帶寬需求。對於這類應用,推送會變得異常昂貴,可能不值得去作。
好了,理論上足夠了。下面到時間來學習如何使用推送了。在咱們投入到美好的事物——編程!以前——有一些無聊的搭建環境的工做須要在iOS Provisioning Portal上完成,因此讓咱們儘快完成它。
Provisioning Profiles和證書,天哪!
APNS須要一個證書
在你的應用中使用推送通知,須要用一個配置過推送功能的provisioning profile來簽名。此外,你服務器全部與APNS的通信都須要進行SSL證書籤名。
Provisioning profile和SSL證書緊密聯繫在一塊兒,而且只對一個App ID有效。這個保護措施能夠保證只有你的服務器能夠發推送通知到你的應用,其它服務器不能夠。
正如你所知道的,應用程序在開發和發佈階段使用不一樣的provisioning profiles。一樣,推送服務器的證書也有兩種:
· Development. 若是你的應用程序運行在debug模式,而且使用的是Development provisioning profile (Code Signing Identity 是 「iPhone Developer」)簽名的,你的服務器必須使用Development證書。
· Production. 使用Ad Hoc方式發佈的,或發佈在App Store(Code Signing Identify 是 「iPhone Distribution」)上的應用程序,必須和使用Production證書籤名的服務器通信。若是這裏面有不匹配,推送通知將沒法送達你的應用。
在這篇教程裏,咱們不須要爲分發profiles和證書煩惱,只須要使用Development版本的便可。
1,生成證書籤名請求(Certificate Signing Request, CSR)
還記得你在註冊成爲iOS開發者以後,如何去iOS Provisioning Portal生成一個開發證書嗎?若是記得,下面的步驟應該會比較熟悉。不過,我仍然建議你準確地按照步驟來作。由於大多數在實現推送通知過程當中遇到的問題,都是因爲證書問題引發的。
數字證書基於公鑰-私鑰加密方法。你不須要知道任何關於證書的加密方法,可是你要知道證書一直會與一個私鑰搭配使用。
證書是密鑰對的非祕密的部分。將它發送給其它人是安全的,好比經過SSL通信的過程當中就會包含證書。然而,對於私鑰,固然是私有的。它是祕密的。你的私鑰只對你有用,對其餘人沒用。要重視的是:若是你沒有私鑰的話,就沒法使用證書。
每當申請一個數字證書的時候,你須要提供一個證書籤名請求,簡稱CSR。當你建立了CSR後,會生成一個新的私鑰保存到keychain應用程序中。而後 你將CSR發送到一個證書頒發機構(目前狀況下就是iOS Developer Portal),它會根據CSR中的信息生成SSL證書。
打開Mac中的Keychain Access程序(在Applications/Utilities下),選擇菜單中的Request a Certificate from a Certificate Authority…
若是菜單中沒有「Request a Certificate from a Certificate Authority with key」選項,就先去下載安裝WWDR Intermediate Certificate。而且確認Keychain Access窗口裏沒有私鑰被選中。
如今,你應該會看到下面的窗口:
在裏面輸入你的郵件地址,聽有人推薦說最好使用和註冊IOS開發者證號一樣的郵件地址,但看起來任何郵件地址均可以。在Common Name中輸入「PushChat」。你能夠輸入任何字符串,但最好是有意義的。這會使你之後容易查找這個私鑰。
選擇Saved to disk選項,點擊Continue。將文件保存爲「PushChat.certSigningRequest」。
2,建立 App ID
每一個使用 APNs 的 iOS 應用必須有一個惟一的 App ID。在本步驟中,你將學到如何建立推送通知中要用到的App ID。
1. 登陸iPhoneDeveloper Program:http://developer.apple.com/iphone/。點擊頁面右邊的「 iPhone Developer Program Portal 」(圖4):
2. 首先看到的是歡迎頁面(圖5):
3. 點擊左邊的「App ID」,而後點擊右邊的「New App ID」按鈕(圖6):
4. 在 Description 欄輸入「PushAppID」,在「Bundle Seed ID」欄中選擇「Generate New」。在「Bundle Identifier」欄,輸入「net.learn2develop.MyPushApp」,而後點擊「Submit」(圖7):
5. 如今你應該能看到所建立的 App ID 了(圖8):
配置 App
一旦建立了 App ID,你還要爲推送通知對 App ID 進行一些配置。
1. 點擊App ID 右邊的 Configure 連接,會看到以下選項(圖9):
勾選「Enable for Apple Push Notificationservice」,點擊「Development Push SSL Certificate」右邊的「Configure」按鈕。
2. 接下來你會看到「Apple Push Notification service SSL Certificate Assistant」頁面。點擊Continue(圖10):
3. 點擊Choose File 按鈕,選擇前面保存的證書請求文件存放地址。點擊 Generate(圖11):
4. 你的SSL 證書會被生成。點擊 Continue(圖12):
5. 點擊Download Now 按鈕,下載 SSL 證書。點擊 Done(圖13):
6. 下載的 SSL 證書文件名爲 aps.developer.identity.cer。雙擊,將證書安裝到鑰匙串中(圖14)。這個證書會在你的程序中用到,它容許程序接收 APNs 發送來的推送通知。
3,建立 Provisioning Profile
接下來,須要建立 provisioning profile 以便容許應用程序安裝到真實設備上。
1. 回到iPhone Development Program Portal,點擊 Provisioning 欄,點擊 New Profile 按鈕(圖15):
2. Profile Name 欄輸入 MyDevicesProfile,在 App ID 欄選擇 PushAppID。在Devices 欄,勾選全部你想激活的設備(在 iPhone Developer Program Portal 的 Devices 頁中註冊的全部設備)。點擊 Submit(圖16)。
3. provisioning profile 會等待審覈。幾秒鐘後,它會顯示在頁面上。點擊Download 按鈕下載該 provisioning profile(圖17):
4. 下載下來的provisioning profile 名爲 MydevicesProfile.mobileprovision。
4,激活設備:建立 provision profile 後,你能夠將它安裝到真實設備中。
--------------------------------------------------
你的app能夠查看哪些推送類型被啓用,用如下代碼來查看
UIRemoteNotificationType enabledTypes = [[UIApplication sharedApplication] enabledRemoteNotificationTypes];
爲了能收到推送消息,咱們還要在app中添加一些內容。將下列代碼添加到PushChatAppDelegate.m中:
- (void)application:(UIApplication*)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData*)deviceToken{ NSLog(@」My token is: %@」, deviceToken);}- (void)application:(UIApplication*)application didFailToRegisterForRemoteNotificationsWithError:(NSError*)error{ NSLog(@"Failed to get token, error: %@", error); }
當你的應用程序註冊遠程通知時,它將會嘗試得到一個「設備標記(device token)」。
這是一個32字節數字,標識你的設備的惟一性。 能夠把device token理解爲推送消息的接收地址。
再次運行程序,你應該能在Xcode的控制檯窗口看到下面這個:
My token is:
<740f4707 bebcf74f 9b7c25d4 8e335894 5f6aa01d a5ddb387 462c7eaf 61bb78ad>
這個標識是一個封裝的二進制數據結構,裝入一個NSData對象裏。蘋果不但願你看見它的內部信息,就咱們而言知道它是32字節長就夠了。
正如你上面所看到的,標識也可用64位十六進制字符表示,咱們將用這種格式使用設備標識,固然還要去掉分隔符和空格。
若是你在模擬器上運行這個程序,因爲你的模擬器不支持推送通知,didFailToRegisterForRemoteNotificationsWithError方法將被調用。
這個應用就是這樣。還有一件事要作,以後咱們立刻就能夠看到一些推送通知,當即行動!
我以前已經提到了幾回,你須要建立一個服務器,它將推送通知給你的app。
第一次測試程序,咱們不會去創建一個服務器。相反,我會給大家一個很是簡單的PHP腳本,
,來創建一個鏈接到APNS併發送一個推送通知到您所指定的設備。你能夠直接在mac電腦上運行這個腳本
下載這些SimplePush代碼並解壓縮,你須要在simplepush.php作些改變。
//把你的設備標識寫在這裏(沒有空格):$deviceToken = '0f744707bebcf74f9b7c25d48e3358945f6aa01da5ddb387462c7eaf61bbad78'; //密碼放在這裏$passphrase = 'pushchat'; // 把你的推送消息放在這裏:$message = 'My first push notification!';
你須要從app中拷貝device token到$deviceToken變量。肯定刪掉了空格以及分隔符。它應該是64位的十六進制字符。把你私鑰密碼短語放到$passphrase變量,以及你想發送的信息放到$message中。
拷貝你的ck.pem 文件到SimplePush目錄,記住,這個ck.pem文件同時包含你的證書和私鑰。
而後打開一個終端並鍵入:
若是一切順利,腳本應該會顯示:
Connected to APNS
Message successfully delivered
注意, 當應用程序是開着的你不會看到任何東西。消息傳過來了,可是咱們在app中沒有作任何處理消息的方法。
若是顯示一些錯誤信息,simplepush.php腳本退出,檢查你是否正確製做PEM文件,
如今,腳本究竟作了什麼並不重要。在這個系列的第二部分,咱們會創建一個真正的推送服務器,到那時候咱們會就此作更多的說明。
此時,你已經成功創建了一個app來接收推送通知,而且經過自定義的PHP代碼發送了第一條推送通知。
----------------------
建立 Push Notification Provider
Push Notification Provider 是一個應用程序,用於經過 APNs 發送推送通知給 iPhone 應用。
經過 APNs 發送推送通知有幾個步驟:
1. 使用前面建立的 SSL 證書與 APNs 通信;
2. 構造所要發送的消息載體;
3. 發送載體到APNs;
APNs 是一個基於流的 TCP socket,你的 provider 以 SSL 協議與其通信。推送通知(包括載體)是以二進制流的方式發送的。和APNs 創建鏈接後,你能夠維持該鏈接並在鏈接中斷以前發送多個通知。
技巧: 應避免每發送一次推送通知就創建、關閉一次鏈接。頻繁的創建、關閉鏈接可能會被 APNs 認爲是 DOS ***,從而拒絕發送 provider 的推送通知發送請求。
一個推送通知消息的格式如圖24 所示:
更多細節,請參考 Apple Push Notification Service Programming Guide。
載體(payload)是 JSON 字符串(最長 256 字節),封裝了你發送給 iOS 應用的信息。這是一個 payload 的例子:
{
"aps": {
"alert" : "Yougot a new message!" ,
"badge" : 5,
"sound" : "beep.wav"},
"acme1" : "bar",
"acme2" : 42
}
寫provider以前,咱們須要生成php Push Notification sender須要的證書文件:
1)在Keychain Access.app裏選定這個新證書(Apple Development Push Services*),導出到桌面,保存爲Certificates.p12.
2)而後運行以下命令:
見第一部分。
下面是一個簡單的push notification proivder寫法:
<span style="font-size:16px;"><?php
$deviceToken = '38c866dd bb323b39 ffa73487 5e157ee5 a85e0b7ce90d56e9 fe145bcc 6c2c594b'; // masked for security reason
// Passphrase for the private key (ck.pem file)
// $pass = '';
// Get the parameters from http get or from command line
$message = $_GET['message'] or $message = $argv[1] or $message = 'Message received from javacom';
$badge = (int)$_GET['badge'] or $badge = (int)$argv[2];
$sound = $_GET['sound'] or $sound = $argv[3];
// Construct the notification payload
$body = array();
$body['aps'] = array('alert' => $message);
if ($badge)
$body['aps']['badge'] = $badge;
if ($sound)
$body['aps']['sound'] = $sound;
$ctx = stream_context_create();
stream_context_set_option($ctx, 'ssl', 'local_cert', 'ck.pem');
// assume the private key passphase was removed.
// stream_context_set_option($ctx, 'ssl', 'passphrase', $pass);
$fp = stream_socket_client('ssl://gateway.sandbox.push.apple.com:2195', $err, $errstr, 60, STREAM_CLIENT_CONNECT, $ctx);
if (!$fp) {
print "Failed to connect $err $errstrn";
return;
}
else {
print "Connection OKn";
}
$payload = json_encode($body);
$msg = chr(0) . pack("n",32) . pack('H*', str_replace(' ', '', $deviceToken)) . pack("n",strlen($payload)) . $payload;
print "sending message :" . $payload . "n";
fwrite($fp, $msg);
fclose($fp);
?></span>
運行結果:Connection OKnsending message :{"aps":{"alert":"Message received from javacom"}}n
效果圖在下面。
爲了省去本身編寫 push notification provider 的麻煩,你也可使用 Stefan Hafeneger 寫的一個 Mac OS X 應用程序:PushMeBaby,下載地址
1. 在Xcode 中打開 PushMeBaby。
2. 右擊 Resouces 文件夾,選擇 Add Existing Files…,選擇前面所下載到的aps.developer.identity.cer 文件(圖25)。
3. 在 ApplicationDelegate.m 文件中,修改以下代碼(加粗部分):
- (id)init {
self = [super init];
if(self != nil) {
self.deviceToken = @"38c866dd bb323b39 ffa73487 5e157ee5 a85e0b7ce90d56e9 fe145bcc 6c2c594b";
self.payload = @"{"aps":{"alert":"Yougot a new message!","badge":5,"sound":"beep.wav"},"acme1":"bar","acme2":42}";
self.certificate = [[NSBundle mainBundle]
pathForResource:@"aps_developer_identity" ofType:@"cer"];
}
return self;
}
4. 按下 +R,運行程序。將會問你是否容許使用證書,點擊Always Allow(老是容許)(圖26):
在 iPhone/iPod,確認 ApplePushNotification 程序未運行。點擊 Push 按鈕,會向設備發送一條推送通知。服務器實際上發送了下列消息給APN 服務器:
{
"aps": {
"alert" : "Yougot a new message!" ,
"badge" : 5,
"sound" : "beep.wav"},
"acme1" : "bar",
"acme2" : 42
}
5. 若是消息推送成功,將會在 iPhone/iPod 上出現下圖(圖27):
6. 若是如今按下 +R 調試 ApplePushNotification 程序,而後從 PushMeBaby 中發送一條消息,控制檯會顯示以下輸出:
2009-11-24 21:11:49.182 ApplePushNotification[1461:207]key: acme1, value: bar
2009-11-24 21:11:49.187 ApplePushNotification[1461:207]key: aps, value: {
alert = "You got a new message!";
badge = 5;
sound = "beep.wav";
}
2009-11-24 21:11:49.191 ApplePushNotification[1461:207]key: acme2, value: 42
幾個注意的問題:
1.若是申請ssl 證書時不是用的新的apple id,而是原來已經存在的,那麼設置好以後要把對應的provisioning profile
也更新一下, 而後去下載新的profile替換掉老的,否則運行會有錯。
2.若是你用的是企業版的開發者證書,別人可能沒有權限去申請這個ssl 證書,當你替他申請好證書後,應該把證書和證書對
的私鑰一塊兒發給他,這樣他在本地安裝私鑰時纔會有對應的密鑰。
3.當push notification到達時,程序狀態不一樣,效果也是不同的,通常來講程序能夠分爲下面三種狀態:
1)程序不在運行(後臺和前臺都不在運行)
這時候若是push notification到了,會彈出一個alertview,當你點擊action按鈕時,會啓動程序,並執行程序delegate.m文件裏的
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
方法,因此你能夠在這裏作一些處理:
//看是否有push notification到達,並作相應處理,這個方法和local notification相同,但注意key要對應就行
UILocalNotification * remoteNotification = [launchOptions objectForKey:UIApplicationLaunchOptionsRemoteNotificationKey];
if (remoteNotification) {
//彈出一個alertview,顯示相應信息
UIAlertView * al = [[UIAlertView alloc]initWithTitle:@"receive remote notification!" message:@"hello" delegate:self cancelButtonTitle:@"Ok" otherButtonTitles:nil, nil];
[al show];
[al release];
}
2)程序在運行(不管是在前臺仍是後臺)
當push notification到達時,若是程序在前臺運行並不會彈出alertview,而是直接執行下面方法:
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo {
UIAlertView * al = [[UIAlertView alloc]initWithTitle:@"receive remote notification!" message:@"hey" delegate:self cancelButtonTitle:@"ok" otherButtonTitles:nil, nil];
[al show];
[al release];
}
在這個方法裏你能夠獲取到userInfo字典來進行相應處理。
若是程序是在後臺運行,則會彈出一個alertview,當你點擊action按鈕,也會執行上面同樣的方法。
因此若是你想要程序在push notification到達時,針對前臺和後臺運行作區分處理,你能夠在上面方法裏先作一個狀態的
判斷:
//能夠根據application狀態來判斷,程序當前是在前臺仍是後臺
UIApplicationState state = [application applicationState];
if (state == UIApplicationStateInactive) {
// Application was in the background when notification
// was delivered.
}
本文轉載自:http://blog.csdn.net/chowpan/article/details/17927747