Android推送通知指南:http://blog.csdn.net/joshua_yu/article/details/6563587
用androidpn来实现推送(Jclick):http://www.iteye.com/topic/1117043?page=13
Androidpn容易出问题的地方:
1,服务器端的监听器,看spring的配置文件就知道,服务器端用的监听器是org.apache.mina.transport.socket.nio.NioSocketAcceptor 也就是apache MINA;
2,客户端容易出问题的地方是在建立连接的时候。之前一直在建立连接的地方抛出异常,连接超时,显而易见是服务器端没有响应导致的,得检查服务器是否有问题。
解决问题的思路:客户端和服务器端建立连接,建立连接之后,服务器端会将客户端信息保存为一个用户,并把信息入库,所以,只需要找到保存user的地方,然后顺藤摸瓜,找到服务端和客户端进行数据交互的地方,最后找到服务端进行数据接收和发送的类大多在org.androidpn.server.xmpp.handle和org.androidpn.server.xmpp.net这个包中,客户端比较重要的地方应该是XmppManager,这个类有和服务器建立连接的地方,建立连接、注册、登录的操作都在这个类中,ConnectTask是XmppManager的内部类,主要作用是建立连接,XMPPConnection是一个connection,出现连接问题,可以打印出XMPPConnection的参数信息是否正确。
其他注意
(一)请修改 XmppServer 的start方法
屏蔽掉context = new ClassPathXmlApplicationContext("spring-config.xml");
改为ApplicationContextAware 接口中的
public void setApplicationContext(ApplicationContext context) throws BeansException
方法,获得ApplicationContext对象。
否则会启动了2个名为ioAcceptor的NioSocketAcceptor实例,可以查看log日志,在tomcat的log目录下的androidpn.log日志,浪费资源
而且在linux系统下会提示5552端口被占用
(二) <bean id="ioAcceptor" class="org.apache.mina.transport.socket.nio.NioSocketAcceptor"
init-method="bind" destroy-method="unbind">
修改成destroy-method="disponse">能快速关闭tomcat进程
(三)把用户系统融合到自己的应用中去,请修改org.androidpn.server.service.impl.UserServiceImpl
,使用自己系统的用户接口
(四)客户端自动注册使用的随机串,如果要使用自己系统的用户,客户端请修改org.androidpn.client.XmppManager 中的username和password
并用修改服务器端的用户身份验证类org.androidpn.server.xmpp.auth.AuthManager的public static AuthToken authenticate(String username, String token,
String digest) throws UnauthenticatedException 方法
开发中,大家的讨论很激烈:
zsg88 写道
在同一手机上运行2个客户端RESOURCE_NAME分别为AndroidpnClient和AndroidpnClient2
session.do页面显示2个在线,user.do页面显示一个在线。
打开UserController类,可以看到判断user是否在线的方法是presenceManager.isAvailable(user)
最终调用的是SessionManager
public ClientSession getSession(String username) {
// return getSession(new JID(username, serverName, null, true));
return getSession(new JID(username, serverName, RESOURCE_NAME, true));
}
注意:new JID(username, serverName, RESOURCE_NAME, true) 只指定了一个RESOURCE_NAME,表示只查找名称为RESOURCE_NAME所代表的应用用户,所以另外一个应用的用户就查找不到了。
把当前这行注释掉
把被注释的上一行打开,return getSession(new JID(username, serverName, null, true))
这里RESOURCE_NAME被设定为null,不指定具体应用名称
修改
public ClientSession getSession(JID from){
......
//if (from.getResource() == null || from.getNode() == null) {
// return null;
//}
if (from.getResource() == null) {
if (from.getNode() != null) {
for (ClientSession session : clientSessions.values()) {
if (session.getAddress().getNode().equals(from.getNode())) {
return session;
}
}
} else {
return null;
}
}
return clientSessions.get(from.toString());
}
非常感谢,你说的我测试了,如果广播信息的话,两个都可以收到。但是如果指定username发送的话,只有一个可以收到。我看了一下代码,还应该修改NotificationManager里面的
public void sendNotifcationToUser(String apiKey, String username,
String title, String message, String uri, String time) {
log.debug("sendNotifcationToUser()...");
IQ notificationIQ = createNotificationIQ(apiKey, title, message, uri,
time);
ClientSession session = sessionManager.getSession(username);
if (session != null) {
if (session.getPresence().isAvailable()) {
notificationIQ.setTo(session.getAddress());
session.deliver(notificationIQ);
}
}
}
把这个方法改成下面的就可以了。
public void sendNotifcationToUser(String apiKey, String username,
String title, String message, String uri, String time)
throws UserNotFoundException {
log.debug("sendNotifcationToUser()...");
IQ notificationIQ = createNotificationIQ(apiKey, title, message, uri,
time);
for (ClientSession session : sessionManager.getSessions()) {
if (session.getUsername().equals(username)
&& session.getPresence().isAvailable()) {
notificationIQ.setTo(session.getAddress());
session.deliver(notificationIQ);
}
}
}
zsg88 写道
在同一手机上运行2个客户端RESOURCE_NAME分别为AndroidpnClient和AndroidpnClient2
session.do页面显示2个在线,user.do页面显示一个在线。
还有两个问题。
1、情景是这样的:一个手机里面有多个客户端需要push服务,但是只有一个用户名,现在已经可以实现了。但是这种方式应该客户有多少个,后台的service就有多少个吧?能不能多个客户端公用一个service,第一个客户端启动后,就启动service,最后一个客户端关闭后才关闭service,service收到信息后再根据resource来决定要推给那个客户端?
2、如果手机1安装客户端1用username1登录后为session1,手机2安装客户端1用username1登录后为session2,这个session2只是session1的created time更新了,其他的不变,但是这个时候只有session2可以接收到信息,但是手机1没有收到任何提示信息,然而它永远也不能收到信息了。而且如果这个时候session1退出service的话,那么session2也关闭了,但是手机2的客户端还开着,然而它永远也连不上服务器了。我想当出现这种情况的时候给手机1一个提示信息,表示你的帐号在别处登录了。
cdztop 写道
zsg88 写道
在同一手机上运行2个客户端RESOURCE_NAME分别为AndroidpnClient和AndroidpnClient2
session.do页面显示2个在线,user.do页面显示一个在线。
还有一个问题。情景是这样的:一个手机里面有多个客户端需要push服务,但是只有一个用户名,现在已经可以实现了。但是这种方式应该客户有多少个,后台的service就有多少个吧?能不能多个客户端公用一个service,第一个客户端启动后,就启动service,最后一个客户端关闭后才关闭service,service收到信息后再根据resource来决定要推给那个客户端?
远程服务(Remote Sercie):
cdztop 写道
zsg88 写道
在同一手机上运行2个客户端RESOURCE_NAME分别为AndroidpnClient和AndroidpnClient2
session.do页面显示2个在线,user.do页面显示一个在线。
还有两个问题。
1、情景是这样的:一个手机里面有多个客户端需要push服务,但是只有一个用户名,现在已经可以实现了。但是这种方式应该客户有多少个,后台的service就有多少个吧?能不能多个客户端公用一个service,第一个客户端启动后,就启动service,最后一个客户端关闭后才关闭service,service收到信息后再根据resource来决定要推给那个客户端?
2、如果手机1安装客户端1用username1登录后为session1,手机2安装客户端1用username1登录后为session2,这个session2只是session1的created time更新了,其他的不变,但是这个时候只有session2可以接收到信息,但是手机1没有收到任何提示信息,然而它永远也不能收到信息了。而且如果这个时候session1退出service的话,那么session2也关闭了,但是手机2的客户端还开着,然而它永远也连不上服务器了。我想当出现这种情况的时候给手机1一个提示信息,表示你的帐号在别处登录了。
1、先仔细看看MINA框架,本来就是多个客户端公用一个service,但是是有数量限制的。。
2、这个也可以解决的,在用户登录的时候,去session里轮询下是否已经有登录的,有的话就把登录的退出。不难解决,关键还是要理清服务端的流程。