zoukankan      html  css  js  c++  java
  • (转)OpenFire源码学习之十八:IOS离线推送

    转:http://blog.csdn.net/huwenfeng_2011/article/details/43458213

    IOS离线推送

    场景:

    如果您有iOS端的APP,在会话聊天的时候,用户登陆了但可能会退出了界面。这时候其他终端给目标端发送消息时候,消息可以发送到ios的推送服务器。用过QQ的都知道,你会有哦一条消息在您的主屏上展示。这个就是利用了IOS的推送服务器呢。那么openfire只需要判断用户不在线的时候将消息推送给IOS端。

    苹果服务器的消息推送都需要手机的唯一标志,也就是唯一的终端设备号。那么IOS端在登陆的时候需要将该手机的设备号传递给OF服务器。这个传递很简单,您可以自定义发送IQ消息。也可以在登陆后绑定资料的时候添加JID属性来绑定设备。(建议用绑定资源的形式,这样在服务端判断的时候可以很方便的根据JID的属性值来决定是都推送)

     服务端实现ios消息推送所需2个证书(附件):测试推送证书.p12、正式推送正式.p12,密码都为123456.

     2个证书的区别在于一个是用于开发测试的推送证书,一个是用于产品正式上线的推送证书。2个证书获取到的终端token是不一样的。这2个证书用于Java后台连接APNS的服务器地址也是不同的,测试推送证书对应服务器地址是:gateway.sandbox.push.apple.com , 正式推送证书对应的服务器地址是:gateway.push.apple.com .

    具体怎么做呢:

    1、安装IOS推送服务需要的证书到本地,这个在网上有很多中方法

    2、IOS终端登陆发送设备消息给服务器,或者以绑定资源的形式。

    3、OF服务端接收该设备ID,并保存起来。

    4、当有消息推送时候,根据JID属性push消息。

    接下来具体看看源码了。

    源码

    OfflinePushPlugin

    [java] view plain copy
     
    1. public class OfflinePushPlugin implements Component, Plugin, PropertyEventListener, PacketInterceptor{  
    2.   
    3.       
    4.     private static final Logger Log = LoggerFactory.getLogger(OfflinePushPlugin.class);  
    5.       
    6.     public static final String NAMESPACE_JABBER_IQ_TOKEN_BIND= "jabber:iq:token:bind";  
    7.     public static final String NAMESPACE_JABBER_IQ_TOKEN_UNBUND= "jabber:iq:token:unbund";  
    8.       
    9.     public static final String SERVICENAME = "plugin.offlinepush.serviceName";  
    10.     public static final String SERVICEENABLED = "plugin.offlinepush.serviceEnabled";  
    11.       
    12.     private ComponentManager componentManager;  
    13.     private PluginManager pluginManager;  
    14.   
    15.     private String serviceName;  
    16. private boolean serviceEnabled;  
    17. //证书安装的目录  
    18.     private static String dcpath = System.getProperty("openfireHome") + "\conf\";  
    19.     private String dcName;  
    20.     private String dcPassword;  
    21.     private boolean enabled;  
    22.       
    23.     private static Map<String, String> map = new ConcurrentHashMap<String, String>(20);  
    24.     private static Map<String, Integer> count = new ConcurrentHashMap<String, Integer>(20);  
    25.       
    26.     private static AppleNotificationServer appleServer = null;  
    27.     private static List<PayloadPerDevice> list ;  
    28.       
    29.     public String getDcName() {  
    30.         return dcName;  
    31.     }  
    32.   
    33.     public void setDcName(String dcName) {  
    34.         JiveGlobals.setProperty("plugin.offlinepush.dcName", dcName);  
    35.         this.dcName = dcName;  
    36.     }  
    37.   
    38.     public String getDcPassword() {  
    39.         return dcPassword;  
    40.     }  
    41.   
    42.     public void setDcPassword(String dcPassword) {  
    43.         JiveGlobals.setProperty("plugin.offlinepush.password", dcPassword);  
    44.         this.dcPassword = dcPassword;  
    45.     }  
    46.   
    47.     public boolean getEnabled() {  
    48.         return enabled;  
    49.     }  
    50.   
    51.     public void setEnabled(boolean enabled) {  
    52.         this.enabled = enabled;  
    53.         JiveGlobals.setProperty("plugin.offlinepush.enabled",  enabled ? "true" : "false");  
    54.     }  
    55.   
    56.     public OfflinePushPlugin () {  
    57.         serviceName = JiveGlobals.getProperty(SERVICENAME, "offlinepush");  
    58.         serviceEnabled = JiveGlobals.getBooleanProperty(SERVICEENABLED, true);  
    59.     }  
    60.   
    61.     @Override  
    62.     public void xmlPropertySet(String property, Map<String, Object> params) {  
    63.           
    64.     }  
    65.   
    66.     @Override  
    67.     public void xmlPropertyDeleted(String property, Map<String, Object> params) {  
    68.     }  
    69.   
    70.     @Override  
    71.     public void initializePlugin(PluginManager manager, File pluginDirectory) {  
    72.           
    73.         dcName = JiveGlobals.getProperty("plugin.offlinepush.dcName", "");  
    74.         // If no secret key has been assigned to the user service yet, assign a random one.  
    75.         if (dcName.equals("")){  
    76.             dcName = "delementtest.p12";  
    77.             setDcName(dcName);  
    78.         }  
    79.         dcpath += dcName;  
    80.         dcPassword = JiveGlobals.getProperty("plugin.offlinepush.password", "");  
    81.         if (dcPassword.equals("")){  
    82.             dcPassword = "123456";  
    83.             setDcPassword(dcPassword);  
    84.         }  
    85.           
    86.         enabled = JiveGlobals.getBooleanProperty("plugin.offlinepush.enabled");  
    87.         setEnabled(enabled);  
    88.           
    89.         Log.info("dcpath: " + dcpath);  
    90.         Log.info("dcPassword: " + dcPassword);  
    91.         Log.info("enabled: " + enabled);  
    92.           
    93.         try {  
    94.             appleServer = new AppleNotificationServerBasicImpl(dcpath, dcPassword, enabled );  
    95.             if (list == null ) {  
    96.                 list = new ArrayList<PayloadPerDevice>();  
    97.             }  
    98.               
    99.         } catch (KeystoreException e1) {  
    100.             Log.error("KeystoreException: " + e1.getMessage());  
    101.         }   
    102.           
    103.         pluginManager = manager;  
    104.           
    105.         componentManager = ComponentManagerFactory.getComponentManager();  
    106.         try {  
    107.             componentManager.addComponent(serviceName, this);  
    108.         }  
    109.         catch (ComponentException e) {  
    110.             Log.error(e.getMessage(), e);  
    111.         }  
    112.           
    113.         InterceptorManager.getInstance().addInterceptor(this);  
    114.         PropertyEventDispatcher.addListener(this);  
    115.           
    116.     }  
    117.   
    118.     @Override  
    119.     public void destroyPlugin() {  
    120.         InterceptorManager.getInstance().removeInterceptor(this);  
    121.         PropertyEventDispatcher.removeListener(this);  
    122.         pluginManager = null;  
    123.         try {  
    124.             componentManager.removeComponent(serviceName);  
    125.             componentManager = null;  
    126.         }  
    127.         catch (Exception e) {  
    128.             if (componentManager != null) {  
    129.                 Log.error(e.getMessage(), e);  
    130.             }  
    131.         }  
    132.         serviceName = null;  
    133.     }  
    134.   
    135.     @Override  
    136.     public String getName() {  
    137.         return pluginManager.getName(this);  
    138.     }  
    139.   
    140.     @Override  
    141.     public String getDescription() {  
    142.         return pluginManager.getDescription(this);  
    143.     }  
    144.   
    145.     @Override  
    146.     public void processPacket(Packet p) {  
    147.         if (!(p instanceof IQ)) {  
    148.             return;  
    149.         }  
    150.         final IQ packet = (IQ) p;  
    151.   
    152.         if (packet.getType().equals(IQ.Type.error)  
    153.                 || packet.getType().equals(IQ.Type.result)) {  
    154.             return;  
    155.         }  
    156.         final IQ replyPacket = handleIQRequest(packet);  
    157.   
    158.         try {  
    159.             componentManager.sendPacket(this, replyPacket);  
    160.         } catch (ComponentException e) {  
    161.             Log.error(e.getMessage(), e);  
    162.         }  
    163.     }  
    164.   
    165.     private IQ handleIQRequest(IQ iq) {  
    166.         final IQ replyPacket; // 'final' to ensure that it is set.  
    167.   
    168.         if (iq == null) {  
    169.             throw new IllegalArgumentException("Argument 'iq' cannot be null.");  
    170.         }  
    171.   
    172.         final IQ.Type type = iq.getType();  
    173.         if (type != IQ.Type.get && type != IQ.Type.set) {  
    174.             throw new IllegalArgumentException(  
    175.                     "Argument 'iq' must be of type 'get' or 'set'");  
    176.         }  
    177.   
    178.         final Element childElement = iq.getChildElement();  
    179.         if (childElement == null) {  
    180.             replyPacket = IQ.createResultIQ(iq);  
    181.             replyPacket  
    182.                     .setError(new PacketError(  
    183.                             Condition.bad_request,  
    184.                             org.xmpp.packet.PacketError.Type.modify,  
    185.                             "IQ stanzas of type 'get' and 'set' MUST contain one and only one child element (RFC 3920 section 9.2.3)."));  
    186.             return replyPacket;  
    187.         }  
    188.   
    189.         final String namespace = childElement.getNamespaceURI();  
    190.         if (namespace == null) {  
    191.             replyPacket = IQ.createResultIQ(iq);  
    192.             replyPacket.setError(Condition.feature_not_implemented);  
    193.             return replyPacket;  
    194.         }  
    195.   
    196.         if (namespace.equals(NAMESPACE_JABBER_IQ_TOKEN_BIND)) {  
    197.             replyPacket = processSetUUID(iq, true);  
    198.         }   
    199.         else if (namespace.equals(NAMESPACE_JABBER_IQ_TOKEN_UNBUND)) {  
    200.             replyPacket = processSetUUID(iq, false);  
    201.         }   
    202.         else if (namespace.equals(IQDiscoInfoHandler.NAMESPACE_DISCO_INFO)) {  
    203.             replyPacket = handleDiscoInfo(iq);  
    204.         }   
    205.         else {  
    206.             // don't known what to do with this.  
    207.             replyPacket = IQ.createResultIQ(iq);  
    208.             replyPacket.setError(Condition.feature_not_implemented);  
    209.         }  
    210.   
    211.         return replyPacket;  
    212.     }  
    213.       
    214.     private static IQ handleDiscoInfo(IQ iq) {  
    215.         if (iq == null) {  
    216.             throw new IllegalArgumentException("Argument 'iq' cannot be null.");  
    217.         }  
    218.   
    219.         if (!iq.getChildElement().getNamespaceURI().equals(  
    220.                 IQDiscoInfoHandler.NAMESPACE_DISCO_INFO)  
    221.                 || iq.getType() != Type.get) {  
    222.             throw new IllegalArgumentException(  
    223.                     "This is not a valid disco#info request.");  
    224.         }  
    225.   
    226.         final IQ replyPacket = IQ.createResultIQ(iq);  
    227.   
    228.         final Element responseElement = replyPacket.setChildElement("query",  
    229.                 IQDiscoInfoHandler.NAMESPACE_DISCO_INFO);  
    230.         responseElement.addElement("identity").addAttribute("category",  
    231.                 "directory").addAttribute("type", "user").addAttribute("name",  
    232.                 "Offline Push");  
    233.         responseElement.addElement("feature").addAttribute("var",  
    234.                 NAMESPACE_JABBER_IQ_TOKEN_BIND);  
    235.         responseElement.addElement("feature").addAttribute("var",  
    236.                 IQDiscoInfoHandler.NAMESPACE_DISCO_INFO);  
    237.         responseElement.addElement("feature").addAttribute("var",  
    238.                 ResultSet.NAMESPACE_RESULT_SET_MANAGEMENT);  
    239.   
    240.         return replyPacket;  
    241.     }  
    242.       
    243.     private IQ processSetUUID(IQ packet, boolean isSet) {  
    244.         Element rsmElement = null;  
    245.         if (!packet.getType().equals(IQ.Type.set)) {  
    246.             throw new IllegalArgumentException(  
    247.                     "This method only accepts 'set' typed IQ stanzas as an argument.");  
    248.         }  
    249.   
    250.         final IQ resultIQ;  
    251.   
    252.         final Element incomingForm = packet.getChildElement();  
    253.   
    254.         rsmElement = incomingForm.element(QName.get("info",  
    255.                 NAMESPACE_JABBER_IQ_TOKEN_UNBUND));  
    256.           
    257.         if(rsmElement == null) {  
    258.             rsmElement = incomingForm.element(QName.get("info",  
    259.                     NAMESPACE_JABBER_IQ_TOKEN_BIND));  
    260.         }  
    261.   
    262.         resultIQ = IQ.createResultIQ(packet);  
    263.         if (rsmElement != null) {  
    264.             String osElement = rsmElement.attributeValue("os");  
    265.             String jidElement = rsmElement.attributeValue("jid");  
    266.               
    267.             String username = new JID(jidElement).getNode();  
    268.            
    269.             if (osElement == null || jidElement == null) {  
    270.                 resultIQ.setError(Condition.bad_request);  
    271.                 return resultIQ;  
    272.             }  
    273.             if (isSet) {  
    274.                 String tokenElement = rsmElement.attributeValue("token");  
    275.                 map.put(username, tokenElement);  
    276.                 count.put(username, 0);  
    277.                 Log.info("set token,username:" + username + " ,token:" + tokenElement);  
    278.             }  
    279.             else {  
    280.                 map.remove(username);  
    281.                 count.remove(username);  
    282.                 Log.info("remove token,username:" + username );  
    283.             }  
    284.         }   
    285.         else{  
    286.             resultIQ.setError(Condition.bad_request);  
    287.         }  
    288.   
    289.         return resultIQ;  
    290.     }  
    291.       
    292.     public String getServiceName() {  
    293.         return serviceName;  
    294.     }  
    295.       
    296.     public void setServiceName(String name) {  
    297.         JiveGlobals.setProperty(SERVICENAME, name);  
    298.     }  
    299.       
    300.     public boolean getServiceEnabled() {  
    301.         return serviceEnabled;  
    302.     }  
    303.       
    304.     public void setServiceEnabled(boolean enabled) {  
    305.         serviceEnabled = enabled;  
    306.         JiveGlobals.setProperty(SERVICEENABLED, enabled ? "true" : "false");  
    307.     }  
    308.       
    309.     public void propertySet(String property, Map<String, Object> params) {  
    310.         if (property.equals(SERVICEENABLED)) {  
    311.             this.serviceEnabled = Boolean.parseBoolean((String)params.get("value"));  
    312.         }  
    313.         if (property.equals("plugin.offlinepush.dcName")) {  
    314.             this.dcName = (String)params.get("value");  
    315.         }  
    316.         else if (property.equals("plugin.offlinepush.enabled")) {  
    317.             this.enabled = Boolean.parseBoolean((String)params.get("value"));  
    318.         }  
    319.         else if (property.equals("plugin.offlinepush.password")) {  
    320.             this.dcPassword = (String)params.get("value");  
    321.         }  
    322.     }  
    323.   
    324.     /* 
    325.      * (non-Javadoc) 
    326.      *  
    327.      * @see org.jivesoftware.util.PropertyEventListener#propertyDeleted(java.lang.String, 
    328.      *      java.util.Map) 
    329.      */  
    330.     public void propertyDeleted(String property, Map<String, Object> params) {  
    331.         if (property.equals(SERVICEENABLED)) {  
    332.             this.serviceEnabled = true;  
    333.         }  
    334.         if (property.equals("plugin.offlinepush.dcName")) {  
    335.             this.dcName = "delementtest.p12";  
    336.         }  
    337.         else if (property.equals("plugin.offlinepush.enabled")) {  
    338.             this.enabled = false;  
    339.         }  
    340.         else if (property.equals("plugin.offlinepush.password")) {  
    341.             this.dcPassword = "123456";  
    342.         }  
    343.     }  
    344.       
    345.     @Override  
    346.     public void initialize(JID jid, ComponentManager componentManager)  
    347.             throws ComponentException {  
    348.         // TODO Auto-generated method stub  
    349.           
    350.     }  
    351.   
    352.     @Override  
    353.     public void start() {  
    354.         // TODO Auto-generated method stub  
    355.           
    356.     }  
    357.   
    358.     @Override  
    359.     public void shutdown() {  
    360.         // TODO Auto-generated method stub  
    361.           
    362.     }  
    363.   
    364.     @Override  
    365.     public void interceptPacket(Packet packet, Session session,  
    366.             boolean incoming, boolean processed) throws PacketRejectedException {  
    367.         if (processed && incoming) {  
    368.             if (packet instanceof Message) {  
    369.                 if (((Message) packet).getBody() == null) {  
    370.                     return;  
    371.                 }  
    372.                 JID jid = packet.getTo();  
    373.                 //获取用户的设备标志id  
    374.                 String uuid = map.get(jid.getNode());  
    375.                 if (uuid != null && !"".equals(uuid)) {  
    376.                     User user = null;  
    377.                     try {  
    378.                         user = XMPPServer.getInstance().getUserManager().getUser(jid.getNode());  
    379.                     } catch (UserNotFoundException e2) {  
    380.                         e2.printStackTrace();  
    381.                     }  
    382.                     PresenceManager presenceManager = XMPPServer.getInstance().getPresenceManager();  
    383.                     org.xmpp.packet.Presence presence = presenceManager.getPresence(user);  
    384.                     if (presence == null) {  
    385.                           
    386.                         String body = ((Message) packet).getBody();  
    387.                         JSONObject jb = null;  
    388.                         String msgType = "10015";  
    389.                         try {  
    390.    
    391.                             jb = new JSONObject(body);  
    392.                             msgType = jb.getString("msgType");  
    393.                             if ("10012".equals(msgType) || "10001".equals(msgType) || "10002".equals(msgType)) {  
    394.                                 return;  
    395.                             }  
    396.                         } catch (JSONException e) {  
    397.                             try {  
    398.                               //根据不同的消息类型,发送不通的提示语  
    399.                                 msgType = jb.getInt("msgType")+"";  
    400.                                 if ("10012".equals(msgType) || "10001".equals(msgType) || "10002".equals(msgType)) {  
    401.                                     return;  
    402.                                 }  
    403.                             } catch (JSONException e1) {  
    404.                                 msgType = "10015";  
    405.                             }  
    406.                         }  
    407.                         if (msgType != null) {  
    408.                             //msgType = "offlinepush." + msgType;  
    409.                             String pushCont = LocaleUtils.getLocalizedString("offlinepush.10015", "offlinepush");  
    410.                             if (!"10000".equals(msgType)) {  
    411.                                 msgType = "offlinepush." + msgType;  
    412.                                 pushCont = LocaleUtils.getLocalizedString(msgType, "offlinepush");  
    413.                             }  
    414.                             else {  
    415.                                 pushCont = LocaleUtils.getLocalizedString("offlinepush.10000", "offlinepush");  
    416.                                 String cont = LocaleUtils.getLocalizedString("offlinepush.other", "offlinepush");;  
    417.                                 String mtype  = "";  
    418.                                 try {  
    419.                                     mtype = jb.getString("mtype");  
    420.                                 } catch (JSONException e) {  
    421.                                     try {  
    422.                                         mtype = jb.getInt("mtype") + "";  
    423.                                     } catch (JSONException e1) {  
    424.                                         msgType = "10015";  
    425.                                     }  
    426.                                 }  
    427.                                 if ("0".equals(mtype)) {  
    428.                                     try {  
    429.                                         cont = jb.getString("Cnt");  
    430.                                         if (cont.length() > 20) {  
    431.                                             cont = cont.substring(0, 20);  
    432.                                             cont += "...";  
    433.                                         }  
    434.                                           
    435.                                     } catch (JSONException e) {  
    436.                                     }  
    437.                                       
    438.                                               
    439.                                 }  
    440.                                 else if ("1".equals(mtype)) {  
    441.                                     cont = LocaleUtils.getLocalizedString("offlinepush.image", "offlinepush");   
    442.                                 }  
    443.                                 else if ("2".equals(mtype)) {  
    444.                                     cont = LocaleUtils.getLocalizedString("offlinepush.audio", "offlinepush");   
    445.                                 }  
    446.                                 else if ("4".equals(mtype)) {  
    447.                                     cont = LocaleUtils.getLocalizedString("offlinepush.file", "offlinepush");   
    448.                                 }  
    449.                                 else if ("3".equals(mtype)) {  
    450.                                     cont = LocaleUtils.getLocalizedString("offlinepush.location", "offlinepush");   
    451.                                 }  
    452.                                 else if ("6".equals(mtype)) {  
    453.                                     cont = LocaleUtils.getLocalizedString("offlinepush.video", "offlinepush");  
    454.                                 }  
    455.                                 pushCont += cont;  
    456.                             }  
    457.                             pushOfflineMsg(uuid, pushCont, jid);  
    458.                         }  
    459.                     }  
    460.                 }  
    461.             }  
    462.         }  
    463.           
    464.     }  
    465.   
    466.     private void pushOfflineMsg(String token, String pushCont, JID jid) {  
    467.             NotificationThreads work = null;  
    468.         try {  
    469.               
    470.             Integer size = count.get(jid.getNode()) + 1;   
    471.             if (size <= 1000)  
    472.                 count.put(jid.getNode(), size);  
    473.             List<PayloadPerDevice> list = new ArrayList<PayloadPerDevice>();  
    474.             PushNotificationPayload payload = new PushNotificationPayload();   
    475.             payload.addAlert(pushCont);  
    476.             payload.addSound("default");   
    477.             payload.addBadge(size);  
    478.             payload.addCustomDictionary("jid", jid.toString());  
    479.             PayloadPerDevice pay = new PayloadPerDevice(payload, token);  
    480.             list.add(pay);   
    481.             work = new NotificationThreads(appleServer,list,1);  
    482.             work.setListener(DEBUGGING_PROGRESS_LISTENER);  
    483.             work.start();   
    484.         } catch (JSONException e) {  
    485.             Log.error("JSONException:" + e.getMessage());  
    486.         } catch (InvalidDeviceTokenFormatException e) {  
    487.             Log.error("InvalidDeviceTokenFormatException:" + e.getMessage());  
    488.         }finally{  
    489.             work.destroy();  
    490.             Log.info("push to apple: username: " + jid.getNode() + " ,context" + pushCont);  
    491.         }  
    492.     }  
    493.       
    494.     public Runnable createTask(final String token, final String msgType, final JID jid) {  
    495.         return new Runnable() {  
    496.             @Override  
    497.             public void run() {  
    498.                 PushNotificationPayload payload = new PushNotificationPayload();    
    499.                 try {  
    500.                     String pushCont = LocaleUtils.getLocalizedString(msgType, "offlinepush");  
    501.                     List<PayloadPerDevice> list = new ArrayList<PayloadPerDevice>();  
    502.                     payload.addAlert(pushCont);  
    503.                     payload.addSound("default");   
    504.                     payload.addBadge(1);  
    505.                     payload.addCustomDictionary("jid", jid.toString());  
    506.                     PayloadPerDevice pay = new PayloadPerDevice(payload, token);  
    507.                     list.add(pay);   
    508.                     NotificationThreads work = new NotificationThreads(appleServer,list,1);  
    509.                     work.setListener(DEBUGGING_PROGRESS_LISTENER);  
    510.                     work.start();   
    511.                 } catch (JSONException e) {  
    512.                     Log.error("JSONException:" + e.getMessage());  
    513.                 } catch (InvalidDeviceTokenFormatException e) {  
    514.                     Log.error("InvalidDeviceTokenFormatException:" + e.getMessage());  
    515.                 }   
    516.             }  
    517.         };  
    518.           
    519.     }  
    520.       
    521.     public static final NotificationProgressListener DEBUGGING_PROGRESS_LISTENER = new NotificationProgressListener() {    
    522.         public void eventThreadStarted(NotificationThread notificationThread) {    
    523.             System.out.println("   [EVENT]: thread #" + notificationThread.getThreadNumber() + " started with " + " devices beginning at message id #" + notificationThread.getFirstMessageIdentifier());    
    524.         }    
    525.         public void eventThreadFinished(NotificationThread thread) {    
    526.             System.out.println("   [EVENT]: thread #" + thread.getThreadNumber() + " finished: pushed messages #" + thread.getFirstMessageIdentifier() + " to " + thread.getLastMessageIdentifier() + " toward "+ " devices");    
    527.         }    
    528.         public void eventConnectionRestarted(NotificationThread thread) {    
    529.             System.out.println("   [EVENT]: connection restarted in thread #" + thread.getThreadNumber() + " because it reached " + thread.getMaxNotificationsPerConnection() + " notifications per connection");    
    530.         }    
    531.         public void eventAllThreadsStarted(NotificationThreads notificationThreads) {    
    532.             System.out.println("   [EVENT]: all threads started: " + notificationThreads.getThreads().size());    
    533.         }    
    534.         public void eventAllThreadsFinished(NotificationThreads notificationThreads) {    
    535.             System.out.println("   [EVENT]: all threads finished: " + notificationThreads.getThreads().size());    
    536.         }    
    537.         public void eventCriticalException(NotificationThread notificationThread, Exception exception) {    
    538.             System.out.println("   [EVENT]: critical exception occurred: " + exception);    
    539.         }    
    540.      };   
    541. }  

    Plugin.xml

    [html] view plain copy
     
    1. <?xml version="1.0" encoding="UTF-8"?>  
    2.   
    3. <plugin>  
    4.     <class>com.....offlinepush.plugin.OfflinePushPlugin</class>  
    5.     <name>offlinepush</name>  
    6.     <description>.......</description>  
    7.     <author>huwenfeng</author>  
    8.     <version>1.5.1</version>  
    9.     <date>1/2/2014</date>  
    10.     <minServerVersion>3.7.0</minServerVersion>  
    11. </plugin>  

    资源文件:offlinepush_i18n_zh_CN.properties

    [html] view plain copy
     
    1. offlinepush.10000=u65B0u6D88u606FuFF1A  
    2. offlinepush.10001=u7528u6237u64CDu4F5C  
    3. offlinepush.image=[u56FEu7247]  
    4. offlinepush.audio=[u8BEDu97F3]  
    5. offlinepush.file=[u6587u4EF6]  
    6. offlinepush.other=[u5176u4ED6]  
    7. offlinepush.location=[u4F4Du7F6E]  
    8. offlinepush.video=[u89C6u9891]  
    9. ......   

    需要的jar包。

    OK啦。

    注意:IOS的推送服务器有两种模式都是免费,一种是测试的还一种是正式使用的。

    所以这里最好将推送服务的使用模式在OF的管理台做配置。

    本人在控制台配置了三个属性值:

  • 相关阅读:
    spring源码学习之容器的扩展(二)
    spring源码学习之容器的扩展(一)
    spring源码学习之bean的加载(三)
    spring源码学习之bean的加载(二)
    Linux find命令使用正则表达式
    Linux获取两个路径之间的相对路径
    利用linux sort命令比较版本号
    yum只下载不安装软件包
    tar命令排除某个文件夹
    ssh远程执行命令的符号转义问题
  • 原文地址:https://www.cnblogs.com/wangle1001986/p/7249473.html
Copyright © 2011-2022 走看看