本文很多基本内容木有讲,比如XMPP协议、MQTT协议的具体细节,楼主懒,不断完善中,争取慢慢加进来,传送门 MQTT协议简介
最近项目有要用到消息推送,于是仔细研究了一下消息推送
消息推送原理基本上就是利用Socket长链接,通过设置心跳,来保证自己是在线状态
目前安卓消息推送的几种方案:
XMPP方案:成熟的案例是AndroidPN,网址http://sourceforge.net/projects/androidpn/
1、XMPP协议采用xml格式,大致如下
<stream>
<presence>
</
presence>
<message>
<body>
</body>
</message>
<iq>
</iq>
</stream>
2、XMPP安卓实现:Smack客户端jar包 + Openfire (服务器端)+Spark(测试用)
这里要说明一点是,Smack自从4.0版以后默认支持安卓客户端了,可以不用asmack了,但是Smack给的文档里面没有说清楚需要引用的Jar包,一直报错,楼主当时找了好久,终于弄全了,大致需要以下几个Jar包,可能可以精简
smack-android-4.1.5.jar
smack-android-extensions-4.1.5.jar
smack-extensions-4.1.5.jar
smack-core-4.1.5.jar
smack-im-4.1.5.jar
smack-tcp-4.1.5.jar
smack-experimental-4.1.5.jar
jxmpp-core-0.4.1.jar
jxmpp-util-cache-0.4.1.jar
smack-sasl-provided-4.1.5.jar
smack-resolver-minidns-4.1.5.jar
minidns-0.1.7.jar
不过楼主没用XMPP做消息推送,而是用来做即时消息通信了
MQTT(简介就自己百度了)
主要原理是服务端把消息发送到消息中间件Broker,由消息中间件来负责推送到客户端
1、MQTT协议格式:固定头长度只有2个字节,轻量,省流量,但是MQTT是基于消息订阅的,一般不支持点对点推送
2、MQTT消息推送搭建
服务器端:代码基本等同于下面Android客户端
消息中间件Broker的选择:目前支持MQTT协议的有ActiveMQ、Active Apollo(ActiveMQ的下一代产品)、Mosquito等。其实做消息推送,性能主要是看这个Broker能力了。
楼主采用的Apollo,貌似出现过丢失情况
Android客户端(需要添加相关jar,楼主用的是mqtt-client-0.4.0.jar,或者在Eclipse加载org.eclipse.paho.mqtt.java.zip:
/**
* MQTT消息推送服务
*/
public class MQTTService extends Service {
protected static final String TAG = "MQTTService";
/**客户端连接标识*/
private String clientId = "melody";
private MqttClient mClient;<span style="white-space:pre"> </span><pre name="code" class="java"><span style="white-space:pre"> </span>private static final String userName = "admin";<span style="font-family: Arial, Helvetica, sans-serif;"> </span>
<span style="white-space:pre"> </span>private <span style="font-family: Arial, Helvetica, sans-serif;">static </span>final String userPwd = "password";
<pre name="code" class="java"><span style="white-space:pre"> </span>private static final int Timeout= 20;
<pre name="code" class="java"><span style="white-space:pre"> </span>private <span style="font-family: Arial, Helvetica, sans-serif;">static final </span>int Heart_Interval= 30;
private MemoryPersistence persistence;/**MQTT连接设置*/private MqttConnectOptions options;/**订阅的主题*/private String[] topicFilters = new String[]{ "sport", "movie", "news" };/**消息质量,0表示至多一次,1表示至少一次,2表示只有一次*/private int[] mQos = new int[]{ 0, 0, 1, 2 };/**消息主题*/private MqttTopic mTopic;private MqttMessage mMessage;private NotificationManager mManager;private Notification.Builder builder;private int notiId = 1;/** */@Overridepublic IBinder onBind(Intent intent) {return null;}/** * 创建时初始化,MQTTClinet,并连接 */@Overridepublic void onCreate() {mManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);builder = new Notification.Builder(this);builder.setSmallIcon(R.drawable.app_icon);PendingIntent intent = PendingIntent.getActivity(this, 1, new Intent(this, MQTTTestActivity.class),PendingIntent.FLAG_CANCEL_CURRENT );builder.setContentIntent(intent);
try {
persistence = new MemoryPersistence();
mClient = new MqttClient(Constants.SERVER_NOTIFY_URI, clientId, persistence);
options = new MqttConnectOptions();<span style="font-family: Arial, Helvetica, sans-serif;"> </span>
options.setCleanSession(false); <span style="font-family: Arial, Helvetica, sans-serif;">//设置离线是否清理session</span>
options.setUserName(<span style="font-family: Arial, Helvetica, sans-serif;">userName</span><span style="font-family: Arial, Helvetica, sans-serif;">);</span>
options.setPassword(<span style="font-family: Arial, Helvetica, sans-serif;">userPwd</span><span style="font-family: Arial, Helvetica, sans-serif;">.toCharArray());</span>
options.setConnectionTimeout(<span style="font-family: Arial, Helvetica, sans-serif;">Timeout</span><span style="font-family: Arial, Helvetica, sans-serif;">);</span>
options.setKeepAliveInterval(<span style="font-family: Arial, Helvetica, sans-serif;">Heart_Interval</span><span style="font-family: Arial, Helvetica, sans-serif;">);</span>
mClient.setCallback(callback);
mClient.connect(options);
mClient.subscribe(topicFilters, mQos); <span style="font-family: Arial, Helvetica, sans-serif;">//定阅主题</span>
} catch (Exception e) {
e.printStackTrace();
}
super.onCreate();
}
/**
* 消息回调
*/
@SuppressLint("NewApi")
private MqttCallback callback = new MqttCallback() {
/**消息到来时,通知栏显示*/
@Override
public void messageArrived(String arg0, MqttMessage msg) throws Exception {
String content = new String(msg.getPayload(), "utf-8");
Log.e(TAG, "Message From Server Arrived: " + content);
mManager.notify(notiId, builder.build());
}
@Override
public void deliveryComplete(IMqttDeliveryToken token) {
Log.e(TAG, "Delivery Complete");
}
/**连接丢失时,重新连接*/
@Override
public void connectionLost(Throwable e) {
Log.e(TAG, "连接出现错误");
try {
mClient.connect();
} catch (Exception e1) {
e1.printStackTrace();
}
}
};
/**发布消息*/
public void publishMessage(String topic, int qos, String message){
mTopic = mClient.getTopic(topic);
mMessage = new MqttMessage();
mMessage.setQos(qos);
mMessage.setRetained(true);
try {
mMessage.setPayload(message.getBytes("utf-8"));
} catch (UnsupportedEncodingException e1) {
e1.printStackTrace();
}
try {
MqttDeliveryToken token = mTopic.publish(mMessage);
token.waitForCompletion();
//Log.e(TAG, "Publish Message: " + token.isComplete());
} catch (MqttException e) {
e.printStackTrace();
}
}
}
其他的方案有谷歌的C2DM、第三方推送如极光推送等等