最近在尝试用AndroidPn(Android Push Notification),配置就不说了,网上很多如下。
XMPP协议:
XMPP : The Extensible Messaging andPresence Protocol.
中文全称:可扩展通讯和表示协议.
简介XMPP可用于服务类实时通讯、表示和需求响应服务中的XML数据元流式传输。
XMPP(可扩展消息处理现场协议)是基于可扩展标记语言(XML)的协议,它用于即时消息(IM)以及在线探测。
它在促进服务器之间的准即时操作。这个协议可能最终允许因特网用户向因特网上的其他任何人发送即时消息,即
使其操作系统和浏览器不同。
XMPP主要显著的优点主要有以下几个方面:
1、分布式 任何人都可以运行自己的XMPP服务器,它没有主服务器,客户端简单
2、安全性很高。使用SASL及TLS等技术的可靠安全性
3、开发性 它是开源的,易于进行学习和了解
4、跨平台 毋庸置疑,使用的XML数据格式进行传输的
Androidpn:
Androidpn :android pushnotification(中文名称:Android消息推送)。
基于XMPP协议的java开发有一个开源框架,那就是smack,它主要封装了一些XMPP的实现。在引用smack的基础上
实现和服务器端的持久连接,以实现服务器对客户端的推送,那就是Androidpn。Androidpn在客户端集成了smack。
这样就可以很容易的简立一个和服务器端的基于xmpp协议的socket连接。所以Androidpn可以说是使用了smack框架
的开源项目。
Androidpn使用好处:
用Androidpn好处有以下方面:采用完全开放的XMPP协议进行数据传输(QQ,MSN,GTalk等都是采用的这种协议)。
良好的框架支持(专门为android 而产生的推送框架smack,以及很好的管理socket的框架MINA,都是很成熟的产品);
完全开放的源代码(我们可以在Androidpn的基础上进行修改,来满足我们的任何需求变更);大大的减少了客户端的代
码,降低了android的开发难度。
Androidpn技术实现:
(这里就不说下载源码后怎么操作了,网上教程颇多)
客户端与服务器建立socket连接。
Androidpn客户端,进行管理连接的信息,比如XMPP的端口、IP(域名)、登录的用户名密码,以及对连接的维护(定时的
发送连接请求保持连接不失效)。整个服务器端和客户端的通信是基于一个session(会话)过程,会话开始,首先会
指定服务器的端口号,然后把信息发送到服务器端;而向服务器发送消息:<stream>根节点的方式开始传递,只有在服
务器和客户端关闭的时候才会发送它的结束标记</stream>。以客户端通过XMPP协议只用做的就是接收消息,而所有
其它的操作都交给服务器,比如管理连接、消息保存等等,这样就很大程度的减轻了客户端的负担。
上段截取自http://www.cnblogs.com/kobe8/p/3976923.html
下面谈谈一些使用和问题
其实重要的就是需要到Android-client包里的所有类和asmack.jar包,配置我们的客户端后,拿到服务器端给的网页端地址和Host,在androidpn.properties中把xmppHost改成服务器端告诉你的host,客户端和服务器建立连接是通过serverManager类完成的:
serviceManager = new ServiceManager(this,sId);
serviceManager.setNotificationIcon(R.drawable.tab_assets);
serviceManager.startService();
这里源代码是通过XmmpManager里面的这个函数生成一个唯一的标识:
private String newRandomUUID() {
String uuidRaw = UUID.randomUUID().toString();
return uuidRaw.replaceAll("-", "");
}
如果不想使用随机函数,我们可以根据自己的需求设置唯一用户名标识,只要在startService之前传入到XmmpManager里面即可,也可以让后台生成唯一标识传给客户端,例子这里是在ServiceManager里面多加入一个构造方法把传来的sessionId拿到。
public ServiceManager(Context context, String sessionId) {
this.context = context;
if (context instanceof Activity) {
Log.i(LOGTAG, "Callback Activity...");
Activity callbackActivity = (Activity) context;
callbackActivityPackageName = callbackActivity.getPackageName();
callbackActivityClassName = callbackActivity.getClass().getName();
}
// apiKey = getMetaDataValue("ANDROIDPN_API_KEY");
// Log.i(LOGTAG, "apiKey=" + apiKey);
// // if (apiKey == null) {
// // Log.e(LOGTAG, "Please set the androidpn api key in the manifest file.");
// // throw new RuntimeException();
// // }
props = loadProperties();
apiKey = props.getProperty("apiKey", "");
xmppHost = props.getProperty("xmppHost", "127.0.0.1");
xmppPort = props.getProperty("xmppPort", "5222");
Log.i(LOGTAG, "apiKey=" + apiKey);
Log.i(LOGTAG, "xmppHost=" + xmppHost);
Log.i(LOGTAG, "xmppPort=" + xmppPort);
sharedPrefs = context.getSharedPreferences(
Constants.SHARED_PREFERENCE_NAME, Context.MODE_PRIVATE);
Editor editor = sharedPrefs.edit();
editor.putString(Constants.API_KEY, apiKey);
editor.putString(Constants.VERSION, version);
editor.putString(Constants.XMPP_HOST, xmppHost);
editor.putInt(Constants.XMPP_PORT, Integer.parseInt(xmppPort));
editor.putString(Constants.CALLBACK_ACTIVITY_PACKAGE_NAME,
callbackActivityPackageName);
editor.putString(Constants.CALLBACK_ACTIVITY_CLASS_NAME,
callbackActivityClassName);
editor.putString(Constants.SESSION_ID,sessionId); //在Sp中存储真正的用户名,建立连接时要使用
editor.commit();
// Log.i(LOGTAG, "sharedPrefs=" + sharedPrefs.toString());
}
我们为了能在服务器端重启后让客户端重连,需要在XmppManager中的AddTask方法的同步块里的else里加入一句runTask即可。
最后,我们运行程序,连接建立完成我们就可以在网页看到这个用户状态,在notification.do中发送一个推送,客户端能接受证明你配置成功了。
下面说说我用androidpn做Android单点登录的要点:
1.和服务器约定好,每次同个用户在不同设备登录都记录最新的Session,然后对旧的session发送下线通知(j建议登录时候后台返回一个唯一标识用来做session的创建)
2.关于Server在android5.0以上要显示调用的问题(需要修改其源码,在服务启动时),可以参考http://blog.csdn.net/nzzl54/article/details/55211660
3.当App重启或杀死的时候,将无法收到推送,此时需要在启动App的时候请求接口去查询这台机器是否应该是要下线的那台
4.退出登录时一定要记得stopServeice,并且清空用户名和sessionId,以防下次登录出现问题
public void logout() {
if (serviceManager != null) {
serviceManager.stopService();
Log.e("lenita","serviceManager.stopService()");
}else {
Log.e("lenita","serviceManager == null");
}
//清除用户名
SharedPreferences sharedPreferences1 = ViewHelperTestActivity.this.getSharedPreferences(Constants.LOGIN_STATUS,Context.MODE_PRIVATE);
SharedPreferences.Editor editor1 = sharedPreferences1.edit();
editor1.putString("userName","");
editor1.commit();
//清除sessionId
SharedPreferences sharedPreferences2 = ViewHelperTestActivity.this.getSharedPreferences(Constants.SHARED_PREFERENCE_NAME,Context.MODE_PRIVATE);
SharedPreferences.Editor editor2 = sharedPreferences2.edit();
editor2.putString("userName","");
editor2.commit();
startActivity(new Intent(MainTestActivity.this, LoginTestActivity.class));
finish();
}