iOS推送APNS

1、背景概述:

1,環境配置

APNS:Apple Push Notification Service。本文對推送相關概念再也不贅述,只側重完整流程。 php

Demo 開發環境:Mac os 10.9.4  ,Xcode 6.0.1 ;測試設備:iphone 4s(ios 7.1)html

服務端開發環境:mac 10.9.4  + php 5.4.2四、node

Demo 下載地址:點擊打開連接ios

2,APNS 相關博客

如對apns相關概念不清楚,可參考如下幾個博客:(博客中部份內容重複,但整體來講,通讀一遍,仍是大有裨益的)程序員

 http://cshbbrain.iteye.com/blog/1859810  =》IOS 基於APNS消息推送原理與實現(JAVA後臺)web

http://www.cnblogs.com/qq78292959/archive/2012/07/16/2593651.html   =》iOS消息推送機制的實現
apache

http://blog.csdn.net/xunyn/article/details/8243573  =》APNS編程----iOS真機測試消息推送
編程

http://blog.csdn.net/wswqiang/article/details/8208581  =》IOS APNS 處理
json

http://eric-gao.iteye.com/blog/1567777  =》 IOS PEM 文件的生成瀏覽器

http://www.36coder.com/study/996.html  =》PHP 實現APNS 推送

http://blog.csdn.net/sxfcct/article/details/7939082  =》 APNS 相關總結(推薦)

3,APNS 接口

消息推送:

開發接口:gateway.sandbox.push.apple.com:2195

發佈接口:gateway.push.apple.com:2195

反饋服務:

開發接口:feedback.sandbox.push.apple.com:2196

發佈接口:產品接口:feedback.push.apple.com:2196

2、製做Push證書和Pem文件

1,新建一個App ID

新建流程再也不贅述,這裏只提醒兩點:1》App ID Suffix 中,必定要選擇Explicit App ID;2》App Services 中,記得勾選Push Notifications。這裏以新建一個id爲:com.eversoft.PushDemo 爲例。

2,配置push開發證書

在App IDs中,選中剛纔新建的App id:com.eversoft.PushDemo ,單擊,展開詳細信息屬性。


在詳細信息屬性中,單擊下方的「Edit」按鈕,

在新打開的編輯界面,單擊「Create Certificate」,


在新打開的界面中,會提示咱們,建立一個csr 證書籤名請求文件。具體的建立步驟,界面中已經給出了詳細的英文說明。


在進行下一步以前,咱們先按照英文說明,建立一個 CSR 文件。

  • 在mac電腦上,打開應用程序  keychain(鑰匙串訪問);

  • 在keychain菜單欄中,依次選擇「鑰匙串訪問」=》「證書助理」=》「從證書頒發機構請求證書」;

  • 在新打開的「證書助理」界面中,填寫用戶電子郵件地址,經常使用名稱,CA電子郵件地址,這兩個郵件地址直接填寫你的蘋果帳號的郵件地址便可,而後選擇「存儲到磁盤」,而後點擊「繼續」;

  • 選擇CSR文件保存位置,「存儲」便可。至此, CSR 文件,製做完成。


回到剛纔咱們的web頁面上,點擊「Continue」,進入下一頁面;新的頁面中,會要求咱們上傳剛纔製做的csr文件,選擇「Choose File」,找到咱們剛纔存儲的csr文件,單擊「打開」,最後,點擊頁面上的「Generate」按鈕,到此,開發使用的push證書製做完畢。

證書生成成功後,選擇「Download」,將製做好的證書下載到本地。而後雙擊下載的證書aps_development.cer,雙擊後,證書就自動導入到鑰匙串中了。

打開 keychain,左側鑰匙串選擇「登陸」,種類選擇「全部項目」,在右側窗口中,選中剛纔導入的Apple Development IOS Push Services證書(不用選中專用密鑰),右鍵,選擇導出,命名爲:ck.p12 ,存儲時,會提示輸入保護密碼,這裏爲演示方便,就輸入了123456。以後又會要求輸入電腦登陸密碼,輸入便可。


3,生成PEM文件

最後,打開終端,執行如下命令,生成pem文件

openssl pkcs12 -in ck.p12 -out ck.pem -nodes 

執行時,會要求輸入導入密碼,這裏輸入剛纔的保護密碼123456便可。


到此,php 服務端使用的pem證書就製做完畢了。

Development PP 文件製做再也不贅述。

3、IOS 代碼編寫

首先,在AppDelegate.m 中:

1,註冊通知

[objc] view plaincopyprint?在CODE上查看代碼片派生到個人代碼片

  1. - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {  

  2.     // Override point for customization after application launch.  

  3.     ViewController *mainCtrl=[[ViewController alloc] init];  

  4.     self.window.rootViewController=mainCtrl;  

  5.       

  6.     //註冊通知  

  7.     if ([UIDevice currentDevice].systemVersion.doubleValue<8.0) {  

  8.         [[UIApplication sharedApplication] registerForRemoteNotificationTypes:(UIRemoteNotificationTypeAlert | UIRemoteNotificationTypeSound | UIRemoteNotificationTypeBadge)];  

  9.     }  

  10.     else {  

  11.         [[UIApplication sharedApplication] registerForRemoteNotifications];  

  12.         [[UIApplication sharedApplication] registerUserNotificationSettings:[UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeBadge|UIUserNotificationTypeSound|UIUserNotificationTypeAlert categories:nil]];  

  13.     }  

  14.       

  15.     //判斷是否由遠程消息通知觸發應用程序啓動  

  16.     if (launchOptions) {  

  17.         //獲取應用程序消息通知標記數(即小紅圈中的數字)  

  18.         NSInteger badge = [UIApplication sharedApplication].applicationIconBadgeNumber;  

  19.         if (badge>0) {  

  20.             //若是應用程序消息通知標記數(即小紅圈中的數字)大於0,清除標記。  

  21.             badge--;  

  22.             //清除標記。清除小紅圈中數字,小紅圈中數字爲0,小紅圈纔會消除。  

  23.             [UIApplication sharedApplication].applicationIconBadgeNumber = badge;  

  24.             NSDictionary *pushInfo = [launchOptions objectForKey:@"UIApplicationLaunchOptionsRemoteNotificationKey"];  

  25.               

  26.             //獲取推送詳情  

  27.             NSString *pushString = [NSString stringWithFormat:@"%@",[pushInfo  objectForKey:@"aps"]];  

  28.             UIAlertView *alert=[[UIAlertView alloc] initWithTitle:@"finish Loaunch" message:pushString delegate:nil cancelButtonTitle:@"cancel" otherButtonTitles:nil, nil nil];  

  29.             [alert show];  

  30.         }  

  31.     }  

  32.       

  33.     return YES;  

  34. }  


2,註冊通知後,獲取device token

[objc] view plaincopyprint?在CODE上查看代碼片派生到個人代碼片

  1. - (void)application:(UIApplication *)app didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {  

  2.     NSString *token = [NSString stringWithFormat:@"%@", deviceToken];  

  3.     NSLog(@"My token is:%@", token);  

  4.     //這裏應將device token發送到服務器端  

  5. }  

  6.   

  7. - (void)application:(UIApplication *)app didFailToRegisterForRemoteNotificationsWithError:(NSError *)error {  

  8.     NSString *error_str = [NSString stringWithFormat@"%@", error];  

  9.     NSLog(@"Failed to get token, error:%@", error_str);  

  10. }  


3,接收推送通知

[objc] view plaincopyprint?在CODE上查看代碼片派生到個人代碼片

  1. - (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo  

  2. {  

  3.     [UIApplication sharedApplication].applicationIconBadgeNumber=0;  

  4.     for (id key in userInfo) {  

  5.         NSLog(@"key: %@, value: %@", key, [userInfo objectForKey:key]);  

  6.     }  

  7.     /* eg. 

  8.     key: aps, value: { 

  9.         alert = "\U8fd9\U662f\U4e00\U6761\U6d4b\U8bd5\U4fe1\U606f"; 

  10.         badge = 1; 

  11.         sound = default; 

  12.     } 

  13.      */  

  14.     UIAlertView *alert=[[UIAlertView alloc] initWithTitle:@"remote notification" message:userInfo[@"aps"][@"alert"] delegate:nil cancelButtonTitle:@"cancel" otherButtonTitles:nil, nil nil];  

  15.     [alert show];  

  16. }  


注意:app 前臺運行時,會調用 remote notification;app後臺運行時,點擊提醒框,會調用remote notification,點擊app 圖標,不調用remote notification,沒反應;app 沒有運行時,點擊提醒框,finishLaunching   中,launchOptions 傳參,點擊app 圖標,launchOptions 不傳參,不調用remote notification。

4、服務器端代碼編寫

此章不在IOS程序員職責範圍以內,故只給出示例代碼,不作深刻討論。

1,php 源碼:

[php] view plaincopyprint?在CODE上查看代碼片派生到個人代碼片

  1. <!DOCTYPE html>  

  2. <html>  

  3. <head>  

  4. <meta http-equiv="content-type" content="text/html;charset=utf-8">  

  5. <title>APNS</title>  

  6. </head>  

  7. <body>  

  8. <?php  

  9. /** 

  10. * @file apns.php 

  11. * @synopsis  apple APNS class 

  12. * @author Yee, <rlk002@gmail.com> 

  13. * @version 1.0 

  14. * @date 2012-09-17 11:27:59 

  15. */  

  16.     class APNS  

  17.     {  

  18.         const ENVIRONMENT_PRODUCTION = 0;  

  19.         const ENVIRONMENT_SANDBOX = 1;  

  20.         const DEVICE_BINARY_SIZE = 32;  

  21.         const CONNECT_RETRY_INTERVAL = 1000000;  

  22.         const SOCKET_SELECT_TIMEOUT = 1000000;  

  23.         const COMMAND_PUSH = 1;  

  24.         const STATUS_CODE_INTERNAL_ERROR = 999;  

  25.         const ERROR_RESPONSE_SIZE = 6;  

  26.         const ERROR_RESPONSE_COMMAND = 8;  

  27.         const PAYLOAD_MAXIMUM_SIZE = 256;  

  28.         const APPLE_RESERVED_NAMESPACE = 'aps';  

  29.         protected $_environment;  

  30.         protected $_providerCertificateFile;  

  31.         protected $_rootCertificationAuthorityFile;  

  32.         protected $_connectTimeout;  

  33.         protected $_connectRetryTimes = 3;  

  34.         protected $_connectRetryInterval;  

  35.         protected $_socketSelectTimeout;  

  36.         protected $_hSocket;  

  37.         protected $_deviceTokens = array();  

  38.         protected $_text;  

  39.         protected $_badge;  

  40.         protected $_sound;  

  41.         protected $_customProperties;  

  42.         protected $_expiryValue = 604800;  

  43.         protected $_customIdentifier;  

  44.         protected $_autoAdjustLongPayload = true;  

  45.         protected $asurls = array('ssl://gateway.push.apple.com:2195','ssl://gateway.sandbox.push.apple.com:2195');  

  46.         protected $_errorResponseMessages = array  

  47.                             (  

  48.                                 0   => 'No errors encountered',  

  49.                                 1 => 'Processing error',  

  50.                                 2 => 'Missing device token',  

  51.                                 3 => 'Missing topic',  

  52.                                 4 => 'Missing payload',  

  53.                                 5 => 'Invalid token size',  

  54.                                 6 => 'Invalid topic size',  

  55.                                 7 => 'Invalid payload size',  

  56.                                 8 => 'Invalid token',  

  57.                                 self::STATUS_CODE_INTERNAL_ERROR => 'Internal error'  

  58.                             );  

  59.           

  60.         function __construct($environment,$providerCertificateFile)  

  61.         {  

  62.             if($environment != self::ENVIRONMENT_PRODUCTION && $environment != self::ENVIRONMENT_SANDBOX)   

  63.             {  

  64.                 throw new Exception(  

  65.                     "Invalid environment '{$environment}'"  

  66.                 );  

  67.             }  

  68.             $this->_environment = $environment;  

  69.   

  70.             if(!is_readable($providerCertificateFile))   

  71.             {  

  72.                 throw new Exception(  

  73.                     "Unable to read certificate file '{$providerCertificateFile}'"  

  74.                 );  

  75.             }  

  76.             $this->_providerCertificateFile = $providerCertificateFile;  

  77.   

  78.             $this->_connectTimeout = @ini_get("default_socket_timeout");  

  79.             $this->_connectRetryInterval = self::CONNECT_RETRY_INTERVAL;  

  80.             $this->_socketSelectTimeout = self::SOCKET_SELECT_TIMEOUT;  

  81.         }  

  82.   

  83.         public function setRCA($rootCertificationAuthorityFile)  

  84.         {  

  85.             if(!is_readable($rootCertificationAuthorityFile))   

  86.             {  

  87.                 throw new Exception(  

  88.                     "Unable to read Certificate Authority file '{$rootCertificationAuthorityFile}'"  

  89.                 );  

  90.             }  

  91.             $this->_rootCertificationAuthorityFile = $rootCertificationAuthorityFile;  

  92.         }  

  93.   

  94.         public function getRCA()  

  95.         {  

  96.             return $this->_rootCertificationAuthorityFile;  

  97.         }  

  98.   

  99.         protected function _connect()  

  100.         {  

  101.             $sURL = $this->asurls[$this->_environment];  

  102.             $streamContext = stream_context_create(  

  103.                 array  

  104.                     (  

  105.                         'ssl' => array  

  106.                         (  

  107.                             'verify_peer' => isset($this->_rootCertificationAuthorityFile),  

  108.                             'cafile' => $this->_rootCertificationAuthorityFile,  

  109.                             'local_cert' => $this->_providerCertificateFile  

  110.                         )  

  111.                     )  

  112.                 );  

  113.   

  114.             $this->_hSocket = @stream_socket_client($sURL,$nError,$sError,$this->_connectTimeout,STREAM_CLIENT_CONNECT, $streamContext);  

  115.   

  116.             if (!$this->_hSocket)   

  117.             {  

  118.                 throw new Exception  

  119.                 (  

  120.                     "Unable to connect to '{$sURL}': {$sError} ({$nError})"  

  121.                 );  

  122.             }  

  123.             stream_set_blocking($this->_hSocket, 0);  

  124.             stream_set_write_buffer($this->_hSocket, 0);  

  125.             return true;  

  126.         }  

  127.   

  128.         public function connect()  

  129.         {  

  130.             $bConnected = false;  

  131.             $retry = 0;  

  132.             while(!$bConnected)   

  133.             {  

  134.                 try   

  135.                 {  

  136.                     $bConnected = $this->_connect();  

  137.                 }catch (Exception $e)   

  138.                 {  

  139.                     if ($nRetry >= $this->_connectRetryTimes)   

  140.                     {  

  141.                         throw $e;  

  142.                     }else   

  143.                     {  

  144.                         usleep($this->_nConnectRetryInterval);  

  145.                     }  

  146.                 }  

  147.                 $retry++;  

  148.             }  

  149.         }  

  150.   

  151.         public function disconnect()  

  152.         {  

  153.             if (is_resource($this->_hSocket))   

  154.             {  

  155.                 return fclose($this->_hSocket);  

  156.             }  

  157.             return false;  

  158.         }  

  159.   

  160.         protected function getBinaryNotification($deviceToken$payload$messageID = 0, $Expire = 604800)  

  161.         {  

  162.             $tokenLength = strlen($deviceToken);  

  163.             $payloadLength = strlen($payload);  

  164.   

  165.             $ret  = pack('CNNnH*', self::COMMAND_PUSH, $messageID$Expire > 0 ? time() + $Expire : 0, self::DEVICE_BINARY_SIZE, $deviceToken);  

  166.             $ret .= pack('n'$payloadLength);  

  167.             $ret .= $payload;  

  168.             return $ret;  

  169.         }  

  170.   

  171.         protected function readErrorMessage()  

  172.         {  

  173.             $errorResponse = @fread($this->_hSocket, self::ERROR_RESPONSE_SIZE);  

  174.             if ($errorResponse === false || strlen($errorResponse) != self::ERROR_RESPONSE_SIZE)   

  175.             {  

  176.                 return;  

  177.             }  

  178.             $errorResponse = $this->parseErrorMessage($errorResponse);  

  179.             if (!is_array($errorResponse) || empty($errorResponse))   

  180.             {  

  181.                 return;  

  182.             }  

  183.             if (!isset($errorResponse['command'], $errorResponse['statusCode'], $errorResponse['identifier']))   

  184.             {  

  185.                 return;  

  186.             }  

  187.             if ($errorResponse['command'] != self::ERROR_RESPONSE_COMMAND)   

  188.             {  

  189.                 return;  

  190.             }  

  191.             $errorResponse['timeline'] = time();  

  192.             $errorResponse['statusMessage'] = 'None (unknown)';  

  193.             if (isset($this->_aErrorResponseMessages[$errorResponse['statusCode']]))   

  194.             {  

  195.                 $errorResponse['statusMessage'] = $this->_errorResponseMessages[$errorResponse['statusCode']];  

  196.             }  

  197.             return $errorResponse;  

  198.         }  

  199.   

  200.         protected function parseErrorMessage($errorMessage)  

  201.         {  

  202.             return unpack('Ccommand/CstatusCode/Nidentifier'$errorMessage);  

  203.         }  

  204.   

  205.         public function send()  

  206.         {  

  207.             if (!$this->_hSocket)   

  208.             {  

  209.                 throw new Exception  

  210.                 (  

  211.                     'Not connected to Push Notification Service'  

  212.                 );  

  213.             }  

  214.             $sendCount = $this->getDTNumber();  

  215.             $messagePayload = $this->getPayload();  

  216.             foreach($this->_deviceTokens AS $key => $value)  

  217.             {  

  218.                 $apnsMessage = $this->getBinaryNotification($value$messagePayload$messageID = 0, $Expire = 604800);  

  219.                 $nLen = strlen($apnsMessage);  

  220.                 $aErrorMessage = null;  

  221.                 if ($nLen !== ($nWritten = (int)@fwrite($this->_hSocket, $apnsMessage)))   

  222.                 {  

  223.                     $aErrorMessage = array  

  224.                     (  

  225.                         'identifier' => $key,  

  226.                         'statusCode' => self::STATUS_CODE_INTERNAL_ERROR,  

  227.                         'statusMessage' => sprintf('%s (%d bytes written instead of %d bytes)',$this->_errorResponseMessages[self::STATUS_CODE_INTERNAL_ERROR], $nWritten$nLen)  

  228.                     );  

  229.                 }  

  230.             }  

  231.         }  

  232.   

  233.   

  234.         public function addDT($deviceToken)  

  235.         {  

  236.             if (!preg_match('~^[a-f0-9]{64}$~i'$deviceToken))   

  237.             {  

  238.                 throw new Exception  

  239.                 (  

  240.                     "Invalid device token '{$deviceToken}'"  

  241.                 );  

  242.             }  

  243.             $this->_deviceTokens[] = $deviceToken;  

  244.         }         

  245.           

  246.         public function getDTNumber()  

  247.         {  

  248.             return count($this->_deviceTokens);  

  249.         }  

  250.   

  251.         public function setText($text)  

  252.         {  

  253.             $this->_text = $text;  

  254.         }  

  255.   

  256.         public function getText()  

  257.         {  

  258.             return $this->_text;  

  259.         }  

  260.   

  261.         public function setBadge($badge)  

  262.         {  

  263.             if (!is_int($badge))   

  264.             {  

  265.                 throw new Exception  

  266.                 (  

  267.                     "Invalid badge number '{$badge}'"  

  268.                 );  

  269.             }  

  270.             $this->_badge = $badge;  

  271.         }  

  272.   

  273.         public function getBadge()  

  274.         {  

  275.             return $this->_badge;  

  276.         }  

  277.   

  278.         public function setSound($sound = 'default')  

  279.         {  

  280.             $this->_sound = $sound;  

  281.         }  

  282.   

  283.         public function getSound()  

  284.         {  

  285.             return $this->_sound;  

  286.         }  

  287.   

  288.         public function setCP($name$value)  

  289.         {  

  290.             if ($name == self::APPLE_RESERVED_NAMESPACE)   

  291.             {  

  292.                 throw new Exception  

  293.                 (  

  294.                     "Property name '" . self::APPLE_RESERVED_NAMESPACE . "' can not be used for custom property."  

  295.                 );  

  296.             }  

  297.             $this->_customProperties[trim($name)] = $value;  

  298.         }  

  299.   

  300.         protected function _getPayload()  

  301.         {  

  302.             $aPayload[self::APPLE_RESERVED_NAMESPACE] = array();  

  303.   

  304.             if (isset($this->_text))   

  305.             {  

  306.                 $aPayload[self::APPLE_RESERVED_NAMESPACE]['alert'] = (string)$this->_text;  

  307.             }  

  308.             if (isset($this->_badge) && $this->_badge > 0)   

  309.             {  

  310.                 $aPayload[self::APPLE_RESERVED_NAMESPACE]['badge'] = (int)$this->_badge;  

  311.             }  

  312.             if (isset($this->_sound))   

  313.             {  

  314.                 $aPayload[self::APPLE_RESERVED_NAMESPACE]['sound'] = (string)$this->_sound;  

  315.             }  

  316.   

  317.             if (is_array($this->_customProperties))   

  318.             {  

  319.                 foreach($this->_customProperties as $propertyName => $propertyValue)   

  320.                 {  

  321.                     $aPayload[$propertyName] = $propertyValue;  

  322.                 }  

  323.             }  

  324.             return $aPayload;  

  325.         }  

  326.   

  327.         public function setExpiry($expiryValue)  

  328.         {  

  329.             if (!is_int($expiryValue))   

  330.             {  

  331.                 throw new Exception  

  332.                 (  

  333.                     "Invalid seconds number '{$expiryValue}'"  

  334.                 );  

  335.             }  

  336.             $this->_expiryValue = $expiryValue;  

  337.         }  

  338.   

  339.         public function getExpiry()  

  340.         {  

  341.             return $this->_expiryValue;  

  342.         }  

  343.   

  344.         public function setCustomIdentifier($customIdentifier)  

  345.         {  

  346.             $this->_customIdentifier = $customIdentifier;  

  347.         }  

  348.   

  349.         public function getCustomIdentifier()  

  350.         {  

  351.             return $this->_customIdentifier;  

  352.         }         

  353.   

  354.         public function getPayload()  

  355.         {  

  356.             $sJSONPayload = str_replace  

  357.             (  

  358.                 '"' . self::APPLE_RESERVED_NAMESPACE . '":[]',  

  359.                 '"' . self::APPLE_RESERVED_NAMESPACE . '":{}',  

  360.                 json_encode($this->_getPayload())  

  361.             );  

  362.             $nJSONPayloadLen = strlen($sJSONPayload);  

  363.   

  364.             if ($nJSONPayloadLen > self::PAYLOAD_MAXIMUM_SIZE)  

  365.             {  

  366.                 if ($this->_autoAdjustLongPayload)   

  367.                 {  

  368.                     $maxTextLen = $textLen = strlen($this->_text) - ($nJSONPayloadLen - self::PAYLOAD_MAXIMUM_SIZE);  

  369.                     if ($nMaxTextLen > 0)  

  370.                     {  

  371.                         while (strlen($this->_text = mb_substr($this->_text, 0, --$textLen'UTF-8')) > $maxTextLen);  

  372.                         return $this->getPayload();  

  373.                     }else  

  374.                     {  

  375.                         throw new Exception  

  376.                         (  

  377.                             "JSON Payload is too long: {$nJSONPayloadLen} bytes. Maximum size is " .  

  378.                             self::PAYLOAD_MAXIMUM_SIZE . " bytes. The message text can not be auto-adjusted."  

  379.                         );  

  380.                     }  

  381.                 }else  

  382.                 {  

  383.                     throw new Exception  

  384.                     (  

  385.                         "JSON Payload is too long: {$nJSONPayloadLen} bytes. Maximum size is " .  

  386.                         self::PAYLOAD_MAXIMUM_SIZE . " bytes"  

  387.                     );  

  388.                 }  

  389.             }  

  390.             return $sJSONPayload;  

  391.         }     

  392.     }  

  393.   

  394. ?>  

  395. <?php  

  396. date_default_timezone_set('PRC');  

  397. echo "we are young,test apns.  -".date('Y-m-d h:i:s',time());  

  398.   

  399. $rootpath = 'entrust_root_certification_authority.pem';  //ROOT證書地址  

  400. $cp = 'ck.pem';  //provider證書地址  

  401. $apns = new APNS(1,$cp);  

  402. try  

  403. {  

  404.     //$apns->setRCA($rootpath);  //設置ROOT證書  

  405.     $apns->connect(); //鏈接  

  406.     $apns->addDT('acc5150a4df26507a84f19ba145ca3c1be5842a6177511ce7c43d01badb1bd96');  //加入deviceToken  

  407.     $apns->setText('這是一條測試信息');  //發送內容  

  408.     $apns->setBadge(1);  //設置圖標數  

  409.     $apns->setSound();  //設置聲音  

  410.     $apns->setExpiry(3600);  //過時時間  

  411.     $apns->setCP('custom operation',array('type' => '1','url' => 'http://www.google.com.hk'));  //自定義操做  

  412.     $apns->send();  //發送  

  413.     echo ' sent ok';  

  414. }catch(Exception $e)  

  415. {  

  416.     echo $e;  

  417. }  

  418. ?>  

  419.   

  420. </body>  

  421. </html>  


2,啓動 Apache 

mac 自帶apache,可直接運行php。

打開「終端(terminal)」,輸入 sudo apachectl -v,可顯示Apache的版本;

輸入 sudo apachectl start,這樣Apache就啓動了。

編輯文件 /etc/apache2/httpd.conf  ,  把  LoadModule php5_module libexec/apache2/libphp5.so 前面的註釋去掉;而後重啓apache: sudo apachectl restart

打開Safari瀏覽器地址欄輸入 「http://localhost」,能夠看到內容爲「It works!」的頁面。其位

於「/Library/WebServer/Documents/」下,這就是Apache的默認根目錄。

3,如何調試

將服務器端寫好的apns.php 文件以及生成的 ck.pem 文件,直接拷貝到 /Library/WebServer/Documents/  下,在瀏覽器中,直接瀏覽: http://localhost/apns.php  。這樣消息就發送到了蘋果服務器。

相關文章
相關標籤/搜索