天天看點

[紹棠] iOS遠端推送原理及實作過程

推送通知,是現在的應用必不可少的功能。那麼在 iOS 中,我們是如何實作遠端推送的呢?iOS 的遠端推送原理又是什麼呢?在做 iOS 遠端推送時,我們會遇到各種各樣的問題。那麼首先讓我們準備一些做推送需要的東西。我們需要一個付費的蘋果開發者賬号(免費的不可以做遠端推送),有了開發者賬号,我們可以去蘋果開發者網站,配置自己所需要的推送的相關證書。然後下載下傳證書,供我們後面使用,詳細的證書配置過程,我們下面再說。

首先我們要說說iOS推送通知的基本原理:

蘋果的推送服務通知是由自己專門的推送伺服器APNs (Apple Push Notification service)來完成的,其過程是 APNs 接收到我們自己的應用伺服器發出的被推送的消息,将這條消息推送到指定的 iOS 的裝置上,然後再由 iOS裝置通知到我們的應用程式,我們将會以通知或者聲音的形式收到推送回來的消息。 iOS 遠端推送的前提是,裝有我們應用程式的 iOS 裝置,需要向 APNs 伺服器注冊,注冊成功後,APNs 伺服器将會給我們傳回一個 devicetoken,我們擷取到這個 token 後會将這個 token 發送給我們自己的應用伺服器。當我們需要推送消息時,我們的應用伺服器将消息按照指定的格式進行打包,然後結合 iOS 裝置的 devicetoken 一起發給 APNs 伺服器。我們的應用會和 APNs 伺服器維持一個基于 TCP 的長連接配接,APNs 伺服器将新消息推送到iOS 裝置上,然後在裝置螢幕上顯示出推送的消息。

裝置注冊APNs的流程圖:

[紹棠] iOS遠端推送原理及實作過程

上圖完成了如下步驟:

1.Device(裝置)連接配接APNs伺服器并攜帶裝置序列号(UUID)

2.連接配接成功,APNs經過打包和處理産生devicetoken并傳回給注冊的Device(裝置)

3.Device(裝置)攜帶擷取的devicetoken發送到我們自己的應用伺服器

4.完成需要被推送的Device(裝置)在APNs伺服器和我們自己的應用伺服器的注冊

推送過程圖:

[紹棠] iOS遠端推送原理及實作過程

推送的過程經過如下步驟:

1.首先,我們的裝置安裝了具有推送功能的應用(應用程式要用代碼注冊消息推動),我們的 iOS裝置在有網絡的情況下會連接配接APNs推送伺服器,連接配接過程中,APNS 伺服器會驗證devicetoken,連接配接成功後維持一個基于TCP 的長連接配接;

2.Provider(我們自己的應用伺服器)收到需要被推送的消息并結合被推送的 iOS裝置的devicetoken一起打包發送給APNS伺服器;

3.APNS伺服器将推送資訊推送給指定devicetoken的iOS裝置;

4.iOS裝置收到推送消息後通知我們的應用程式并顯示和提示使用者(聲音、彈出框)

比較直覺的流程圖:

[紹棠] iOS遠端推送原理及實作過程

資訊包結構圖:

[紹棠] iOS遠端推送原理及實作過程

上圖顯示的這個消息體就是我們的應用伺服器(Provider)發送給APNs伺服器的消息結構,APNs驗證這個結構正确并提取其中的資訊後,再将消息推送到指定的iOS裝置。這個結構體包括五個部分,第一個部分是指令标示符,第二個部分是我們的devicetoken的長度,第三部分是我們的devicetoken字元串,第四部分是推送消 息體(Payload)的長度,最後一部分也就是真正的消息内容了,裡面包含了推送消息的基本資訊,比如消息内容,應用Icon右上角顯示多少數字以及推送消息到達時所播放的聲音等

Payload(消息體)的結構:

{
     “aps”:{
     “alert”:“聽雲給您發送了新消息”,
     “badge”:1,
     “sound”:“default”
     },
}      

這其實就是個JSON結構體,alert标簽的内容就是會顯示在使用者手機上的推送資訊,badge顯示的數量(注意是整型)是會在應用Icon右上角顯示的數量,提示有多少條未讀消息等,sound就是當推送資訊送達是手機播放的聲音,傳defalut就标明使用系統預設聲音。

下面就是我們推送通知所需要的證書的推送過程:

1.首先我們要建立一個Certificate Signing Request(也就是CSR)的請求檔案

在應用程式裡的使用工具中找到鑰匙串通路,選擇從證書頒發機構請求證書

[紹棠] iOS遠端推送原理及實作過程
[紹棠] iOS遠端推送原理及實作過程

注意:郵箱位址,填自己的開發者賬号,常用名,随便填一個記住就行。然後選擇存儲到磁盤。繼續就行。

[紹棠] iOS遠端推送原理及實作過程

儲存位置在 tingyun(指定自己的檔案夾,這裡我選擇的是我的檔案夾),點選存儲

然後點選完成後我們會在 tingyun 裡看到一個CertificateSigningRequest.certSigningRequest的請求檔案,也就是我們說的CSR檔案。在我們生成CSR檔案的同時,會在鑰匙串通路中生成一對秘鑰,名稱為剛才我們填寫的常用名

2.配置AppID

到蘋果開發者網站https://developer.apple.com

點選Account 

[紹棠] iOS遠端推送原理及實作過程

選擇 Certificates,identifiers&Profiles 

[紹棠] iOS遠端推送原理及實作過程

選擇 Identifiers ->App IDs 點選上方的+号建立一個 App ID.

[紹棠] iOS遠端推送原理及實作過程

Name: 填寫 App 的名字就行

App ID Suffix 選擇不用通配符的及 Explicit App ID

Bundle ID:填寫自己應用的 Bundle ID 一定要和自己應用的一緻.

[紹棠] iOS遠端推送原理及實作過程

在下面的 App Services 中選擇自己需要的服務

我們需要推送服務,是以在Push Notifications上打勾

然後點選continue

[紹棠] iOS遠端推送原理及實作過程

3.建立證書

證書需要建立兩種,一種是開發的、一種是釋出的,開發的是做測試用的。

選擇Development 點選右上角的+号,建立證書,我們首先建立開發證書

[紹棠] iOS遠端推送原理及實作過程

選擇Apple Push Notification service SSL (Sandbox),建立推送服務證書點選下一步

[紹棠] iOS遠端推送原理及實作過程

這兒的 App ID 選擇我們剛才建立的 App ID

然後點選下一步,下一步

[紹棠] iOS遠端推送原理及實作過程

這兒點選 Choose File,選擇我們剛才建立的 CSR 檔案.

然後點選生成(Generate)

最後點選下載下傳,下載下傳證書。将下載下傳的證書,放到指定位置。

[紹棠] iOS遠端推送原理及實作過程

釋出證書的建立和開發證書一樣,選擇Production->Apple Push Notification service SSL (Production)後面和開發證書一樣

[紹棠] iOS遠端推送原理及實作過程
[紹棠] iOS遠端推送原理及實作過程

4.添加 Devices:

首先選中你要添加哪種裝置,然後在左上角點選“+”号。

[紹棠] iOS遠端推送原理及實作過程

Name 填寫一個裝置名字。

UDID 填寫自己需要加入測試的裝置的 UDID。

然後點選下一步

[紹棠] iOS遠端推送原理及實作過程

然後點選 Register 即可

[紹棠] iOS遠端推送原理及實作過程

點選Done。

[紹棠] iOS遠端推送原理及實作過程
[紹棠] iOS遠端推送原理及實作過程

5.查找裝置的 UDID:

用自己的 iOS 裝置連接配接到電腦上,打開 iTunes。

在裝置摘要處可以看見一個序列号,點選序列号就會變成 UDID。

[紹棠] iOS遠端推送原理及實作過程

6.生成配置檔案

配置檔案也有兩種,一種是開發的,一種是釋出的,開發的使我們做測試需要的,釋出的是我們在 Appstore 上釋出時需要的,我們都需要生成。

我們先生成開發配置檔案,選擇Provisioning Profiles->Development點選右上角的+号。

[紹棠] iOS遠端推送原理及實作過程

選擇iOS App Development 點選下一步

[紹棠] iOS遠端推送原理及實作過程

這兒的 App ID 仍然選擇我們剛才建立的 App ID

[紹棠] iOS遠端推送原理及實作過程
[紹棠] iOS遠端推送原理及實作過程

這兒選擇我們開發者的證書,如果不知道是哪個選擇全部即可

[紹棠] iOS遠端推送原理及實作過程

這兒選擇我們的測試裝置,如果沒有則在前面的Devices裡面添加即可

[紹棠] iOS遠端推送原理及實作過程
[紹棠] iOS遠端推送原理及實作過程

随便取個名字即可,然後下載下傳下來

[紹棠] iOS遠端推送原理及實作過程

釋出配置檔案和開發配置檔案一樣建立,選擇Distribution->Ad Hoc即可,後面與釋出配置檔案一樣。

[紹棠] iOS遠端推送原理及實作過程
[紹棠] iOS遠端推送原理及實作過程
[紹棠] iOS遠端推送原理及實作過程

證書配置完成,打開我們建立的應用項目

打開AppDelegate.m 檔案,在- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 方法中添加下面代碼,注冊消息推送

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    // Override point for customization after application launch.
        /** 消息推送注冊 */
    if ([UIDevice currentDevice].systemVersion.floatValue >= 8.0) {
        
        UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeBadge | UIUserNotificationTypeSound | UIUserNotificationTypeAlert categories:nil];
        [application registerUserNotificationSettings:settings];
        [application registerForRemoteNotifications];
    }else {
        [application registerForRemoteNotificationTypes:(UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeSound | UIRemoteNotificationTypeAlert)];
    }
    
    return YES;
}
下面方法是傳回 ANPs 蘋果推送伺服器生成的唯一辨別
/** 接收伺服器傳回的裝置唯一辨別 token */
-(void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken{
    
    // 第一次運作擷取到DeviceToken時間會比較長!
    // 将deviceToken轉換成字元串,以便後續使用
    NSString *token = [deviceToken description];
    NSLog(@"description %@", token);
}

下面方法是當有消息推送回來時,接收推送消息	
/** 裝置接收到來自蘋果推送伺服器的消息時觸發的,用來顯示推送消息 */

-(void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo{

    NSLog(@"userInfo == %@",userInfo);
}

上面方法是當注冊推送服務失敗時,接收錯誤資訊
/** 注冊推送服務失敗 */
-(void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error{
    NSLog(@"注冊失敗 %@",error);
}      

伺服器端(Java伺服器)

伺服器端我們需要,一個字尾為. p12的證書,以及需要的 jar 包

伺服器端的證書生成方式:

打開我們前面下載下傳的證書,在鑰匙串中找到它

[紹棠] iOS遠端推送原理及實作過程

點選滑鼠右鍵選擇導出

[紹棠] iOS遠端推送原理及實作過程

導出字尾為.p12的檔案儲存到自己的電腦上,需要輸入一個密碼,在 Java 伺服器端要用到

[紹棠] iOS遠端推送原理及實作過程

Java伺服器端需要的 Jar 包

[紹棠] iOS遠端推送原理及實作過程

Java 伺服器端代碼:

import javapns.back.PushNotificationManager;
import javapns.back.SSLConnectionHelper;
import javapns.data.Device;
import javapns.data.PayLoad;
public class pushService {
	public static void main(String[] args) {
		   
		   
		  try {
		           String deviceToken = "eab6df47eb4f81e0aaa93bb208cffd7dc3884fd346ea0743fcf93288018cfcb6";
		           //被推送的iphone應用程式标示符      
		           PayLoad payLoad = new PayLoad();
		           payLoad.addAlert("測試我的push消息");
		           payLoad.addBadge(1);
		           payLoad.addSound("default");
		                    
		           PushNotificationManager pushManager = PushNotificationManager.getInstance();
		           pushManager.addDevice("iphone", deviceToken);
		           
		           		           //測試推送伺服器位址:gateway.sandbox.push.apple.com /2195 
		      	   //産品推送伺服器位址:gateway.push.apple.com / 2195 
		           String host="gateway.sandbox.push.apple.com";  //測試用的蘋果推送伺服器
		           int port = 2195;
		           String certificatePath = "/Users/hsw/Desktop/PushTest/PushTest.p12"; //剛才在mac系統下導出的證書
		           
		           String certificatePassword= "123456";
		          
		           pushManager.initializeConnection(host, port, certificatePath,certificatePassword, SSLConnectionHelper.KEYSTORE_TYPE_PKCS12);
		                     
		           //Send Push
		           Device client = pushManager.getDevice("iphone");
		           pushManager.sendNotification(client, payLoad); //推送消息
		           pushManager.stopConnection();
		           pushManager.removeDevice("iphone");
		          }
		          catch (Exception e) {
		           e.printStackTrace();
		           System.out.println("push faild!");
		            return;
		          }
		          System.out.println("push succeed!");
		         }

}