客户端的主要包说明

org.androidpn.client包下的文件

  1. public class Constants {  //包含静态数据
  2. public class InvalidFormatException extends RuntimeException { // 运行时所产生的错误处理
  3. public class LogUtil { //信息输出
  4. public class NotificationService extends Service { //后台运行并响应来自服务器的事件推送通知服务
  5. public final class ServiceManager { //管理的notificatin服务,加载配置
  6. public class XmppManager { // 管理客户端和服务器之间的连接
  7. public class ConnectivityReceiver extends BroadcastReceiver { // 网络变化广播接收器
  8. public class PersistentConnectionListener implements ConnectionListener { //连接关闭和重新连接事件的监听器 ,在XMPPManager中注册。
  9. public class PhoneStateChangeListener extends PhoneStateListener { //监听手机状态
  10. public class ReconnectionThread extends Thread {  // 用于断线重连
  11. public class NotificationIQ extends IQ {                    // 来自服务器的推送消息
  12. public class NotificationPacketListener implements PacketListener {// NotificationIQ通知传入的数据包的接收,在XMPPManager中注册
  13. public class NotificationIQProvider implements IQProvider { //提过给XmppConnection的NotificationIQ 解析方式,在XMPPManager中注册
  14. public final class NotificationReceiver extends BroadcastReceiver { //推送通知消息的广播接收器
  15. public class Notifier { //通知用户,这里正式对消息进行处理,如发送本地通知等。
  16. public class NotificationSettingsActivity extends PreferenceActivity { // 设置信息
  17. public class NotificationDetailsActivity extends Activity {  // 活动通知详细视图显示(未使用)

客户端使用的了smack.jar

做了一些修改,整个jar包解压了。smack.jar中 PacketReader解析消息,PacketWriter发消息,XMPPConnection负责连接管理。

发送消息:

XmppManager -> XmppConnection-> PacketWriter

接收消息:

XmppConnection -> packetReader -> NotificationPacketListener -> NotificationReceiver -> Notifier

服务器端的主要包说明

原项目有4+5+15,共计24个包,另有一个default包,里面仅有一段控制台测试代码。

3.3.3.1 web相关的4个包

1. org.androidpn.server.console.api   接口

2. org.androidpn.server.console.controller   控制器

3. org.androidpn.server.console.vo   viewModel

4. org.androidpn.server.container    未用到

3.3.3.2 数据库访问相关的5个包

1.org.androidpn.server.dao

2.org.androidpn.server.dao.hibernate

3.org.androidpn.server.model

4.org.androidpn.server.service

5.org.androidpn.server.service.impl

3.3.3.3 推送相关的15个包

1. org.androidpn.server.util

包中的类用来加载resources中的配置文件,在配置文件中可指定监听端口和ssl证书目录等属性。

  1. public class Config {  //读取配置信息
  2. public class ConfigManager { //应用程序配置信息管理

2. org.androidpn.server.xmpp 

主要是包含有入口类XmppServer,这个类用来启动和停止server程序,

包里面定义了一些异常类型。

  1. public class XmppServer {    //服务启动

3. org.androidpn.server.xmpp.auth

认证相关的一些类。

  1. public class AuthToken {  //封装用户认证token 名字、域名
  2. public class AuthManager {  //用户认证管理

4.org.androidpn.server.xmpp.codec

XMPP协议的XML文件解析包,通过这个包来进行xmpp协议数据传输的编码和解码。

  1. public class XmppCodecFactory implements ProtocolCodecFactory { //编码/解码器,用于解析XMPP消息。
  2. public class XmppDecoder extends CumulativeProtocolDecoder { //协议解码  (这里增加了心跳回送)
  3. public class XmppEncoder implements ProtocolEncoder { //协议编码  ,androidpn把加密放在了Connection 类中

5.org.androidpn.server.xmpp.handler

对消息的处理,我们可以针对不同的消息类型定义自己的handler。

  1. public class IQAuthHandler extends IQHandler {//APP连接时认证身份
  2. public abstract class IQHandler { //抽象类,处理客户端发来的IQ消息
  3. public class IQRegisterHandler extends IQHandler { //APP连接时处理用户注册
  4. public class IQRosterHandler extends IQHandler {  //未使用,拉取好友列表
  5. public class PresenceUpdateHandler { //处理操作(APP连接时登陆成功后更新在线状态)

6.org.androidpn.server.xmpp.net

负责维护与client之间的持久连接,并实现了一些传输方式供发送xmpp消息时使用。

  1. public class Connection { //一个XMPP连接服务器的实例  所有与客户端的消息连接都通过本类来处理
  2. public interface ConnectionCloseListener { // 连接关闭监听
  3. public class IoBufferWriter extends Writer { //输入输出处理
  4. public class StanzaHandler { //处理传入的XML (增加了一个方法getClientSession)
  5. public class XmppIoHandler implements IoHandler { //创建新的会话,销毁会话,并提供接收XML

7.org.androidpn.server.xmpp.presence

只包含PresenceManager类,用来维护client的在线状态。

  1. public class PresenceManager { //它会调用SessionManager,用于判断某用户是否在线或获取用户当前的Presence。

8.org.androidpn.server.xmpp.push

只NotificationManager类包含有向client发送消息的接口。

  1. public class NotificationManager { // 消息推送入口

9.org.androidpn.server.xmpp.router

负责将收到的信息包发送到相应的handler进行处理,是一个路由包。

  1. public class IQRouter { //路由IQ消息到其相应的处理
  2. public class MessageRouter { //路由Message消息到其相应的处理程序
  3. public class PacketDeliverer { //将数据包发送到连接会话
  4. public class PacketRouter { //处理传入的数据包,并将它们路由到其相应的处理程序
  5. public class PresenceRouter { //路由Presence消息到其相应的处理程序

10.org.androidpn.server.xmpp.session

定义了用来表示持久链接的session,每个session包含一条连接的状态信息。

  1. public class ClientSession extends Session {  //会话
  2. public abstract class Session { //会话抽象类
  3. public class SessionManager { //会话管理

11.org.androidpn.server.xmpp.ssl

对连接进行ssl认证的工具包。

  1. public class SSLConfig {  //ssl配置
  2. public class SSLKeyManagerFactory { //负责产生ssl管理 实例
  3. public class SSLTrustManagerFactory { //SSL信任管理器工厂类

12.org.dom4j.io 

输出输入流工具包

  1. public class XMPPPacketReader { // xml解析器

13.org.jivesoftware.openfire.net 

  1. public class MXParser extends org.xmlpull.mxp1.MXParser { //解析器验证文件

14.org.jivesoftware.openfire.nio

  1. public class XMLLightweightParser { //一个轻量级的XML解析器

15.org.jivesoftware.util

  1. public class PropertyEventDispatcher { //事件调配
  2. public interface PropertyEventListener { //事件监听
  3. public class XMLWriter extends XMLFilterImpl implements LexicalHandler { //xml编辑

推送实现

连接的建立和维持

服务器端

webRoot/WEB-INF/dispatcher-servlet.xml 和resources/spring-config.xml 内的bean在应用启动时会自动实例化,而它们中的许多在实例化时都会直接或间接地调用XmppServer.getInstance()方法。从而启动服务。

resources/spring-config.xml 中有相应的mina框架配置信息:

服务器和客户端之间的消息在org.androidpn.server.xmpp.net.XmppIoHandler中处理:

sessionCreated -> sessionOpened -> messageReceived - > sessionIdle -> sessionClosed

客户端

  1. 提供了三个监听器对手机网络状态或连接状态进行监听,在状态变化时启动断线或重连操作。
  2. 重连的时间间隔(秒)
    private int waiting() {
    //waiting 在每次重连会自增1
    if (waiting > 20) {
    return 600;
    }
    if (waiting > 13) {
    return 300;
    }
    return waiting <= 7 ? 10 : 60;
    }
  3. 在app操作中的任何一次页面切换都会判断服务的状态。
       //如果服务未启动,则启动服务
    private void startService(){
    if(NotificationService.getNotificationService() == null){
    // Start the service
    ServiceManager serviceManager = new ServiceManager(this);
    serviceManager.setNotificationIcon(R.drawable.ic_launcher);
    serviceManager.startService();
    }
    }
  4. ServiceManager实例化时会读取配置信息。
  5. ServiceManager的startService =>XmppManager的connect方法=>XMPPConnection的connect方法
  6. 连接时,执行登陆操作,在登陆前先判别是否需要注册,注册前先判别是否有连接,详细连接过程见XmppManager类。这个登陆类似于QQ一样,它先通过认证建立连接后,然后会要求使用用户名和密码来登陆,这组用户名和密码是随机生成的,每台设备对应唯一一组。

用户会话状态的维持

  1. mina框架提供了IoSession对象,IoSession维护着连接状态,并提供读写流,可以将信息发送给用户。
  2. IoSession中会创建Connection、Stanzahandler两个对象的实例,并持有它们。
  3. Stanzahandler中又创建了androidPN新增的ClientSession对象的实例,ClientSession对象又持有Connection对象。
  4. Connection对象中持有这两个Session成员: IoSession 和ClientSession 。
  5. SessionManager对象维护着一个Map,它存有设备标识(apn_user表的username)与用户会话ClientSession的映射关系,并提供了一个单例。

消息推送

安卓消息服务器端的推送流程

  1. NotificationManager的方法被调用,依据参数得到一组设备标识。
  2. 通过设备标识在SessionManager中检索可以匹配到ClientSession。
  3. 定义自己的xmpp消息格式并拼接出xml消息体。
  4. 通过ClientSession中的deliver方法,调用Connection中的deliver方法向用户发送消息。

要定义和组装自己的xmpp消息,将适当的信息发送给客户端并便于客户端解析,需要修改的就是第3步,实例化一个IQ对象,放入特定格式的消息体,然后直接发送就可以了。

发送

ClientSession session = sessionManager.getSession(username);
if (session != null&&session.getPresence().isAvailable()) {
iq.setTo(session.getAddress());
session.deliver(iq);
}

创建element的时候,传入的namespace要和客户端解析使用的namespace相匹配。

安卓消息服务器端的消息接收和处理

  1. 收到用户传输的数据时,首先经过IoFilter,完成消息的接收、编/解码等操作后。
  2. 解码操作由org.androidpn.server.xmpp.codec.XmppDecode来完成,解析完成后为每一个解码后的消息对象调用ProtocolDecoderOutput接口的write(Object)方法,将消息输出。
  3. 之后就开始消息的处理工作,以XmppIoHandler 的messageReceived方法为起点,后续StanzaHandler -> PacketRouter,然后依据消息体的类型选择对应的路由器,如处理IQ的IQRouter,Router再根据packet的namespace,选择对应的handler。
  4. handler进行处理。

router和handler类在androidpn中都有例子可以参考。开发中只要根据client发送消息的格式,定义自己的router和handler类,然后在PacketRouter中注册router,在IQRouter中注册handler即可。

客户端消息的接收

  1. org.jivesoftware.smack.PacketReader负责消息的接收。
  2. NotificationIQ、NotificationIQProvider、NotificationPacketListener三个类负责对收到的Notification格式的消息进行解析和处理。

    NotificationIQ中定义消息实体,

    NotificationIQProvider提供NotificationIQ的解析方法,

    NotificationPacketListener中对执行具体处理操作。

    它们需要在XmppManager中进行注册,代码如下:

    1. 连接成功后注册消息解析器:

2. 登陆成功后添加监听器:

要解析服务器推送的某IQ,需要实现*IQ和*IQProvider两个类,然后要在XmppManager中注册,并在NotificationPacketListener提供相应的处理操作。

客户端消息的发送

发送消息:xmppManager.getConnection().sendPacket(*IQ);

具体执行数据传输的是org.jivesoftware.smack.PacketWriter。

要发送某IQ到服务器,只要实现*IQ一个类就可以了,然后调用上面的方法发送到服务器。

主要的一些改动

APP中在NotificationService中增加对自身的引用

方便更加便捷地在任意位置获取xmppManager对象,同时可以方便判别当前服务器是否已启动。

增加心跳

APP端

在PacketWriter增加定时任务,默认每隔30秒向服务器发送一个空格,维持活跃状态,同时服务器会每隔300秒自动回复1个EchoIQ,如果app连续1000秒没有收到这个回应,则抛出连接中断异常,启动重连:XmppManager.startReconnectionThread()。心跳在登陆成功后启动,仅在超时后才会因异常而中断。

服务器端

设置readerIdleTime主动检查用户是否掉线,默认超时时间120秒

      spring-config.xml 文件底部添加:

<bean id="getSessionConfig" factory-bean="ioAcceptor" factory-method="getSessionConfig">

<property name="readerIdleTime" value="60"></property>

</bean>

  在org.androidpn.server.xmpp.codec.XmppDecode增加对客户端发送的“心跳”的处理(因为任何消息无论是否合法都会经过这里)。同时每隔300秒主动回一个“心跳”(一个EchoIQ)给安卓APP,在ClientSession中增加字段echoTime;在服务器发送消息给客户端时记录本次“心跳”的时间(在connection.deliver(packet)中)。

APP中修改重连功能

虽然存在3个监听器来监听手机网络和服务的状态,但这里存在BUG。

在XmppConnection中有3个连接状态connectedauthenticatedwasAuthenticated

 在不是主动下线(连接服务器时发生异常或者收到服务器的shotdown的要求)的情况下,被动断网后XmppConnection里的连接状态始终是connectedConnectivityReceiver并没有被触发,重连操作无法正常执行,只是一路XMPP contected already,Account registered already下来,最后无法成功登陆。

PersistentConnectionListener类 在XmppManager中加入监听集合,

XmppConnection在连接关闭时或读写异常时会调用:

XmppConnection.notifyConnectionError(e)->

PersistentConnectionListener.notifyConnectionError(e)->

xmppManager.startReconnectionThread();

PacketReader,PacketWriter的shutDown中如果有操作未完成,会调用

PersistentConnectionListener.connectionClosed();

在重连成功会调用

XmppConnection.notifyReconnection()->

PersistentConnectionListener.reconnectionSuccessful(e)

修改:

1. XmppConnection中新增了noConnected(),在开启重连线程时先将connected 改为false。

2. XmppManager.startReconnectionThread()可能会经常被触发,所以做了修改,避免开启多个重连线程,或一个重连线程启动多次。

3. 在PersistentConnectionListener内的几个事件中选择性地添加重连的调用。

增加离线消息

添加notification表,发送消息前先将消息缓存到数据库中,在用户上线时主动读取这些消息。客户端上线的消息类型属于Presence(在org.androidpn.server.xmpp.handler.PresenceUpdateHandler中执行):

StanzaHandler->PacketRouter->PresenceRouter->PresenceUpdateHandler

客户端增加了DeliverConfirmIQ,在收到消息后,主动通知服务器删除缓存。

服务器处理IQ的相关文件:DeliverConfirmIQ,IQDeliverConfirmIQHandler。

如果该消息在2周后依然无法送达则会主动删除(在配置文件中可以修改这个有效期)。

其他主要的一些修改

1. 服务器端通过引入javaPNS2.2.jar来增加对IOS推送的支持。

2. 增加一个新的用户表,它和apn_user中的用户存在一对一的映射关系。apn_user表是消息推送的直接用户,因为消息推送是直接推送给手机设备的。新增的用户表的则是为了连接业务操作,实际操作中推送消息是通过app的业务用户映射到apn_user表中记录的用户设备来完成。因为用户的登陆设备是可更换,所以用户每次登陆(验证短信)都要重新绑定用户名与设备标识(apn_user表中的username),就是移除旧的映射关系,建立新的映射关系,同时会记录用户的新设备类型(安卓还是苹果)。依据用户的设备类型,从而决定最终的消息发送方式。所有的发送模式都是最终获取一组apn_user表的用户数据,然后遍历它们完成消息推送操作的。

3. 关于apn_user表中的数据,安卓会在socket连接成功后,依据设备的IMEI到服务器上查询是否已有记录,没有则会生成新的随机用户名和密码,并记录设备IMEI。另一个用户表中的数据则是在APP账号首次登陆APP时通过访问服务器的API接口来创建,并建立与apn_user表中数据的映射关系,IOS设备可能会先自动创建一份apn_user表的数据再绑定。IOS设备的机器标识直接使用苹果APNS服务器所生成的token,android设备则使用随机字符串,但会记录设备的唯一标识IMEI,通过IMEI可以保障同一设备不会重复注册。

AndroidPn的更多相关文章

  1. AndroidPn源码分析(一)

    好了,开始研究源码了.目前对androidpn,只限于使用过它,跑了一下demo.现在开始研究一下源码. (一)入口 当服务器端启动的时候,控制台会打印一些log,除了spring和hibernate ...

  2. AndroidPN中的心跳检测

    在AndroidPN客户端里存在着心跳检测功能.就是每隔一段时间客户端向服务器端发送一个消息,以检测连接是否正常,发送的消息内容为: <presence id="h09Ke-13&qu ...

  3. 消息推送之androidpn部署

    androidpn客户端的部署在eclipse上,要记住两点: 1.直接导入的项目是上个世纪的lib这个文件夹,要改为libs.否则会报错找不到云云类. 2.如果在虚拟器上测试,要将res/raw/a ...

  4. 基于androidpn客户端修改的AndroidPNClient

    最近在做推送,采用的框架是androidpn,但对于客户端实在是修改得受不了了,特别是重连和连接那一块,有些BUG的修改实在是难以下手,比如在重连那里,原来的写法是在死循环中不断调用 xmppMana ...

  5. [android] androidPN开源项目介绍

    打开androidPN项目,会看到server和client两份代码 server部分 找到server的代码,开启服务,双击 bin/run.bat ,服务启动后监听127.0.0.1:7070端口 ...

  6. androidpn 推送系统

    (文中部分内容来自网络,如无意中侵犯了版权,请告之!) XMPP协议: XMPP : The Extensible Messaging andPresence Protocol. 中文全称:可扩展通讯 ...

  7. java.lang.NoClassDefFoundError: org.androidpn.client.PersistentConnectionListener

    在运行AndroidpnClient项目时出现了java.lang.NoClassDefFoundError: org.androidpn.client.PersistentConnectionLis ...

  8. AndroidPN环境建立

    AndroidPN环境 AndroidPN实现了从服务器到android移动平台的文本消息推送.这里先简单说一下androidPN的安装过程. 下载androidpn-client-0.5.0.zip ...

  9. Androidpn 简单实现及分析

    (文中部分内容来自网络) XMPP协议: XMPP : The Extensible Messaging andPresence Protocol. 中文全称:可扩展通讯和表示协议. 简介:可扩展通讯 ...

随机推荐

  1. Unity Ragdoll(布娃娃系统)

    逼真的动作如何实现的? 在一些游戏中当NPC或玩家死亡的时候,死亡的肢体动作十分逼真,这一物理现象如何用Unity来实现呢?Unity物理引擎中的Ragdoll系统,可以用来创建这种效果,具体请参阅以 ...

  2. JMeter学习(一)工具简单介绍

    一.JMeter 介绍 Apache JMeter是100%纯JAVA桌面应用程序,被设计为用于测试客户端/服务端结构的软件(例如web应用程序).它可以用来测试静态和动态资源的性能,例如:静态文件, ...

  3. $(window).load(function() {})和$(document).ready(function(){})的区别

    JavaScript 中的以下代码 : Window.onload = function (){// 代码 }  等价于  Jquery 代码如下: $(window).load(function ( ...

  4. 给ros安装arbotix simulator仿真环境

    首先下载程序包.编译.安装. cd ~/catkin_ws/src git clone https://github.com/pirobot/rbx1.git cd rbx1 git checkout ...

  5. excel技巧

    1. 使文字自动适配方格大小. 自动调整行高(但是合并后的方格不行)

  6. TestLink测试软件安装条件检查不通过的解决方案

    在第一次安装的时候出现这个错误信息 解决办法: 修改config.inc.php文件里的两个属性值为: $tlCfg->log_path = TL_ABS_PATH . 'logs' . DIR ...

  7. php中的ip2long和long2ip的理解

    IPv4地址是如何表示的 IPv4使用无符号32位地址,因此最多有2的32次方减1(4294967295)个地址.一般的书写法为用4个小数点分开的十进制数,记为:A.B.C.D,比如:157.23.5 ...

  8. iOS原生项目中集成React Native

    1.本文的前提条件是,电脑上已经安装了CocoaPods,React Native相关环境. 2.使用Xcode新建一个工程.EmbedRNMeituan [图1] 3.使用CocoaPods安装Re ...

  9. 表单 - Validatebox - 表单参数校验

    $("input[name='username']").validatebox({ required: true,//必填 validType:'email'//要求用户名必须是一 ...

  10. 探索Windows 8.1 Update 新功能点

    Windows 8.1 Update 已经使用一段时间了,整体感觉比Windows 8.1 方便了不少,尤其是对鼠标用户来说更是进行了很多优化. 应用磁贴尺寸 在应用磁贴点击鼠标右键,有小.中.宽.大 ...