zoukankan      html  css  js  c++  java
  • 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             // 推送方式
     98             if (sendCount) {
     99                 System.out.println("-------现在进行一对一推送-------");
    100                 Device device = new BasicDevice();
    101                 device.setToken(tokens.get(0));
    102                 PushedNotification notification = pushManager.sendNotification(device, payLoad, 
    103 
    104 true);
    105                 notifications.add(notification);
    106             } else {
    107                 System.out.println("------现在进行群发-------");
    108                 List<Device> device = new ArrayList<Device>();
    109                 for (String token : tokens) {
    110                     device.add(new BasicDevice(token));
    111                 }
    112                 notifications = pushManager.sendNotifications(payLoad, device);
    113             }
    114 
    115             List<PushedNotification> failedNotifications = PushedNotification.findFailedNotifications
    116 
    117 (notifications);
    118             List<PushedNotification> successfulNotifications = 
    119 
    120 PushedNotification.findSuccessfulNotifications(notifications);
    121             int failed = failedNotifications.size();
    122             int successful = successfulNotifications.size();
    123             
    124             if (successful > 0 && failed == 0) {
    125                 //log.debug("-----All notifications pushed success (" + 
    126 
    127 successfulNotifications.size() + "):");
    128                 System.out.println("-----All notifications pushed success (" + 
    129 
    130 successfulNotifications.size() + "):");
    131             } 
    132             else if (successful == 0 && failed > 0) {
    133                 //log.debug("-----All notifications pushed failed(" + failedNotifications.size() + 
    134 
    135 "):");
    136                 System.out.println("-----All notifications pushed failed(" + 
    137 
    138 failedNotifications.size() + "):");
    139             } 
    140             else if (successful == 0 && failed == 0) {
    141                 System.out.println("No notifications could be sent, probably because of a critical 
    142 
    143 error");
    144             } 
    145             else {
    146                 //log.debug("------Some notifications pushed failed (" + failedNotifications.size
    147 
    148 () + "):");
    149                 //log.debug("------Others pushed success(" + successfulNotifications.size() + 
    150 
    151 "):");
    152                 System.out.println("------Some notifications pushed failed (" + 
    153 
    154 failedNotifications.size() + "):");
    155                 System.out.println("------Others pushed success(" + successfulNotifications.size() 
    156 
    157 + "):");
    158             }
    159             pushManager.stopConnection();
    160             
    161         } catch (Exception e) {
    162             e.printStackTrace();
    163         }
    164     }
    165 }
    复制代码

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

     

    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

  • 相关阅读:
    转:SVN Eclipse插件Subclipse安装和配置
    Apache、php、mysql单独安装配置
    HDU 1150:Machine Schedule(二分匹配,匈牙利算法)
    Oracle 数据的导入和导出(SID service.msc)
    swift-数组array
    wxWidgets刚開始学习的人导引(4)——wxWidgets学习资料及利用方法指导
    用php 把数组中偶数,选择出来
    java 异常 之 实战篇(trows 和 try catch Dead Code)
    语言处理程序
    使用Maven构建和部署J2EE应用程序的EAR文件
  • 原文地址:https://www.cnblogs.com/zhibin/p/4137537.html
Copyright © 2011-2022 走看看