IOS 推送
利用APNS进行消息推送
原理
APNS 是Apple Push Notification Service(Apple Push服务器)的缩写,是苹果的服务器。
APNS推送可以分为三个阶段:
第一阶段:推送服务器应用程序把要发送的消息、目的iPhone的标识打包,发给APNS。
第二阶段:APNS在自身的已注册推送服务的iPhone列表中,查找有相应标识的iPhone,并把消息发到iPhone。
第三阶段:iPhone把发来的消息传递给相应的应用程序,并且按照设定弹出推送通知。
详细流程如下:
1、首先是应用程序注册消息推送服务。
2、APNS向应用程序返回deviceToken。
3、应用程序将deviceToken发送给推送服务端程序。
4、服务端程序向APNS服务发送消息。
5、APNS服务将消息发送给iPhone应用程序。
证书生成
网上有很多关于证书生成的详细步骤,这里不再说明了。
最终生成的证书共包含下面四个
1、pushNotification.certSigningRequest
2、aps_development.cer(下载生成的支持推送服务的证书。)
3、pushNotificationDevprofile.mobileprovision
4、pushNotification.p12
下面直接上代码。
客户端
1、应用程序注册消息推送服务
在AppDelegate.m的(BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions方法中加入注册消息通知推送服务。
1 - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
2 {
3 //判断是否由远程消息通知触发应用程序启动
4 if ([launchOptions objectForKey:UIApplicationLaunchOptionsRemoteNotificationKey]!=nil) {
5 NSLog(@"远程消息通知触发应用程序启动");
6 }
7 //消息推送注册
8 [[UIApplication sharedApplication] registerForRemoteNotificationTypes:UIRemoteNotificationTypeSound|UIRemoteNotificationTypeAlert|UIRemoteNotificationTypeBadge];
9 }
2、接收deviceToken的方法
在项目的AppDelegate.m中加入以下两个代理方法
1 - (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
2 NSString *token = [NSString stringWithFormat:@"%@", deviceToken];
3 //获取终端设备标识,标识获取后需要将其发送到服务器端,服务器端推送消息到APNS时需要知道终端的标识,APNS通过注册的终端标识找到终端设备。
4 NSLog(@"My token is:%@", token);
5 }
6 - (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error {
7 NSString *error_str = [NSString stringWithFormat: @"%@", error];
8 NSLog(@"Failed to get token, error:%@", error_str);
9 }
3、接收消息的处理方法
在项目AppDelegate.m中加入消息接收处理代理方法。
1 - (void)application:(UIApplication *)application
2 didReceiveRemoteNotification:(NSDictionary *)userInfo
3 {
4 //在此处理接收到的消息。
5 NSLog(@"Receive remote notification : %@",userInfo);
6 }
至此,IOS端的代码已经码完了。(^_^)
服务器
服务器端可以用php、Java、.net等语言实现。本文使用Java语言实现
1、导入jar包
工程建好之后,将JavaPNS_2.2.jar、javapns-jdk16-163.jar、bcprov-jdk16-145.jar这几个jar包拷贝到工程的lib目录下。
2、生成服务器端所用的.p12文件(.net或Java等后台)
在mac终端下执行以下指令:
(1)、将aps_development.cer转换成aps_development.pem格式
$ openssl x509 -in aps_development.cer -inform DER -out aps_development.pem -outform PEM
(2)、将p12格式的私钥转换成pem
$ openssl pkcs12 -nocerts -out Push_Noenc.pem -in pushNotification.p12
(3)、创建p12文件
$ openssl pkcs12 -export -in aps_development.pem -inkey Push_Noenc.pem -certfile pushNotification.certSigningRequest -name "aps_development" -out aps_development.p12
这样我们就得到了在.net或java等后台应用程序中使用的证书文件:aps_development.p12
3、编写服务器端代码
1 package com.push.server;
2 import java.io.FileInputStream;
3 import java.io.FileNotFoundException;
4 import java.io.IOException;
5 import java.util.ArrayList;
6 import java.util.List;
7 import java.util.Properties;
8
9 import javapns.devices.Device;
10 import javapns.devices.implementations.basic.BasicDevice;
11 import javapns.notification.AppleNotificationServerBasicImpl;
12 import javapns.notification.PushNotificationManager;
13 import javapns.notification.PushNotificationPayload;
14 import javapns.notification.PushedNotification;
15
16 public class SendToAPNS {
17 // 从客户端获取的deviceToken,在此为了测试,设一个固定值
18 private static final String DEVICE_TOKEN =
19
20 "13b11050a3fc064b3692e25c0fbd3b774b39ecb0c55a51ff4fb1373e004577a0";
21 List<String> deviceToken = new ArrayList<String>();
22
23 public void send () {
24 // 证书文件(.p12)在服务器端的目录
25 String filePath = null;
26 try {
27 String path = this.getClass().getClassLoader().getResource("/").getPath();
28 filePath = java.net.URLDecoder.decode(path,"utf-8");
29 } catch (Exception e){
30 e.printStackTrace();
31 }
32 System.out.println("filePath=" + filePath);
33 String certificatePath = (filePath + "conf/ios_development.p12");
34 // 获取ios_development.p12的密码
35 Properties prop = new Properties();
36 FileInputStream fis = null;
37 try {
38 fis = new FileInputStream(filePath + "conf/pushmessage.properties");
39
40 } catch (FileNotFoundException e) {
41 // TODO Auto-generated catch block
42 e.printStackTrace();
43 }
44 try {
45 prop.load(fis);
46 } catch (IOException e) {
47 // TODO Auto-generated catch block
48 e.printStackTrace();
49 }
50 String certificatePassword = prop.getProperty("password");
51
52 // 构建发送的消息
53 String message="{'aps':{'alert':'this is a push message'}}";
54
55 // 设别标识
56 deviceToken.add(DEVICE_TOKEN);
57 // 发送消息
58 sendpush(deviceToken, certificatePath, certificatePassword, message, 4, false);
59 }
60
61 /************************************************
62 测试用URL gateway.sandbox.push.apple.com /2195
63 正式发布用URL gateway.push.apple.com / 2195
64 javaPNS_2.2.jar必须
65 ***************************************************/
66 /**
67 * @param tokens iphone设备的唯一标识
68
69 * @param path .p12证书文件的路径
70
71 * @param password .p12证书文件的密码
72
73 * @param message 发送的消息内容
74
75 * @param count
76
77 * @param sendCount true 一对一发送 false 群发
78
79 */
80 public void sendpush(List<String> tokens,String path, String password, String message,Integer
81
82 count,boolean sendCount) {
83 try {
84 // message:{"aps":{"alert":"一条新消息"}}
85 PushNotificationPayload payLoad = PushNotificationPayload.fromJSON(message);
86 //payLoad.addAlert(message);
87 payLoad.addBadge(count);
88 payLoad.addSound("default");
89
90 PushNotificationManager pushManager = new PushNotificationManager();
91 // true 正式发布用URL
92 // false 测试用URL
93 pushManager.initializeConnection(new AppleNotificationServerBasicImpl(path, password,
94
95 false));
96 List<PushedNotification> notifications = new ArrayList<PushedNotification>();
97