蘋果推送通知服務APNs編程(轉)

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 {

    NSString *str = [NSString

       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. 
        } 
相關文章
相關標籤/搜索