iOS 消息推送 詳解


如果英文好的話,建議查看官方文檔:https://developer.apple.com/library/ios/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/Chapters/ApplePushService.html#//apple_ref/doc/uid/TP40008194-CH100-SW9

什麼是遠程消息推送功能

蘋果給iOS和Mac添加了消息推送的功能,使得我們可以通過後臺服務器給應用程序(APP)發送消息,不管APP是否正在使用,比如郵箱的來件提示功能。這項服務被稱爲Apple Push Notification service(APNs)。裏面一共涉及到四個角色:APP、設備、APNs和應用後臺服務器(Provider),其中APP、後臺服務器和APNs之間使用deviceToken唯一的標識一個用戶。

推送服務的工作流程:

  1. APP向系統註冊推送服務。

  2. 設備從APNs請求deviceToken。

  3. 通過代理方法將deviceToken返回給APP。

  4. APP將deviceToken發送給應用後臺服務器(Provider)。

  5. 應用後臺服務器保存deviceToken,然後在需要推送通知的時候,給APNs發送信息,使用deviceToken標識所要送達的客戶端。

  6. APNs將後臺服務器發過來的數據推送到設備。

  7. 設備將消息分發給應用程序。

在使用推送功能的時候,需要在開發者中心創建支持Push Notification的證書,並且將證書和私鑰用於應用後臺服務器與APNs之間通信。

環境配置

使用推送服務有一些必要條件:

  1. 開發者賬號。

  2. iOS真機(iPhone、iPad、iPod)。

  3. 後臺服務器。

  4. 網絡。

爲了使應用支持推送服務,需要配置Provisioning Profile使它支持Push,和普通的Provisioning Profile文件一樣分爲Development和Production兩個版本。我們使用Development版進行測試。

接下來創建一個用於應用後臺服務器和APNs服務器通信時使用的SSL證書和私鑰。

1 .在鑰匙串訪問工具中獲取證書請求文件(CSR)。

2 .保存請求文件。

3 .從鑰匙串訪問工具中導出私鑰,將它保存爲PushKey.p12,輸入密碼abcde。千萬別把密碼給忘了哈,等下要用的。

4 .登陸iOS Dev Center創建APP ID和*Provisioning Profile*。

5 .創建新的App ID時,要注意開啓Push Notification

6 .最後App ID看起來是這樣的。

7 .到這一步,雖然已經開啓了推送服務,但是還需要進一步配置,點擊Setting按鈕進行設置。

8 .滾動到最下面,需要創建SSL證書(Create Certificate),測試環境使用Development SSL Certificate

9 .查看證書創建步驟和說明,上傳第1步得到的證書請求文件。

10 .下載生成好的證書,命名爲aps_development.cer

到現在爲止,我們已經生成了三個文件:

1、Push.certSigningRequest

2、Push.p12

3、aps_development.cer


接下來就是進行推送測試階段:

到了這裏,我們有多種選擇繼續了。

1 .使用第三方小工具PushMeBaby模擬應用後臺服務器發送推送信息。

2 .搭建應用後臺服務器發送推送信息。

                  


下面先試一試第一種方法,使用PushMeBaby。這是一個開源的Mac小程序,將ApplicationDelegate.m中添上deviceToken和證書的位置。
- (id)init {
    self = [super init];
    if(self != nil) {
        //55e231f0 86257e00 eed93ac6 47b52c78 12abe79f 9c9d1c67 4c770589 36c9a235 ---- 保留空格
        self.deviceToken = @"";
        //推送內容,JSON格式
        self.payload = @"{\"aps\":{\"alert\":\"喬幫主喬幫主喬幫主\",\"badge\":1}}";
        //獲取證書路徑
        self.certificate = [[NSBundle mainBundle] pathForResource:@"aps_development" ofType:@"cer"];
    }
    return self;}

deviceToken的獲取在下面的代碼部分。

一定要記得將剛纔的aps_development.cer證書文件添加到項目中,當然也可以直接將證書路徑賦值給self.certificate。

接下來試一試第二種方法:

發送通知的後臺應用程序如果用php, java 實現,除了需要知道deviceToken之外,還需要一個與APNS連接的證書。

這個證書可以通過我們前面生成的文件中得到。


1)我們使用PHP來發送通知(其實運行PHP並不需要另外搭建服務器和下載程序,Mac默認支持PHP運行,不信到命令行運行一下php)。

這種方式相對來說麻煩一些,但是也是實際使用的時候會採取的方式。我們需要進一步處理私鑰和證書文件。

1 .首先將證書文件和私鑰處理成單個方便使用的pem文件,假設CSR、p12和cer文件都放在桌面上。

$ cd ~/Desktop$ls aps_development.cer
CertificateSigningRequest.certSigningRequest
PushKey.p12

2 .將aps_development.cer轉換爲pem文件。

$ openssl x509 -in aps_development.cer -inform der -out PushCert.pem$ ls
aps_development.cer
CertificateSigningRequest.certSigningRequest
PushCert.pem
PushKey.p12

3 .將p12私鑰文件轉換爲pem文件。

$ openssl pkcs12 -nocerts -out PushKey.pem -in PushKey.p12 
Enter Import Password:
MAC verified OK
Enter PEM pass phrase:
Verifying - Enter PEM pass phrase:

4 .將兩個文件合成同一個。

$ cat PushCert.pem PushKey.pem > ck.pem$ ls
aps_development.cer
CertificateSigningRequest.certSigningRequest
ck.pem
PushCert.pem
PushKey.pem 
PushKey.p12

5 .測試證書是否有效。

$ openssl s_client -connect gateway.sandbox.push.apple.com:2195 -cert PushCert.pem -key PushKey.pem

如果有效的話,會輸出一堆信息,並且建立連接,否則不會成功建立連接。

6 .使用PHP進行測試,下載SimplePush.php,修改文件並填入deviceToken和密碼。在終端運行該代碼。

$ php simplepush.php 
Connected to APNS
Message successfully delivered

成功發送推送消息。

2)JAVA來發送通知

1、將aps_development.cer轉換成aps_development.pem格式

  1. openssl x509 -in aps_development.cer -inform DER -out aps_development.pem -outform PEM  

2、將p12格式的私鑰轉換成pem

  1. openssl pkcs12 -nocerts -out Push_Noenc.pem -in Push.p12  

3、創建p12文件

  1. openssl pkcs12 -export -in aps_development.pem -inkey Push_Noenc.pem -certfile Push.certSigningRequest -name "aps_development" -out aps_development.p12  

這樣我們就得到了在.net或java等後臺應用程序中使用的證書文件:aps_development.p12

核心代碼

import javapns.back.PushNotificationManager;
import javapns.back.SSLConnectionHelper;
import javapns.data.Device;
import javapns.data.PayLoad;
 
public class MainSend
{
    public static void main(String[] args) throws Exception
    {
        try
        {
            //從客戶端獲取的deviceToken
            String deviceToken = "3a20764942e9cb4c4f6249274f12891946bed26131b686b8aa95322faff0ad46";
            System.out.println("Push Start deviceToken:" + deviceToken);
            //定義消息模式
            PayLoad payLoad = new PayLoad();
            payLoad.addAlert("消息推送測試!");
            payLoad.addBadge(4);
            payLoad.addSound("default");
            //註冊deviceToken
            PushNotificationManager pushManager = PushNotificationManager.getInstance();
            pushManager.addDevice("iPhone", deviceToken);
            //連接APNS
            String host = "gateway.sandbox.push.apple.com";
            int port = 2195;
            String path = "/Users/iMilo/Work.localized/iShop/project/service/iPush/";
            String certificatePath = (path + "src/ipush/iPush.p12");
            //certificatePath 步驟一中生成的*.p12文件位置
            String certificatePassword = "Love24mm";
            pushManager.initializeConnection(host, port, certificatePath, certificatePassword, SSLConnectionHelper.KEYSTORE_TYPE_PKCS12);
            //發送推送
            Device client = pushManager.getDevice("iPhone");
            pushManager.sendNotification(client, payLoad);
            //停止連接APNS
            pushManager.stopConnection();
            //刪除deviceToken
            pushManager.removeDevice("iPhone");
            System.out.println("Push End");
        }
        catch (Exception ex)
        {
            ex.printStackTrace();
        }
    }
}

iOS端代碼實現

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    //判斷是否註冊了遠程通知
    if (![application isRegisteredForRemoteNotifications]) {
        UIUserNotificationSettings *uns = [UIUserNotificationSettings settingsForTypes:(UIUserNotificationTypeAlert|UIUserNotificationTypeBadge|UIUserNotificationTypeSound) categories:nil];
        [application registerUserNotificationSettings:uns];
        //註冊遠程通知
        [application registerForRemoteNotifications];
    }

    return YES;}

//獲取DeviceToken成功
- (void)application:(UIApplication *)application
didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
{
    NSLog(@"DeviceToken: {%@}",deviceToken);
    //這裏進行的操作,是將Device Token發送到服務端
}
 
//註冊消息推送失敗
- (void)application:(UIApplication *)application
didFailToRegisterForRemoteNotificationsWithError:(NSError *)error
{
    NSLog(@"Register Remote Notifications error:{%@}",[errorlocalizedDescription]);
}
 
//處理收到的消息推送
- (void)application:(UIApplication *)application
didReceiveRemoteNotification:(NSDictionary *)userInfo
{
    NSLog(@"Receive remote notification : %@",userInfo);
    UIAlertView *alert =
    [[UIAlertView alloc] initWithTitle:@"溫馨提示"
                               message:@"推送成功!"
                              delegate:nil
                     cancelButtonTitle:@"確定"
                     otherButtonTitles:nil];
    [alert show];
    [alert release];
}

下面附上另外一份比較詳細的文章,感謝這位博友分享http://blog.csdn.net/showhilllee/article/details/8631734

另一位博友的三篇文章:(

http://blog.sina.com.cn/s/blog_6afb7d800101fa29.html

http://blog.sina.com.cn/s/blog_6afb7d800101fafl.html

http://blog.sina.com.cn/s/blog_6afb7d800101faiz.html

以及另一位博友摘錄的國外的文檔:http://blog.csdn.net/kepoon/article/details/22384375


另附上對Certificate、App Id、Identifiers 和 Provisioning Profile理解的文章:http://www.th7.cn/Program/IOS/201406/218729.shtml

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章