要实现离线消息推送服务器端
阅读
openfire
源码后发现,如果要实现离线消息推送服务器端,我们必须找到
(
1
)接收信息广播,并且经过一些列的处理(和源代码相同逻辑),最终到达我们要进行推送的逻辑
(
2
)在存储离线消息的位置发出自定义
iq
,自定义插件对
iq
进行处理,到达我们的推送逻辑
(
3
)使用数据库触发器,数据库中有离线消息存储就触发调用远程
java
方法,从而到达我们的推送逻辑
(1)
经过阅读源码,发现其发送广播的位置过早,如果要接收广播并进行一些列处理的话,逻辑过于复杂
(2)
这种方法会造成修改
openfire
源码,不便于
openfire
升级
(3)
这种方法会增大数据库压力,同时需要使用
c
来写一个
mysql
扩展,来实现发送未读消息信息到推送逻辑的过程。
最终确定试验(
2
)(
3
)两种方案
推送逻辑:
jid
和
deviceid
存储于一个自定义表中
每次用户登录会把自己的
jid
和
deviceid
存储到表中
推送数据:
根据
message
中的
jid
和从表中获取到相对应的
deviceid
,组成
push
条件,推送消息,推送的消息必须进行处理,将以前约定的特殊标志串去除,分别是文本、图片、音频
下面讲解最终实现方案。
个人与个人聊天记录存储在ofoffline表中,群组聊天记录存储在缓存中,两种实现方案不一致,因此需要在两个位置进行自定义聊天记录IQ发送
定位后:
个人聊天插入点:OfflineMessageStore.addMessage
群聊插入点:LocalMUCUser.process
插入方式:将发送iq 的复杂逻辑提取成一个工程,在openfire源码使用时引用jar包。
相关iq接收处理:
(1)接收设备信息:
<iq id="***" type="set"from="***">
<query xmlns="***">
<username>111</username>
<method>store</method>
<token>sdsdsd</token>
<type>1</type>
<language>zh</language>
</query>
</iq>
删除iq
<iq id="***" type="set" from="***">
<query xmlns="***">
<username>111</username>
<method>del</method>
</query>
</iq>
(2)在处理离线消息位置插入自定义iq发送 public void sendPushIQ(String username,String body){
PacketRouter packetRouter = XMPPServer.getInstance().getPacketRouter();
IQ reply = new IQ();
reply.setType(Type.set);
Element probeResult = DocumentHelper.createElement(QName.get("query", "******")) ;
probeResult.addElement("username").setText(username);
probeResult.addElement("body").setText(body);
reply.setChildElement(probeResult);
packetRouter.route(reply);
}
(3)自定义插件接收自定义iq,进行处理:
其中ios推送的代码如下
public static void push( String deviceToken,String content){
try {
//被推送的iphone应用程序标示符
PayLoad payLoad = new PayLoad();
payLoad.addAlert(content);
payLoad.addBadge(1);
payLoad.addSound("default");
PushNotificationManager pushManager = PushNotificationManager.getInstance();
pushManager.addDevice("iphone", deviceToken);
//Device c = pushManager.getDevice("iphone");
String host= "gateway.sandbox.push.apple.com"; //测试用的苹果推送服务器
int port = 2195;
//注意在linux中插件路径问题
String certificatePath = "E:/***.p12";
String certificatePassword= "***";
pushManager.initializeConnection(host, port, certificatePath,certificatePassword, SSLConnectionHelper.KEYSTORE_TYPE_PKCS12);//初始化tcp连接
//Send Push
Device client = pushManager.getDevice("iphone");
pushManager.sendNotification(client, payLoad); //推送消息
pushManager.stopConnection();
pushManager.removeDevice("iphone");
}
catch (Exception e) {
e.printStackTrace();
System.out.println(e.getMessage());
}
System.out.println("push succeed!");
}