好久沒有寫過博客啦,今天就由本菜鳥給大家做一個簡單的IOSApp消息推送教程吧!
一切從0開始,包含XCode6, IOS8, 以及蘋果開發人員中心最新怎樣注冊應用,申請證書以及下載配置概要文件,相信非常多剛開始接觸ios的人會非常想了解一下。(ps:網上看了一下盡管有非常多講述推送的好教程,我也是看着一步步學會的。可是這些教程的時間都是去年或者更早時期的。對引導新手來說不是非常合適)
第一部分
首先第一步當然是介紹一下蘋果的推送機制(APNS)咯(ps:事實上每一篇教程都有),先來看一張蘋果官方對其推送做出解釋的概要圖。

Provider是給你手機應用發出推送消息的server,而APNS(Apple Push Notification Service)則是蘋果消息推送server。你本地的server當須要給應用推送一條消息的時候,先要將消息發出到蘋果推送server。然后再由蘋果推送server將消息發到安裝了該應用的手機。
接下來再看一張解釋圖:

依據上圖的邏輯我來給大家解釋一下:
1.你的IOS應用須要去注冊APNS消息推送功能。
2.當蘋果APNS推送服收到來自你應用的注冊消息就會返回一串device token給你(非常重要)
3.將應用收到的device Token傳給你本地的Pushserver。
4.當你須要為應用推送消息的時候,你本地的推送server會將消息,以及Device Token打包發送到蘋果的APNS服
5.APNS再將消息推送給目的iphone
第二部分
1.從證書頒發機構頒發證書
打開你mac的鑰匙串訪問:
然后點擊鑰匙串訪問


隨后它會彈出一個窗體用戶電子郵件信息就填寫你蘋果開發人員賬號的名稱就可以(應該是一個郵件名稱),點擊保存到磁盤的選
項。點擊繼續,顯演示樣例如以下:

點擊存儲。文件名稱為:CertificateSigningRequest.certSigningRequest 隨后將他放在一個目錄中我們取名push吧!
第三部分
訪問蘋果開發人員網址:https://developer.apple.com/

選中MemberCenter選項,進入登陸頁面。用你的蘋果開發人員賬號登陸,過一會網頁就會自己主動跳轉到下圖。

點擊紅色所選部分內容進行下一步的操作。

選擇Certificates選項,設置證書,如圖所看到的先解釋一下:
Development選項的作用顧名思義就是用來作為開發使用的證書。Production選項則是用來公布產品使用的,名稱非常陌生是不是。之
前的開發人員網頁是沒有這一選項的,可能是蘋果把他改動了,用這個名稱更加能讓人理解吧(字面上解釋就是產品么)。兩個選項生
成證書的步驟是一樣的,如今我們使用開發人員的選項進行證書的制作。過程例如以下:選擇Development選項:

點擊上面的加號選項,

選擇APNS選項(開發么當然是在沙盒環境下了。模擬真實情況),然后Continue

這個AppID我們在下一部分講怎樣生成,如今我用的是已經生成好的一個應用ID,繼續Continue

這邊就要選擇在鑰匙串訪問環節下載下來的CertificateSigningRequest.certSigningRequest文件了。選擇並生成:

點擊下載。得到aps_development .cer,保存到push文件里去。
第四部分
新建一個AppID,選擇網頁上的AppIDs,然后點擊右上角的 “加號”

App的取名僅僅要依照蘋果要求的就能夠了

然后BundleID是比較重要的,在提交審核以及測試(蘋果的TestFlight)和付費環節都須要用到。也僅僅需依照蘋果要求來寫就好了。

接下來就是對你的應用須要使用蘋果的哪些服務進行選擇即可了,比如廣告。游戲中心,推送,付費等等情況。

最后選擇“Submit”選項,在下一個界面中選擇“done”選項,這樣我們設置AppID的步驟我們就完畢了。
第五部分:生成Provisioning Profiles
這個配置概要文件分為兩種,一種是為開發使用的,另一種則是為公布到appStore上面。

創建公布版的ProvisioningProfile與開發版的流程同樣。點擊Development然后點擊右上角的加號

會進入選擇何種配置概要文件的界面:

我們如今時測試,所以選擇“IOS App Development”的選項,在以下的Distribution公布選項中有兩個選擇,“App Store”以及
“Ad hoc”,你能夠依據以下的描寫敘述選擇你公布所需的選項。點擊Continue進入下一步。

選擇你上一步創建的AppID,點擊Continue 進行下一步

選擇你的開發人員賬號,Continue進行下一步

在這一步上選擇你的設備(你僅僅有在這一步上勾選了你的設備。你才干在設備上用這個簽名進行調試)。關於怎樣將你的設備號加入
進去也是很簡單的,選擇左側的"Devices",然后點擊右上角的加號。在隨后出來的頁面上加入你設備的UUID(在XCode中能夠查
看到)以及name( 能夠隨便取,自己看的懂即可)然后Register一下,照着流程走到最后一步就完畢了。
好咱們繼續回到上面的Provisioning Profile配置環節。當你選好了你的設備后點擊“Continue”進入下一頁。

輸入一個文件名稱(最好是起的能看懂是干嘛的。當然也能夠隨便起),點擊“Generate”進入下一個頁面,在這個頁面中就會有一個下
載button讓你下載這個文件,我們把它下載下來放在Push目錄中。
第六部分
好了。前期的准備工作都已經做完了,如今讓我們開始推送吧!(吼吼)
首先雙擊我們生成的 “aps_development .cer” 文件,進入鑰匙串訪問。找到我們的專用秘鑰(依據在第二部分中從證書機構頒發證書操作中填寫的經常使用名)

我在第二部分填寫的是“silicon”,因為換了一台mac之前安裝的沒有了,之前沒有截圖。所以隨便找了個圖給大家看一下,憑大家的聰明才智應該不難理解吧。
然后右擊導出,會彈出例如以下所看到的的圖。

將他存儲到push目錄中,命名為“push.p12”,在這一步中導出會讓你輸入password並驗證,你能夠自己定義一個password。比如abc123
如今push目錄中應該有幾個文件“aps_development .cer” 。"push.p12",“CertificateSigningRequest.certSigningRequest”以及
剛才下下來的配置概要文件。
接下來我們打開終端將他們生成.pem文件
1.把aps_development .cer文件生成.pcm文件,cd到push目錄下

2.把push.p12文件生成為.pem文件

上邊輸入的password則是你導出證書所設的password,即abc123.接着還會讓你輸入.pem文件的password。還是使用abc123好了,防止混淆。
這樣我們在push目錄中就又得到了兩個文件。PushChatCert.pem和PushChatKey.pem。
3.把PushChatCert.pem和PushChatKey.pem合並為一個pem文件。

在push目錄中又多了一個ck.pem文件。以上我們把須要使用的文件都准備好了
接下來就要測試一下啦。是不是非常激動~
為了測試證書工作的狀況。我們能夠使用“telnet gateway.sandbox.push.apple.com 2195”來檢測一下,假設顯示下圖則表示成功了。

然后,我們使用我們生成的證書和私鑰來設置一個安全的鏈接去鏈接蘋果server
在終端輸入例如以下命令:openssl s_client -connect gateway.sandbox.push.apple.com:2195 -cert PushChatCert.pem -key PushChatKey.pem
須要輸入password(abc123 我們剛才所設置的)。
然后他會返回一系列的數據,這里我就粘貼一部分啦:
CONNECTED(00000003)
depth=1 /C=US/O=Entrust, Inc./OU=www.entrust.net/rpa is incorporated by reference/OU=(c) 2009 Entrust, Inc./CN=Entrust Certification Authority - L1C
verify error:num=20:unable to get local issuer certificate
verify return:0
---
Certificate chain
。。。。。(省略)
。。
。。
。(省略)
。。。
。。(省略)
Start Time: 1416389389
Timeout : 300 (sec)
Verify return code: 0 (ok)
---
測試就到這里啦。。。
第七部分
1.建立推送項目
//
// AppDelegate.m
// TestPushNotifiy
//
// Created by silicon on 14-10-30.
// Copyright (c) 2014年 silicon. All rights reserved.
//
#import "AppDelegate.h"
@implementation AppDelegate
@synthesize mainView = _mainView;
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
if ([application respondsToSelector:@selector(isRegisteredForRemoteNotifications)])
{
//IOS8
//創建UIUserNotificationSettings。並設置消息的顯示類類型
UIUserNotificationSettings *notiSettings = [UIUserNotificationSettings settingsForTypes:(UIUserNotificationTypeBadge | UIUserNotificationTypeAlert | UIRemoteNotificationTypeSound) categories:nil];
[application registerUserNotificationSettings:notiSettings];
} else{ // ios7
[application registerForRemoteNotificationTypes:(UIRemoteNotificationTypeBadge |UIRemoteNotificationTypeSound |UIRemoteNotificationTypeAlert)];
}
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Override point for customization after application launch.
self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
self.mainView = [[MainViewController alloc] initWithNibName:@"MainViewController" bundle:nil];
self.window.rootViewController = self.mainView;
return YES;
}
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)pToken{
NSLog(@"---Token--%@", pToken);
}
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo{
NSLog(@"userInfo == %@",userInfo);
NSString *message = [[userInfo objectForKey:@"aps"]objectForKey:@"alert"];
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"提示" message:message delegate:self cancelButtonTitle:@"取消" otherButtonTitles:@"確定", nil];
[alert show];
}
- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error{
NSLog(@"Regist fail%@",error);
}
- (void)applicationWillResignActive:(UIApplication *)application
{
// Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
// Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
}
- (void)applicationDidEnterBackground:(UIApplication *)application
{
// Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
// If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
}
- (void)applicationWillEnterForeground:(UIApplication *)application
{
// Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.
}
- (void)applicationDidBecomeActive:(UIApplication *)application
{
// Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
}
- (void)applicationWillTerminate:(UIApplication *)application
{
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
}
@end
在appdelegate.m中增加以上代碼,
if ([application respondsToSelector:@selector(isRegisteredForRemoteNotifications)])
{
//IOS8
//創建UIUserNotificationSettings,並設置消息的顯示類類型
UIUserNotificationSettings *notiSettings = [UIUserNotificationSettings settingsForTypes:(UIUserNotificationTypeBadge | UIUserNotificationTypeAlert | UIRemoteNotificationTypeSound) categories:nil];
[application registerUserNotificationSettings:notiSettings];
} else{ // ios7
[application registerForRemoteNotificationTypes:(UIRemoteNotificationTypeBadge |UIRemoteNotificationTypeSound |UIRemoteNotificationTypeAlert)];
} 因為ios8的推送跟ios7及下面的不一樣。所以須要加推斷來注冊消息推送。
函數:
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)pToken{
NSLog(@"---Token--%@", pToken);
}
會接收來自蘋果server給你返回的deviceToken,然后你須要將它加入到你本地的推送server上。(非常重要,決定你的設備能不能接收到推送消息)。
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo{
NSLog(@"userInfo == %@",userInfo);
NSString *message = [[userInfo objectForKey:@"aps"]objectForKey:@"alert"];
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"提示" message:message delegate:self cancelButtonTitle:@"取消" otherButtonTitles:@"確定", nil];
[alert show];
}這個函數則是當設備接收到來自蘋果推送server的消息時觸發的,用來顯示推送消息。
- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error{
NSLog(@"Regist fail%@",error);
} 當注冊失敗時,觸發此函數。
2.PHP服務端
將simplepush.php這個推送腳本也放在push目錄中
<?php // ??
?
???????
deviceToken??????
??
?
?
???
??
$deviceToken = 'c95f661371b085e2517b4c12cc76293522775e5fd9bb1dea17dd80fe85583b41'; // Put your private key's passphrase here: $passphrase = 'abc123'; // Put your alert message here: $message = 'My first push test!'; //////////////////////////////////////////////////////////////////////////////// $ctx = stream_context_create(); stream_context_set_option($ctx, 'ssl', 'local_cert', 'ck.pem'); stream_context_set_option($ctx, 'ssl', 'passphrase', $passphrase); // Open a connection to the APNS server //?
?
?????
?
?? //$fp = stream_socket_client(?ssl://gateway.push.apple.com:2195?, $err, $errstr, 60, //STREAM_CLIENT_CONNECT, $ctx); //??
??
??
?
?
??
?
??appstore?????
?
$fp = stream_socket_client( 'ssl://gateway.sandbox.push.apple.com:2195', $err, $errstr, 60, STREAM_CLIENT_CONNECT|STREAM_CLIENT_PERSISTENT, $ctx); if (!$fp) exit("Failed to connect: $err $errstr" . PHP_EOL); echo 'Connected to APNS' . PHP_EOL; // Create the payload body $body['aps'] = array( 'alert' => $message, 'sound' => 'default' ); // Encode the payload as JSON $payload = json_encode($body); // Build the binary notification $msg = chr(0) . pack('n', 32) . pack('H*', $deviceToken) . pack('n', strlen($payload)) . $payload; // Send it to the server $result = fwrite($fp, $msg, strlen($msg)); if (!$result) echo 'Message not delivered' . PHP_EOL; else echo 'Message successfully delivered' . PHP_EOL; // Close the connection to the server fclose($fp); ?
>
deviceToken填寫你接收到的token,passPhrase則填寫你的ck.pem設置的password。
此刻就是見證奇跡的時候了,使用終端進入到push目錄,在終端輸入 php simplepush.php

若顯示以上提示則表示推送成功了。
附上一張成功圖。

推送就到這邊吧!
感謝這篇博客的指導:http://blog.csdn.net/showhilllee/article/details/8631734
simplepush.php以及XCodeproject我會上傳到我的資源里去,大家能夠去那邊下載。有什么不明確的地方大家能夠留言或者私信我。我會第一之間回復的~
大家能夠關注我的微信公眾號與我互動。相關問題也能夠直接用公眾號聯系我:

