1.推送過程簡介
< 1.iPhone向APNS索取DeviceToken
<2.APNS返回Token
<3.iPhone將獲取的Token上傳至App對應的服務器
<4.服務器將Token和推送的要聞上傳至APNS
<5.APNS將消息推送給iPhone用戶
-
用到的證書文件及生成過程
(1)certSigningRequest文件,該文件在MAC系統中生成,用于在Apple網站上申請推送證書文件。
生成過程:
打開應用程序中的“鑰匙串訪問”軟件,從菜單中選擇 “鑰匙串訪問”-》“證書助理”-》“從證書頒發機構請求證書”,郵箱和名稱隨便填寫,然后選擇保存到磁盤,就可以在本地生成一個CertificateSigningRequest.certSigningRequest文件。(2)注冊一個支持push的app id,后面會用到。
生成過程:
進入developer.apple.com,選擇member center - Certificates, Identifiers & Profiles - Identifiers- App Ids,然后選擇注冊app id,設置appid名稱,同時,app id suffix一欄必須選擇explicit app id,然后設置bundle id,最后勾選 App Services中的 Push Notifications,這樣就可以注冊一個支持push的aphid。
(3) 推送證書cer文件,該文件在developer.apple.com中生成,用于生成服務端需要的文件。
生成過程:
進入developer.apple.com,選擇member center - Certificates, Identifiers & Profiles - Certificates,然后選擇創建certificate,類型分為Development和Product。這里以Development為例,選擇Apple Push Notification service SSL (Sandbox) ,然后下一步,選擇之前生成的支持push的AppId,然后下一步,提交之前創建的CSR文件,再下一步就可以生成cer文件,然后保存到本地。
(4)生成服務端使用的證書文件。如果是使用網上的mac 版PushMeBaby工具,在mac機器上進行推送消息的發送,那么有上面的cer文件就夠了。如果是使用PHP、java/c#開發自己的服務端,那么還需要將上面的cer文件做一個轉換,生成pem文件或者p12文件。
生成php用的pem文件過程為:
首先雙擊前面保存的cer文件,此時會打開“鑰匙串訪問”軟件,里面會出現一個Apple Development IOS push services證書,一個公用密鑰和一個專用秘鑰,秘鑰的名稱與證書助理中填寫的名稱一致。
選中證書,導出為 apns-dev-cert.p12 文件
選中專有秘鑰,導出為apns-dev-key.p12文件
通過終端命令將這些文件轉換為PEM格式:
openssl pkcs12 -clcerts -nokeys -out apns-dev-cert.pem -in apns-dev-cert.p12
openssl pkcs12 -nocerts -out apns-dev-key.pem -in apns-dev-key.p12
最后, 需要將兩個pem文件合并成一個apns-dev.pem文件,此文件在連接到APNS時需要使用:
cat apns-dev-cert.pem apns-dev-key-noenc.pem > apns-dev.pem
生成java/c#用的p12文件過程為:
openssl pkcs12 -clcerts -nokeys -out apns-dev-cert.pem -in apns-dev-cert.p12
openssl pkcs12 -nocerts -out apns-dev-key.pem -in apns-dev-key.p12
openssl pkcs12 -export -in apns-dev-cert.pem -inkey apns-dev-key.pem -certfile CertificateSigningRequest.certSigningRequest -name "push" -out push.p12
(5)生成XCODE使用的provisioning文件,該文件用于真機調試。
生成過程:
進入developer.apple.com,選擇member center - Certificates, Identifiers & Profiles - Provisioning Profiles,然后選擇創建Provisioning file,接著選擇iOS App Development ,下一步選擇AppId,選中之前建立的支持push的appid,接著下一步選擇支持push的certificate,下一步勾選需要支持的device id,最后一步設置provisioning文件的文件名,這樣provisioning文件就生成了。
3. 服務端的開發
(1)如果只是希望在mac電腦上測試一下消息的推送,可以使用PushMeBaby工具,使用起來比較簡單。該工具是開源的,可以從https://github.com/stefanhafeneger/PushMeBaby 下載,代碼的執行過程實際上就是設置一下SSL證書,然后連接APNS,接著發送JSON數據。由于要處理SSL邏輯,因此代碼稍微多點。在使用工具時,將工程資源中的cer文件替換成自己的cer文件,然后將代碼中的deviceToken替換成自己設備的deviceToken即可。
(2)使用php開發服務端
由于php已經內置了ssl模塊,因此使用php連接APNS服務器來發送json的過程實際上是很簡單的,代碼如下:
該文件可以放到服務器中通過瀏覽器來訪問,也可以通過命令行的方式來解釋執行,代碼為:$ php -f Pusher.php
復制以下代碼
<?php
$deviceToken= ‘自己的deviceToken'; //沒有空格
$body = array("aps" => array("alert" => 'message',"badge" => 2,"sound"=>'default')); //推送方式,包含內容和聲音$$ctx = stream_context_create();
//如果在Windows的服務器上,尋找pem路徑會有問題,路徑修改成這樣的方法:
//$pem = dirname(FILE) . '/' . 'apns-dev.pem';
//linux 的服務器直接寫pem的路徑即可
stream_context_set_option($ctx,"ssl","local_cert","apns-dev.pem");
$pass = "xxxxxx";stream_context_set_option($ctx, 'ssl', 'passphrase', $pass);//
//此處有兩個服務器需要選擇,如果是開發測試用,選擇第二名sandbox的服務器并使用Dev的pem證書,如果是正式發布,使用Product的pem并選用正式的服務器
$fp = stream_socket_client("ssl://gateway.push.apple.com:2195", $err, $errstr, 60, STREAM_CLIENT_CONNECT, $ctx);
$fp = stream_socket_client("ssl://gateway.sandbox.push.apple.com:2195", $err, $errstr, 60, STREAM_CLIENT_CONNECT, $ctx);
if (!$fp)
{echo "Failed to connect $err $errstrn";return;}
print "Connection OK\n";
$payload = json_encode($body);$msg = chr(0) . pack("n",32) . pack("H*", str_replace(' ', '', $deviceToken)) . pack("n",strlen($payload)) . $payload;
echo "sending message :" . $payload ."\n";
fwrite($fp, $msg);
fclose($fp);
?>
4. 客戶端的開發
(1)下載前面建立的cer文件和provisioning文件,雙擊,導入到xcode中,在build setting中code signing一欄里選擇這兩個文件的名稱,這樣就可以將支持push的app部署到真機中。
(2)處理推送消息
客戶端對推送消息的處理分兩種情況:
一. 在App沒有運行的情況下,系統收到推送消息,用戶點擊推送消息,啟動App。此時,不會執行前面提到的 didReceiveRemoteNotification函數,而是在App的applicationDidFinishLaunching函數中處理推送,通過以下代碼可以獲取推送消息中的數據: NSDictionary *userInfo =[launchOptionsobjectForKey:UIApplicationLaunchOptionsRemoteNotificationKey];
二. 當APP處于前臺時,系統收到推送消息,此時系統不會彈出消息提示,會直接觸發application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo函數,推送數據在userInfo字典中。
三. 當App處于后臺時,如果系統收到推送消息,當用戶點擊推送消息時,會執行application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo函數,此時AppDelegate中函數執行的順序為:
applicationWillEnterForeground
application:didReceiveRemoteNotification
applicationDidBecomeActive
(3):將設備DeviceToken數據提供給服務商,以供推送到具體的手機上面. 如果遠程推送消息來了,用戶點擊了推送消息,或者應用已經處于打開狀態,系統都會自動調用以下委托:
//點擊某條遠程通知時調用的委托 如果界面處于打開狀態,那么此委托會直接響應
-(void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
{
NSLog(@"遠程通知");
[self PMD_uesPushMessage:userInfo];
}
//第三點里面的介紹的情況是應用程序已經處于運行狀態,上面的委托才會被執行,如果應用程序處于未啟用狀態,此時又需要響應消息,那么需要以下委托處理.
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
//這里處理應用程序如果沒有啟動,但是是通過通知消息打開的,此時可以獲取到消息.
if (launchOptions != nil) {
NSDictionary *userInfo = [launchOptions objectForKey:UIApplicationLaunchOptionsRemoteNotificationKey];
[self doSomeThingWith:userInfo];
}
return YES;
}
5:清空通知中心已有的推送消息,只需要將指定App 的 Badge 設置為 0即可
[[UIApplication sharedApplication ] setApplicationIconBadgeNumber:0];
6:主動推送的字符串必須符合如下Json數組的格式,才能正確推送到手機當中.
{
//自定義參數
\\"userinfo":
{
\\"name":\\"remote notice"
},
//標準寫法
"aps":
{
"alert":
{
"action-loc-key":"Open",//支持多語言
"body":"messgae content"http://消息正文
},
"badge":1,//為App 的icon 標記 具體數值
"sound":"default" //播放的音頻文件,default 表示系統默認的選擇列鈴聲
}
}
{"aps":{"alert":{"action-loc-key": "Open","body": "Hello, world!"},
"badge":9,
"sound":"default"
}
}
deviceToken輸出不能用 [[NSString alloc] initWithData:deviceToken encoding:NSUTF8StringEncoding];
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
{
//傳遞直接傳遞 deviceToken 以下是輸出
NSString *tokenString = [NSString stringWithFormat:@"%@",deviceToken];
NSLog(@"tokenString - %@",tokenString);
}