AndroidPn
客户端的主要包说明
org.androidpn.client包下的文件
- public class Constants { //包含静态数据
- public class InvalidFormatException extends RuntimeException { // 运行时所产生的错误处理
- public class LogUtil { //信息输出
- public class NotificationService extends Service { //后台运行并响应来自服务器的事件推送通知服务
- public final class ServiceManager { //管理的notificatin服务,加载配置
- public class XmppManager { // 管理客户端和服务器之间的连接
- public class ConnectivityReceiver extends BroadcastReceiver { // 网络变化广播接收器
- public class PersistentConnectionListener implements ConnectionListener { //连接关闭和重新连接事件的监听器 ,在XMPPManager中注册。
- public class PhoneStateChangeListener extends PhoneStateListener { //监听手机状态
- public class ReconnectionThread extends Thread { // 用于断线重连
- public class NotificationIQ extends IQ { // 来自服务器的推送消息
- public class NotificationPacketListener implements PacketListener {// NotificationIQ通知传入的数据包的接收,在XMPPManager中注册
- public class NotificationIQProvider implements IQProvider { //提过给XmppConnection的NotificationIQ 解析方式,在XMPPManager中注册
- public final class NotificationReceiver extends BroadcastReceiver { //推送通知消息的广播接收器
- public class Notifier { //通知用户,这里正式对消息进行处理,如发送本地通知等。
- public class NotificationSettingsActivity extends PreferenceActivity { // 设置信息
- 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证书目录等属性。
- public class Config { //读取配置信息
- public class ConfigManager { //应用程序配置信息管理
2. org.androidpn.server.xmpp
主要是包含有入口类XmppServer,这个类用来启动和停止server程序,
包里面定义了一些异常类型。
- public class XmppServer { //服务启动
3. org.androidpn.server.xmpp.auth
认证相关的一些类。
- public class AuthToken { //封装用户认证token 名字、域名
- public class AuthManager { //用户认证管理
4.org.androidpn.server.xmpp.codec
XMPP协议的XML文件解析包,通过这个包来进行xmpp协议数据传输的编码和解码。
- public class XmppCodecFactory implements ProtocolCodecFactory { //编码/解码器,用于解析XMPP消息。
- public class XmppDecoder extends CumulativeProtocolDecoder { //协议解码 (这里增加了心跳回送)
- public class XmppEncoder implements ProtocolEncoder { //协议编码 ,androidpn把加密放在了Connection 类中
5.org.androidpn.server.xmpp.handler
对消息的处理,我们可以针对不同的消息类型定义自己的handler。
- public class IQAuthHandler extends IQHandler {//APP连接时认证身份
- public abstract class IQHandler { //抽象类,处理客户端发来的IQ消息
- public class IQRegisterHandler extends IQHandler { //APP连接时处理用户注册
- public class IQRosterHandler extends IQHandler { //未使用,拉取好友列表
- public class PresenceUpdateHandler { //处理操作(APP连接时登陆成功后更新在线状态)
6.org.androidpn.server.xmpp.net
负责维护与client之间的持久连接,并实现了一些传输方式供发送xmpp消息时使用。
- public class Connection { //一个XMPP连接服务器的实例 所有与客户端的消息连接都通过本类来处理
- public interface ConnectionCloseListener { // 连接关闭监听
- public class IoBufferWriter extends Writer { //输入输出处理
- public class StanzaHandler { //处理传入的XML (增加了一个方法getClientSession)
- public class XmppIoHandler implements IoHandler { //创建新的会话,销毁会话,并提供接收XML
7.org.androidpn.server.xmpp.presence
只包含PresenceManager类,用来维护client的在线状态。
- public class PresenceManager { //它会调用SessionManager,用于判断某用户是否在线或获取用户当前的Presence。
8.org.androidpn.server.xmpp.push
只NotificationManager类包含有向client发送消息的接口。
- public class NotificationManager { // 消息推送入口
9.org.androidpn.server.xmpp.router
负责将收到的信息包发送到相应的handler进行处理,是一个路由包。
- public class IQRouter { //路由IQ消息到其相应的处理
- public class MessageRouter { //路由Message消息到其相应的处理程序
- public class PacketDeliverer { //将数据包发送到连接会话
- public class PacketRouter { //处理传入的数据包,并将它们路由到其相应的处理程序
- public class PresenceRouter { //路由Presence消息到其相应的处理程序
10.org.androidpn.server.xmpp.session
定义了用来表示持久链接的session,每个session包含一条连接的状态信息。
- public class ClientSession extends Session { //会话
- public abstract class Session { //会话抽象类
- public class SessionManager { //会话管理
11.org.androidpn.server.xmpp.ssl
对连接进行ssl认证的工具包。
- public class SSLConfig { //ssl配置
- public class SSLKeyManagerFactory { //负责产生ssl管理 实例
- public class SSLTrustManagerFactory { //SSL信任管理器工厂类
12.org.dom4j.io
输出输入流工具包
- public class XMPPPacketReader { // xml解析器
13.org.jivesoftware.openfire.net
- public class MXParser extends org.xmlpull.mxp1.MXParser { //解析器验证文件
14.org.jivesoftware.openfire.nio
- public class XMLLightweightParser { //一个轻量级的XML解析器
15.org.jivesoftware.util
- public class PropertyEventDispatcher { //事件调配
- public interface PropertyEventListener { //事件监听
- 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
客户端
- 提供了三个监听器对手机网络状态或连接状态进行监听,在状态变化时启动断线或重连操作。
- 重连的时间间隔(秒)
private int waiting() {
//waiting 在每次重连会自增1
if (waiting > 20) {
return 600;
}
if (waiting > 13) {
return 300;
}
return waiting <= 7 ? 10 : 60;
} - 在app操作中的任何一次页面切换都会判断服务的状态。
//如果服务未启动,则启动服务
private void startService(){
if(NotificationService.getNotificationService() == null){
// Start the service
ServiceManager serviceManager = new ServiceManager(this);
serviceManager.setNotificationIcon(R.drawable.ic_launcher);
serviceManager.startService();
}
} - ServiceManager实例化时会读取配置信息。
- ServiceManager的startService =>XmppManager的connect方法=>XMPPConnection的connect方法
- 连接时,执行登陆操作,在登陆前先判别是否需要注册,注册前先判别是否有连接,详细连接过程见XmppManager类。这个登陆类似于QQ一样,它先通过认证建立连接后,然后会要求使用用户名和密码来登陆,这组用户名和密码是随机生成的,每台设备对应唯一一组。
用户会话状态的维持
- mina框架提供了IoSession对象,IoSession维护着连接状态,并提供读写流,可以将信息发送给用户。
- IoSession中会创建Connection、Stanzahandler两个对象的实例,并持有它们。
- Stanzahandler中又创建了androidPN新增的ClientSession对象的实例,ClientSession对象又持有Connection对象。
- Connection对象中持有这两个Session成员: IoSession 和ClientSession 。
- SessionManager对象维护着一个Map,它存有设备标识(apn_user表的username)与用户会话ClientSession的映射关系,并提供了一个单例。
消息推送
安卓消息服务器端的推送流程
- NotificationManager的方法被调用,依据参数得到一组设备标识。
- 通过设备标识在SessionManager中检索可以匹配到ClientSession。
- 定义自己的xmpp消息格式并拼接出xml消息体。
- 通过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相匹配。
安卓消息服务器端的消息接收和处理
- 收到用户传输的数据时,首先经过IoFilter,完成消息的接收、编/解码等操作后。
- 解码操作由org.androidpn.server.xmpp.codec.XmppDecode来完成,解析完成后为每一个解码后的消息对象调用ProtocolDecoderOutput接口的write(Object)方法,将消息输出。
- 之后就开始消息的处理工作,以XmppIoHandler 的messageReceived方法为起点,后续StanzaHandler -> PacketRouter,然后依据消息体的类型选择对应的路由器,如处理IQ的IQRouter,Router再根据packet的namespace,选择对应的handler。
- handler进行处理。
router和handler类在androidpn中都有例子可以参考。开发中只要根据client发送消息的格式,定义自己的router和handler类,然后在PacketRouter中注册router,在IQRouter中注册handler即可。
客户端消息的接收
- org.jivesoftware.smack.PacketReader负责消息的接收。
- 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个连接状态:connected、authenticated、wasAuthenticated。
在不是主动下线(连接服务器时发生异常或者收到服务器的shotdown的要求)的情况下,被动断网后XmppConnection里的连接状态始终是connected,ConnectivityReceiver并没有被触发,重连操作无法正常执行,只是一路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的更多相关文章
- AndroidPn源码分析(一)
好了,开始研究源码了.目前对androidpn,只限于使用过它,跑了一下demo.现在开始研究一下源码. (一)入口 当服务器端启动的时候,控制台会打印一些log,除了spring和hibernate ...
- AndroidPN中的心跳检测
在AndroidPN客户端里存在着心跳检测功能.就是每隔一段时间客户端向服务器端发送一个消息,以检测连接是否正常,发送的消息内容为: <presence id="h09Ke-13&qu ...
- 消息推送之androidpn部署
androidpn客户端的部署在eclipse上,要记住两点: 1.直接导入的项目是上个世纪的lib这个文件夹,要改为libs.否则会报错找不到云云类. 2.如果在虚拟器上测试,要将res/raw/a ...
- 基于androidpn客户端修改的AndroidPNClient
最近在做推送,采用的框架是androidpn,但对于客户端实在是修改得受不了了,特别是重连和连接那一块,有些BUG的修改实在是难以下手,比如在重连那里,原来的写法是在死循环中不断调用 xmppMana ...
- [android] androidPN开源项目介绍
打开androidPN项目,会看到server和client两份代码 server部分 找到server的代码,开启服务,双击 bin/run.bat ,服务启动后监听127.0.0.1:7070端口 ...
- androidpn 推送系统
(文中部分内容来自网络,如无意中侵犯了版权,请告之!) XMPP协议: XMPP : The Extensible Messaging andPresence Protocol. 中文全称:可扩展通讯 ...
- java.lang.NoClassDefFoundError: org.androidpn.client.PersistentConnectionListener
在运行AndroidpnClient项目时出现了java.lang.NoClassDefFoundError: org.androidpn.client.PersistentConnectionLis ...
- AndroidPN环境建立
AndroidPN环境 AndroidPN实现了从服务器到android移动平台的文本消息推送.这里先简单说一下androidPN的安装过程. 下载androidpn-client-0.5.0.zip ...
- Androidpn 简单实现及分析
(文中部分内容来自网络) XMPP协议: XMPP : The Extensible Messaging andPresence Protocol. 中文全称:可扩展通讯和表示协议. 简介:可扩展通讯 ...
随机推荐
- Unity Ragdoll(布娃娃系统)
逼真的动作如何实现的? 在一些游戏中当NPC或玩家死亡的时候,死亡的肢体动作十分逼真,这一物理现象如何用Unity来实现呢?Unity物理引擎中的Ragdoll系统,可以用来创建这种效果,具体请参阅以 ...
- JMeter学习(一)工具简单介绍
一.JMeter 介绍 Apache JMeter是100%纯JAVA桌面应用程序,被设计为用于测试客户端/服务端结构的软件(例如web应用程序).它可以用来测试静态和动态资源的性能,例如:静态文件, ...
- $(window).load(function() {})和$(document).ready(function(){})的区别
JavaScript 中的以下代码 : Window.onload = function (){// 代码 } 等价于 Jquery 代码如下: $(window).load(function ( ...
- 给ros安装arbotix simulator仿真环境
首先下载程序包.编译.安装. cd ~/catkin_ws/src git clone https://github.com/pirobot/rbx1.git cd rbx1 git checkout ...
- excel技巧
1. 使文字自动适配方格大小. 自动调整行高(但是合并后的方格不行)
- TestLink测试软件安装条件检查不通过的解决方案
在第一次安装的时候出现这个错误信息 解决办法: 修改config.inc.php文件里的两个属性值为: $tlCfg->log_path = TL_ABS_PATH . 'logs' . DIR ...
- php中的ip2long和long2ip的理解
IPv4地址是如何表示的 IPv4使用无符号32位地址,因此最多有2的32次方减1(4294967295)个地址.一般的书写法为用4个小数点分开的十进制数,记为:A.B.C.D,比如:157.23.5 ...
- iOS原生项目中集成React Native
1.本文的前提条件是,电脑上已经安装了CocoaPods,React Native相关环境. 2.使用Xcode新建一个工程.EmbedRNMeituan [图1] 3.使用CocoaPods安装Re ...
- 表单 - Validatebox - 表单参数校验
$("input[name='username']").validatebox({ required: true,//必填 validType:'email'//要求用户名必须是一 ...
- 探索Windows 8.1 Update 新功能点
Windows 8.1 Update 已经使用一段时间了,整体感觉比Windows 8.1 方便了不少,尤其是对鼠标用户来说更是进行了很多优化. 应用磁贴尺寸 在应用磁贴点击鼠标右键,有小.中.宽.大 ...