AndroidPN的入门
- 推送方案介绍
1、常见的推送应用:软件更新 + 商家推送的消息
2、邮件到达的提示消息 - 推送方式:
1、Push(推模式):服务端向客户端发送
2、Pull(拉模式):客户端向服务端请求 - 常见的推送方案
基于XMPP的协议的Androidpn
Androidpn框架搭建
xmpp + Spring + Hibernate + SpringMVC + Ehcache + mina
- 服务端的修改
1、修改相应的配置文件:
①、jdbc.properties:数据库连接的基本属性信息
②、config.properties:服务器配置的相关信息(ip + 默认端口号(5222))——修改成本地IP
admin.console.host=127.0.0.1 //设置成本地的IP
admin.console.port=7070 //端口号可以不修改
③、hibernate.cfg.xml:数据库连接的信息——修改连接数据库的信息(与jdbc.properties文件有冗余,最好两个都修改下)
<!-- Database connection settings -->
<property name="hibernate.connection.driver_class">org.hsqldb.jdbcDriver</property>
<property name="hibernate.connection.url">jdbc:hsqldb:db/androidpn;shutdown=true</property>
<property name="hibernate.connection.username">sa</property>
<property name="hibernate.connection.password"/>
<!-- SQL dialect -->
<property name="hibernate.dialect">org.hibernate.dialect.HSQLDialect</property>
注意:数据库androidpn必须提前先创建
Mapping_info + 用于初始过程反向生成table:User(启动时会创建的表格信息)
//hibernate.cfg.xml文件
<mapping class="org.androidpn.server.model.User"/>
修改好后就可以/bin/run.bat运行服务器了(注意run.bat中要配置了正确的JAVA_HOME)
但是这样修改后倒入MyEclipse运行服务器还是会报这样一个错误:Cannot load jdbc driver class…,原因是我们修改了Androidpn原来的服务器的数据库编程自己使用的MySQL,因此要倒入自己的sqljdbc.jar包导入到lib中
之后再运行即可:http://loclahost:7070
- Androidpn客户端修改
1、修改res/row/androidpn.properties文件中客户端和服务器请求的Host和Port
xmppHost=192.168.0.5 //修改成自己的本机
xmppPort=5222 //如果这个客户端端口要修改的话则要在服务端/config/spring-config.xml文件
<property name="defaultLocalAddress" value=":5222"/>
2、修改后运行有可能会出错:Link of class … fail
找不到链接依赖的库(这有可能是SDK版本不一样,lib目录变成了libs目录),将lib改成libs目录后先删除错误依赖的jar包后再重新导入即可。
修改成功后,即可运行,实现服务端向客户端信息的推送
但是有以下几点地方是要修改的
1、服务端推送了多条消息,点开后显示的都只是最后一条推送的消息,这是客户端接收的问题
2、如何集成到现有的web项目
3、数据库不一样该怎么修改
4、加入使用的框架不是SSH,该如何改动
5、发送自定义的消息包
将androidpn_server改进成Tomcat web项目
androidpn-Server src目录介绍
1. Maven构建环境(Androidpn的实现是基于Maven的)
2. Androidpn_server包含了三个工程:Server + Console + Starter
3. Maven导入Androidpn常见的问题
将 androidpn-Server该进程Tomcat web项目
Androidpn使用的服务器是jetty而不是Tomcat,因此如果自己的项目是使用tomcat作为服务器的时候,就应该改进Tomcat
1、项目框架构建:Hiberate + Spring + SpringMVC
2、WEB CONTENT:赋值Console web文件 +Web.xml.schema声明方式
3、Resourses:配置文件
4、整合src代码:Console、Server可能会引入的问题:lib引入的问题(从源码中拷贝 + 数据库驱动包)
1、包冲突
2、找不到XXX包改进过程中涉及到的问题
1、Hiberate + Spring + SpringMVC的项目相关配置
2、通讯端口:默认是5222,如果是企业的话有专门的网络管理
3、server/src/main/java/org目录下的源码的中全部代码拷到自己的项目中去 + server/src/main/sresources配置文件(多了conf.security配置文件) + 将要引用的库放到WEB_INF/lib目录下 + console下的org + starter代码
4、引入jar包是不要引入与jetty相关的包(jasper + jetty不用)将 androidpn-Server该进程Tomcat web项目总结
1、首先Androidpn采用的服务器是jetty,如果使用Tomcat做服务器的话就要移除或者屏蔽jetty的相关配置信息,添加Tomcat的配置信息(libm目录的Spring、Hibernate、SpringMVC)
2、Androidpn的实现框架的话是基于Maven的,如果使用SSH作为项目框架的话也要修改相应的配置文件信息(Web.xml、Spring.xml、hibernate.cfg.xml、conf.properties)
4、Androidpn服务器默认的数据库是HSQLDB,如果采用的是MySQL数据库的话则要添加相应的jar包和修改连接数据库的相应信息(jdbc.properties、MySQL.jar)。
5、以及重要类库的改动:XmppServer.java与UI路径的改动
Androidpn体系结构和消息推送流程分析
Androidpn概述
- androidpn是一个基于xmpp开源组件的一个整合方案
1、服务端:openfire + apache mina
2、客户端:基于smack的asmack - 技术支持
1、Spring + Hibernate + SpringMVC
2、socket + Thread + XML
androidpn消息推送流程
- 建立连接(XMPP + XML)
- 服务端消息推送
- 客户端接收和显示
- 客户端发送消息
Server端代码结构
dao + model + service + util(加载resource中的配置文件) + xmpp(推送的核心包,入口类为XmppServer,用来启动和停止Server程序)
- server.xmpp包结构说明
1、auth:认证信息类,可以扩展认证模块(自定义自己的认证方式)
2、codec:xmpp协议的xml文件解析包,server收发消息通过此包进行编码和解码(可自定义自己的编码和解码规则)
3、handler:消息处理(根据自己的消息类型定义自己的消息handler)
4、net:负责客户端与服务端持久的连接
5、presence:用来维护客户端的在线状态(PresenceManager)
6、push:服务端向客户端发送消息(NotificationManager)
7、router:将受到的消息包发送到相应的Handler进行处理
8、session:定义了用来表示持久链接的session,每个session包含了一条连接的状态信息
9、ssl(Socket security layer):连接进行ssl认证的工具包
关于apache mina
xmpp包含的两个核心:Apache mina +
核心:Socket的连接管理以及通信的IO操作
- Apache mina涉及到的类
1、 Socket的连接管理
2、I/OServer:负责实际的IO操作
3、I/O Filter Chain:IO操作中设计到数据的加密、编码、压缩等
4、. IO Handler(apace mina的应用层):负责实际的业务逻辑处理,这是开发人员要关注的(实现的类为XMPPHandler) - Apache mina 实现的基本流程
1、IOAcceptor监听客户端的连接
2、连接成功后创建一个Session
3、Session接收到数据后过滤器
4、最后将数据交给handler处理
Androidpn客户端的Asmack
- Asmack的简单介绍
1、smack:基于XMPP协议的及时通信客户端编程库(J2EE)
2、Asmack:smack库的Android版本 + 基于xmpp协议与服务器端的Socket连接 - 客户端服务器之间通信流程图解
Androidpn 客户端执行流程
client主要包括消息的收发、解析以及持久连接的发起
涉及到的类
1、XmppManager:主控制器,业务逻辑的核心代码,NotificationService通过这个类,在后台维护与服务器的连接
2、Notifier:客户端发送通知的类
3、ServiceManager:管理消息服务和加载相关配置
4、NotificationSettingActivity:推送消息页面设置的类
。。。Androidpn客户端执行的流程
1、创建服务ServiceManager
在构造方法中读取配置文件的信息(XMPP连接的主机啊、IP啊、Activity的类名啊,用于回调)并保存在sharePreference中,下次的的话就不用再读取配置文件而直接从sp中取就行了
2、启动服务
Thread serviceThread = new Thread(new Runnable() {
@Override
public void run() {
Intent intent = NotificationService.getIntent();
context.startService(intent);
}
});
serviceThread.start();
- androidpn客户端涉及到的任务
1、涉及到连接的任务ConnectTask
2、注册和登录任务:RegisterTask + LoginTask
3、客户端接收/发送消息流程
①、NotificationPacketListener
做的事情有:
一直坚挺从服务器发送过来的数据包Packet
重复执行数据包的解析:NotificationIQ(客户端现有的消息结构:id、apiKey、title、message、uri)——Intent
发送广播:sendBroadcast给NotificationReceiver
②:NotificationReceiver的onReceive方法接收广播
③:notificationDetailActivity回发消息
封装消息成IQ
XMPPConnection的sendPacket方法回发消息 - Server发送消息流程
1、NotificationManager的push接口被调用
①使用Sessionanager 在当前session集合中查找相应的client连接
②XMPP消息格式
2、通过相应的Session,想Client发送消息 - Server接收消息的流程
1、connection收到packet,使用codec解码消息
2、router根据packet的namespace信息,将packet路由到相应的handler
3、handler进行处理
Androidpn的不足地方及修改
1、服务器重启,客户端如何重新连接
2、消息处理
①、服务器收到消息后如果知道要发给哪个
②、服务器如何保存消息
③、消息如何跟踪:用户是否收到消息、用户是否读取消息
④、客户端离线如何处理消息
Androidpn服务端发送自定义消息
(androidpn服务器端自定义消息及消息处理流程)
(客户端XmppManager类中的三个线程(连接、注册和登录三个任务)与服务器端交互)
各种消息的处理
- 连接以及消息发送的数据处理
1、客户端请求连接的时候用创建Session对象保存客户端的相关连接信息
2、接收客户端发送过来的XML消息,之后交给StanzaHandler类中的process方法用于处理XML消息
3、XML消息处理完之后将是数据的发送处理,该数据为一个raw数据 - Login消息的处理
登录时首先要判断是否有该用户,没有则启动RegisterTaste任务线程 - IQRegisterHandler处理
用户注册成功,则将数据保存在 - 客户端close的消息处理
当客户端服务stop的时候向服务器发送“不可用消息”
消息包的结构(xml文件)
(会在stanzaHandler中处理)
<stream>
<presence> // 用户状态
</show>
</presence>
<message to='foo'>
<body/>
</message> // 用户发送的消息
<iq to=bar'> //iq:信息/请求(认证信息 + 注册信息+ 联系人列表roster,Androidpn中没有写,要自己实现)
</query>
</iq>
</stream>
简单的业务应用
- 应用场景
电信给客户经理推送工单信息
工单信息包含有工单的各种状态 - 需求
客户经理收集客户端要分别收到:
①各种状态的工单数目
②各种不同状态需要不同的通知图片
③通过通知进入不同攻打状态的UI进行处理 - 解决方案
消息包的扩展和处理
服务器端的消息处理
NotificationManager.createNotificationIQ + 自定义封装IQ + 在用到这个函数的地方也要改(sendXXX)
//在这里扩展成自己的数据类型,使用如下代码来添加新的XML元素:notification.addElement("uri").setText(uri);
private IQ createNotificationIQ(String apiKey, String title,
String message, String uri) {
Random random = new Random();
String id = Integer.toHexString(random.nextInt());
// String id = String.valueOf(System.currentTimeMillis());
Element notification = DocumentHelper.createElement(QName.get(
"notification", NOTIFICATION_NAMESPACE));
notification.addElement("id").setText(id);
notification.addElement("apiKey").setText(apiKey);
notification.addElement("title").setText(title);
notification.addElement("message").setText(message);
notification.addElement("uri").setText(uri);
IQ iq = new IQ();
iq.setType(IQ.Type.set);
iq.setChildElement(notification);
return iq;
}
自定义编码解码的扩展
自定义用户验证的扩展
IQRegisterHandler:用户信息的扩展
IQAuthHandler:用户验证信息扩展
IQRosterHandler:所有用户 + 所有在线/离线用户扩展
Androidpn客户端自定义消息和逻辑处理
消息处理:
(添加消息 + 修改消息的XML解析 +监听消息的到达并封装成实体类NotificationIQ,并广播 + 广播后NotificationReceiver.onReceive中接收并且通过Notifier.notify方法显示在通知栏 + 点击通知栏后再NotificationDetailActivity.onCreate中显示)
1. 自定义消息时需要定义的3个类
1、xxIQ定义消息的实体
2、xxIQProvider将消息转化为xxIQ实体
3、对实体进行处理
2. 具体的实现可参考如下三个类:
1、NotificationIQ:extendsIQ,消息实体
2、NotificationIQProvider:parseIQ,封装IQ,将接收的xml数据转换成实体
3、NotificationPacketListener:IQ处理
①将IQ数据存入到Intent数据中
②将intent数据广播出去:xmppManager.getContext().sendBradcast(intent)
4、之后广播的消息由NotificationReceiver类中的onRecevier方法接收,其中会调用Notify与Notification类建立起关联关系
消息处理:注册
- 在XmppServerManager中注册,参考如下三个类
1、LoginTask:NotificationIQ + NotificationPacketListene
2、ConnectTask:NotificationIQProvider
应用扩展:用户
- 用户注册信息:XmppManager.RegisterTask—IQRegister
- 用户登录验证:XmppManager.LoginTask—IQAuthHandler
- 用户好友列表:IQRosterHandler
Android客户端的改进
通讯机制的改进
1. 关于心跳处理(Socket)
2. 服务器掉线重连(现有的客户端在服务器停止后不会重连)
3. Wakeup lock
4. 用户验证改进
5. 网络选择:WiFi—3G、GPRS
通知服务的改进
(后台运行的服务)
1. 开机启动服务
2. 退出程序:退出或不退出服务
通知消息的改进
- 通知各种消息模式
1、保存最后一条消息
2、所有消息
3、消息归类 - 通知回写服务器(现有的Androidpn服务端对客户端已阅读的消息没有回写,需改进)
- 自定义通知UI
xmpp客户端asmack源码可能要改动,下载源码替代原来的jar包XMPPConnection对象)
XMPPConnection:创建连接XMPP服务器的Socket对象
(服务端使用mima,实际上是对socket连接的管理)
- sendPacket方法:发送消息包
还有建立连接的方法(匿名连接 + 提供用户密码的连接 ) - startKeepAliveThread:保持长连接的机制
XMPPManager
- ConnetTask:负责连接服务器的线程(服务器主机、端口、连接安全的配置、connect()发起连接),最后将任务加入到任务嘟列钟来
1、如果没有连接到服务器,程序会从sp中读取服务器主机ip和端口号,并使用XMPPConnection通过配置信息实例化一个连接对象向服务器发起连接;连接成功调用XMPPManager runTask方法来执行之前添加到任务集合中的任务RegisterTask,同时TaskTracker计数减一 - LoginTask
先登录,但是要有连接、其次是要有注册 - RegisterTask
线程管理:线程池
客户端服务器的连接
- 长连接机制
- 心跳机制
1/按需来发送信息,而不是时刻都与服务器保持连接
2、SmackConfiguration:keepAliveInterval= 30000(30秒),即每个30秒通信一次,发送一个空的字符
3、如果发送失败,则作为异常处理:重新连接(自己修改代码)
4、数据包超时响应的时间:packetReplyTimeout
5、客户端不能重连:服务端重启或晚于客户端启动 +网络类型的切换
综上所述,改进为:
1、登录之后保持长连接或者心跳连接
2、客户端重连
通讯建立
- 通知服务:NotificationService类
- 按需服务管理
开机启动服务:booterReceiver广播接收器,把开机的广播接收器交给ServiceManager,
- 程序退出方式:退出程序后是否关闭服务
- 普通优先级的service会在系统资源不够的时候,会被自动回收(kill)
关于程序休眠
如果保持长时间待机时,程序休眠问题引起通讯不正常,wake_lock
通讯安全的改进
- 用户注册:
1、添加用户注册信息
2、设备ID最为用户的唯一ID
3、后台管理记录设备ID(绑定用户)
4、参考Google Map API - 验证改进:多终端用户 + 单一终端用户
服务端消息通知
(不覆盖 + 分类)
1. 原来的Androidpn消息通知问题
1、当服务端连续发送多跳消息是,客户端都只显示同一条消息内容
2、当服务端连续发送多跳消息是,客户端都只显示各自的通知内容
- 改进:
requestCode :表示通知的不同类型 - PendingIntent
消息的回发
- 客户端收到通知后告诉服务器
- 如何改进:
1、回发动作:收到通知回发给服务器NotificationPacketListener收到消息后向服务器会送一个IQ消息,如果服务端没有收到该消息,则请求重发
2、阅读完消息之后怎么做:已读消息的回发
自定义通知的UI