利用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方法中加入注册消息通知推送服务。

 - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
//判断是否由远程消息通知触发应用程序启动
if ([launchOptions objectForKey:UIApplicationLaunchOptionsRemoteNotificationKey]!=nil) {
NSLog(@"远程消息通知触发应用程序启动");
}
//消息推送注册
[[UIApplication sharedApplication] registerForRemoteNotificationTypes:UIRemoteNotificationTypeSound|UIRemoteNotificationTypeAlert|UIRemoteNotificationTypeBadge];
}

2、接收deviceToken的方法

在项目的AppDelegate.m中加入以下两个代理方法

 - (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
NSString *token = [NSString stringWithFormat:@"%@", deviceToken];
//获取终端设备标识,标识获取后需要将其发送到服务器端,服务器端推送消息到APNS时需要知道终端的标识,APNS通过注册的终端标识找到终端设备。
NSLog(@"My token is:%@", token);
}
- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error {
NSString *error_str = [NSString stringWithFormat: @"%@", error];
NSLog(@"Failed to get token, error:%@", error_str);
}

3、接收消息的处理方法

在项目AppDelegate.m中加入消息接收处理代理方法。

 - (void)application:(UIApplication *)application
didReceiveRemoteNotification:(NSDictionary *)userInfo
{
//在此处理接收到的消息。
NSLog(@"Receive remote notification : %@",userInfo);
}

至此,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、编写服务器端代码

 package com.push.server;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties; import javapns.devices.Device;
import javapns.devices.implementations.basic.BasicDevice;
import javapns.notification.AppleNotificationServerBasicImpl;
import javapns.notification.PushNotificationManager;
import javapns.notification.PushNotificationPayload;
import javapns.notification.PushedNotification; public class SendToAPNS {
// 从客户端获取的deviceToken,在此为了测试,设一个固定值
private static final String DEVICE_TOKEN = "13b11050a3fc064b3692e25c0fbd3b774b39ecb0c55a51ff4fb1373e004577a0";
List<String> deviceToken = new ArrayList<String>(); public void send () {
// 证书文件(.p12)在服务器端的目录
String filePath = null;
try {
String path = this.getClass().getClassLoader().getResource("/").getPath();
filePath = java.net.URLDecoder.decode(path,"utf-8");
} catch (Exception e){
e.printStackTrace();
}
System.out.println("filePath=" + filePath);
String certificatePath = (filePath + "conf/ios_development.p12");
// 获取ios_development.p12的密码
Properties prop = new Properties();
FileInputStream fis = null;
try {
fis = new FileInputStream(filePath + "conf/pushmessage.properties"); } catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
prop.load(fis);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
String certificatePassword = prop.getProperty("password"); // 构建发送的消息
String message="{'aps':{'alert':'this is a push message'}}"; // 设别标识
deviceToken.add(DEVICE_TOKEN);
// 发送消息
sendpush(deviceToken, certificatePath, certificatePassword, message, , false);
} /************************************************
测试用URL gateway.sandbox.push.apple.com /2195
正式发布用URL gateway.push.apple.com / 2195
javaPNS_2.2.jar必须
***************************************************/
/**
* @param tokens iphone设备的唯一标识 * @param path .p12证书文件的路径 * @param password .p12证书文件的密码 * @param message 发送的消息内容 * @param count * @param sendCount true 一对一发送 false 群发 */
public void sendpush(List<String> tokens,String path, String password, String message,Integer count,boolean sendCount) {
try {
// message:{"aps":{"alert":"一条新消息"}}
PushNotificationPayload payLoad = PushNotificationPayload.fromJSON(message);
//payLoad.addAlert(message);
payLoad.addBadge(count);
payLoad.addSound("default"); PushNotificationManager pushManager = new PushNotificationManager();
// true 正式发布用URL
// false 测试用URL
pushManager.initializeConnection(new AppleNotificationServerBasicImpl(path, password, false));
List<PushedNotification> notifications = new ArrayList<PushedNotification>();
// 推送方式
if (sendCount) {
System.out.println("-------现在进行一对一推送-------");
Device device = new BasicDevice();
device.setToken(tokens.get());
PushedNotification notification = pushManager.sendNotification(device, payLoad, true);
notifications.add(notification);
} else {
System.out.println("------现在进行群发-------");
List<Device> device = new ArrayList<Device>();
for (String token : tokens) {
device.add(new BasicDevice(token));
}
notifications = pushManager.sendNotifications(payLoad, device);
} List<PushedNotification> failedNotifications = PushedNotification.findFailedNotifications (notifications);
List<PushedNotification> successfulNotifications = PushedNotification.findSuccessfulNotifications(notifications);
int failed = failedNotifications.size();
int successful = successfulNotifications.size(); if (successful > && failed == ) {
//log.debug("-----All notifications pushed success (" + successfulNotifications.size() + "):");
System.out.println("-----All notifications pushed success (" + successfulNotifications.size() + "):");
}
else if (successful == && failed > ) {
//log.debug("-----All notifications pushed failed(" + failedNotifications.size() + "):");
System.out.println("-----All notifications pushed failed(" + failedNotifications.size() + "):");
}
else if (successful == && failed == ) {
System.out.println("No notifications could be sent, probably because of a critical error");
}
else {
//log.debug("------Some notifications pushed failed (" + failedNotifications.size () + "):");
//log.debug("------Others pushed success(" + successfulNotifications.size() + "):");
System.out.println("------Some notifications pushed failed (" + failedNotifications.size() + "):");
System.out.println("------Others pushed success(" + successfulNotifications.size() + "):");
}
pushManager.stopConnection(); } catch (Exception e) {
e.printStackTrace();
}
}
}

至此,服务器端代码也码完了。(^_^)

APNS推送的特点

从APNS的文档中大概总结了以下几点:

1、提供单一发送和群发功能。

2、当用户手机不在线(可能没有信号或者关机),APNs会存储转发,等用户在线时再发送。

3、如果用户长时间不在线,这条信息会被忽略。

4、如果用户不在线,通知会合并,只会保留最新的一条。

5、payload,就是最后生成的那段Json,不得超过256字节。如果超过了,建议去掉一些不需要的参数,把alert,就是提示

信息的字数减少。

6、发送成功的没有返回,只有发送失败的才会返回。

7、如果有error-response,那么这条之后的通知都需要重发。

8、如果出错了,需要关闭当前的连接,并且重新连接再发。error-response中返回的通知ID,可以帮助我们找出哪条出错

了,这样就能知道哪些需要重发了。

9、不要反复多次连接、终止与APNS的连接,否则会被APNS拒绝连接。

10、APNS的feedback service会返回那些已经卸载的设备的deviceToken。对于这些token,下次就不用再发了。可以节省

点资源。需要注意的是:feedback的接口读取一次,APNS就会清空它的列表,下次再读取时,返回的就是这两次读取之间这

段时间新产生的deviceToken

消息推送之APNS的更多相关文章

  1. iOS 消息推送实现 APNS

    本文只是记录一下如何在自己的电脑上配置APNS推送环境,其它的如推送的原理,流程什么的这里就不写了. 一. 去Apple 开发者中心,创建App ID.注意App ID不能使用通配符.并注意添加Pus ...

  2. [Erlang 0106] Erlang实现Apple Push Notifications消息推送

        我们的IOS移动应用要实现消息推送,告诉用户有多少条消息未读,类似下图的效果(笑果),特把APNS和Erlang相关解决方案笔记于此备忘.          上面图片中是Apple Notif ...

  3. iOS远程消息推送原理

    1. 什么是远程消息推送? APNs:Apple Push Notification server 苹果推送通知服务苹果的APNs允许设备和苹果的推送通知服务器保持连接,支持开发者推送消息给用户设备对 ...

  4. Push:iOS基于APNS的消息推送

    1. Push的三个步骤,如下图所示: (1)Push服务应用程序把要发送的消息.目的iPhone的标识打包,发给APNS: (2)APNS在自身的已注册Push服务的iPhone列表中,查找有相应标 ...

  5. 【转】APNs消息推送完整讲解

    https://developer.apple.com/library/ios/#documentation/NetworkingInternet/Conceptual/RemoteNotificat ...

  6. .NET向APNS苹果消息推送通知

    一.Apns简介: Apns是苹果推送通知服务. 二.原理: APNs会对用户进行物理连接认证,和设备令牌认证(简言之就是苹果的服务器检查设备里的证书以确定其为苹果设备):然后,将服务器的信息接收并且 ...

  7. IOS 基于APNS消息推送原理与实现(JAVA后台)

    Push的原理: Push 的工作机制可以简单的概括为下图 图中,Provider是指某个iPhone软件的Push服务器,这篇文章我将使用.net作为Provider. APNS 是Apple Pu ...

  8. APNs消息推送完整讲解

    在项目的AppDelegate中的didFinishLaunchingWithOptions方法中加入下面的代码: [[UIApplication sharedApplication] registe ...

  9. oc学习之路----APNS消息推送从证书到代码(2015年4月26号亲试可用)

    前言:看这篇博客之前要准备:首先的有一个99刀的个人开发者账号或者199刀的企业开发者账号,其次你用的是apns消息推送,(本人之前四处打听有没有其他消息推送的方法:收获如下:首先如果想做到apns的 ...

随机推荐

  1. 那些不能错过的Xcode插件

      来源:http://www.cocoachina.com/applenews/devnews/2013/0918/7022.html 古人云“工欲善其事必先利其器”,打造一个强大的开发环境,是立即 ...

  2. C语言位运算符及作用:与、或、异或、取反、左移和右移

    一.& 按位与 如果两个相应的二进制位都为1,则该位的结果值为1,否则为0应用:(1)清零 若想对一个存储单元清零,即使其全部二进制位为0,只要找一个二进制数,其中各个位符合一下条件:原来的数 ...

  3. CentOS 安装 Chrome

    cd  /etc/yum.repos.d/ vi  google.repo [gogle] name=Google-x86_64 baseurl=http://dl.google.com/linux/ ...

  4. vs 2012 智能提示后为何不能 直接按enter键把提示的内容输入

    这个是VS的"建议完成模式"和"标准模式",两者间切换按快捷键:Ctrl+Alt+空格键

  5. NAND flash cache编程

    PROGRAM PAGE CACHE MODE 0x80-0x15: CACHE编程实际上是标准的页编程命令的带缓冲编程模式,编程开始是发布SERIAL DATA INPUT(0x80)命令,随后是5 ...

  6. Reflect

    反射技术:其实就是动态加载一个指定的类,并获取该类中的所有的内容.而且将字节码文件封装成对象,并将字节码文件中的内容都封装成对象,这样便于操作这些成员.简单说:反射技术可以对一个类进行解剖. 反射的好 ...

  7. 【转】android的一些开源项目

    自己一直很喜欢Android开发,就如博客副标题一样,我想做个好的App. 在摸索过程中,GitHub上搜集了很多很棒的Android第三方库,推荐给在苦苦寻找的开发者,而且我会不定期的更新这篇文章. ...

  8. MS Sqlserver 备份数据库SQL

    通过作业的方式调用SQL执行自动备份,可以解决忘记备份数据库的问题,记录一下 declare @FileFullName varchar(40); declare @FileName varchar( ...

  9. MySQL主存复制与读写分离的感悟

    1.主存复制: 就是实现数据拷贝,有点实时的感觉,完成数据同步,存储两份数据. 项目开发中,类似场景许多,尤其是异构系统之间的交互,协作.-------------------场景目的:为了安全,各自 ...

  10. java——操作文件

    Java文件操作,共实现了文件复制(单个文件和多层目录文件),文件移动(单个文件和多层目录文件),文件删除(单个文件和多层目录文件),文件压缩 (单个文件),文件解压(单个文件),文件分割(将一个大文 ...