add by zhj: 下面的幾篇文章也很是好,php
http://www.raywenderlich.com/32960/apple-push-notification-services-in-ios-6-tutorial-part-1html
http://www.raywenderlich.com/32963/apple-push-notification-services-in-ios-6-tutorial-part-2java
http://blog.csdn.net/chenglibin1988/article/details/10051971 此文是上面兩篇文章的翻譯,但沒有翻譯完ios
http://blog.csdn.net/ryantang03/article/details/8482259 json
http://blog.csdn.net/ryantang03/article/details/8540362服務器
原文:http://blog.csdn.net/kmyhy/article/details/6688370網絡
iPhone 對於應用程序在後臺運行有諸多限制(除非你越獄)。所以,當用戶切換到其餘程序後,原先的程序沒法保持運行狀態。對於那些須要保持持續鏈接狀態的應用程序(好比社區網絡應用),將不能收到實時的信息。app
爲解決這一限制,蘋果推出了APNs(蘋果推送通知服務)。APNs 容許設備與蘋果的推送通知服務器保持常鏈接狀態。當你想發送一個推送通知給某個用戶的iPhone上的應用程序時,你可使用 APNs 發送一個推送消息給目標設備上已安裝的某個應用程序。iphone
本文中,你將學到建立使用 APNs 的iOS 應用的詳細步驟。socket
建立證書請求
使用APNs 的第一步是生成一個證書請求,使用該證書請求來申請一個用於開發的 SSL 證書。
1. 打開「鑰匙串訪問」應用程序。
2. 選擇「KeychainAccess -> Certificate Assistant -> Request a Certificate From CertificateAuthority」(如圖1 所示):
3. 輸入所需的信息,勾選「Saved to disk」選項,點擊 Continue(如圖2 所示):
4. 使用默認文件名把證書請求進行保存(圖3):在彈出窗口中,點擊Done。
建立 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 發送來的推送通知。
建立 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。
激活設備
建立 provision profile 後,你能夠將它安裝到真實設備中。
1. 將iPhone 或 iPod 鏈接到 Mac。
2. 把下載下來的 MyDevicesProfile.mobileprovision 文件拖到Dock 欄的 Xcode 圖標上。
3. Xcode 的 Organizer 程序將啓動,選擇當前連機的設備。能夠看到MyDevicesProfile 已自動安裝到設備上了(圖18)。
建立 iPhone 應用程序
1. 打開Xcode,建立 View-Based Application 項目,命名爲 ApplePushNotification。
2. 把一個 WAV 文件(本例是 beep.wav)拖到Xcode 的 Resouces 文件夾(圖19)。
3. 展開Xcode 中的 Targets 項目,選擇ApplePushNotification,按下 ⌘+i,在 info 出口,點擊Properties 標籤欄(圖20):
在 Identifier 文本框,輸入net.learn2develop.MyPushApp.
4. 點擊 Build 標籤欄,在 search 輸入框中鍵入Code Signing。在 Any iPhone OS Device 選項,選擇正確的 profile(圖21):
5. 在 ApplePushNotificationAppDelegate.m 文件中,輸入如下代碼(加粗部分):
#import "ApplePushNotificationAppDelegate.h"
#import "ApplePushNotificationViewController.h"
@implementation ApplePushNotificationAppDelegate
@synthesize window;
@synthesize viewController;
- (void)applicationDidFinishLaunching:(UIApplication*)application {
[window addSubview:viewController.view];
[window makeKeyAndVisible];
NSLog(@"Registeringfor push notifications...");
[[UIApplication sharedApplication]
registerForRemoteNotificationTypes:
(UIRemoteNotificationTypeAlert |
UIRemoteNotificationTypeBadge |
UIRemoteNotificationTypeSound)];
}
- (void)application:(UIApplication*)appdidRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
stringWithFormat:@"Device Token=%@",deviceToken];
NSLog(str);
}
- (void)application:(UIApplication*)appdidFailToRegisterForRemoteNotificationsWithError:(NSError *)err {
NSString *str = [NSStringstringWithFormat: @"Error: %@", err];
NSLog(str);
}
- (void)application:(UIApplication*)application didReceiveRemoteNotification:(NSDictionary *)userInfo {
for (id key in userInfo) {
NSLog(@"key: %@, value: %@", key, [userInfo objectForKey:key]);
}
}
- (void)dealloc {
[viewController release];
[window release];
[super dealloc];
}
@end
6. 按下 ⌘+R 運行程序(在真實設備)。按下 shift+⌘+R 顯示Debugger Console 窗口。查看設備輸出到控制檯的 device token(圖22)。在下圖,device token 是 38c866dd bb323b39 ffa73487 5e157ee5 a85e0b7c e90d56e9fe145bcc 6c2c594b。記下device token(複製、粘貼到一個文本文件裏)
7. 若是查看 iPhone/iPod 上的「Settings」程序,你會發現一個 Notifications 的項(圖23):
建立 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)而後運行以下命令:
1. openssl pkcs12 -clcerts -nokeys -out cert.pem -in Certificates.p12
2. openssl pkcs12 -nocerts -out key.pem -in Certificates.p12
3. openssl rsa -in key.pem -out key.unencrypted.pem
4. cat cert.pem key.unencrypted.pem > ck.pem
下面是一個簡單的push notification proivder寫法:
[php] view plaincopyprint?
<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; /* End of Configurable Items */
$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,而是直接執行下面方法:
/** * Remote Notification Received while application was open. */
- (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.
}