歡迎在我的公衆號aserbao給我留言,無償服務!同時,歡迎大家來加入微信羣二維碼討論羣,一起討論Android開發技術!羣二維碼定時在我公衆號更新!
前言
項目中有用到mqtt,碰巧沒人負責這一塊,所以毛遂自薦就看了一波,下面是一些簡單的使用記錄,寫得不好,僅供參考。若沒有mqtt服務器的朋友,建議先建一個mqtt服務,不然看不到效果。
什麼是Mqtt?
MQTT 的全稱爲 Message Queue Telemetry Transport,是輕量級基於代理的發佈/訂閱的消息傳輸協議,它可以通過很少的代碼和帶寬和遠程設備連接。例如通過衛星和代理連接,通過撥號和醫療保健提供者連接,以及在一些自動化或小型設備上,而且由於小巧,省電,協議開銷小和能高效的向一和多個接收者傳遞信息,故同樣適用於稱動應用設備上。MQTT就包含了以下一些特點:
- 實現簡單
- 提供數據傳輸的 QoS
- 輕量、佔用帶寬低
- 可傳輸任意類型的數據
- 可保持的會話(session)
Android 下如何使用Mqtt?
在Android中使用Mqtt可以分爲6個步驟:
- 導入mqtt包;
- 配置MqttConnectOptions;
- 調用connect並將配置好的參數寫入;
- 通過指定的消息進行消息訂閱;
- 向訂閱的topic中發佈消息;
- 通過mqttCallBack的回調對接收到的消息進行處理;
// mqtt 包導入
implementation 'org.eclipse.paho:org.eclipse.paho.client.mqttv3:1.1.0'
implementation 'org.eclipse.paho:org.eclipse.paho.android.service:1.1.1'
導入類:
public class MQTTManager {
private static final String TAG = "MQTTManager";
public static final String SERVER_HOST = "tcp://52.80.116.245:1883";
private String clientid = "2df8aabfb8b6088953664f413a446bbc";
private static MQTTManager mqttManager=null;
private MqttClient client;
private MqttConnectOptions options;
private Context mContext;
private MessageHandlerCallBack callBack;
private MQTTManager(Context context){
mContext = context;
clientid+=MqttClient.generateClientId();
}
/**
* 獲取一個MQTTManager單例
* @param context
* @return 返回一個MQTTManager的實例對象
*/
public static MQTTManager getInstance(Context context) {
Log.d(TAG,"mqttManager="+mqttManager);
if (mqttManager==null) {
mqttManager=new MQTTManager(context);
synchronized (Object.class) {
Log.d(TAG,"synchronized mqttManager="+mqttManager);
if (mqttManager!=null) {
return mqttManager;
}
}
}else {
Log.d(TAG,"else mqttManager="+mqttManager);
return mqttManager;
}
return null;
}
/**
* 連接服務器
*/
public void connect(){
Log.d(TAG,"開始連接MQtt");
try {
// host爲主機名,clientid即連接MQTT的客戶端ID,一般以唯一標識符表示,MemoryPersistence設置clientid的保存形式,默認爲以內存保存
client = new MqttClient(SERVER_HOST, "2df8aabfb8b6088953664f413a446bbc", new MemoryPersistence());
// MQTT的連接設置
options = new MqttConnectOptions();
// 設置是否清空session,這裏如果設置爲false表示服務器會保留客戶端的連接記錄,這裏設置爲true表示每次連接到服務器都以新的身份連接
options.setCleanSession(true);
// 設置連接的用戶名
options.setUserName("7302");
// 設置連接的密碼
options.setPassword("64ec6f32366ccb80f0dacc804546d62e623e4b72".toCharArray());
// 設置超時時間 單位爲秒
options.setConnectionTimeout(30);
// 設置會話心跳時間 單位爲秒 服務器會每隔1.5*20秒的時間向客戶端發送個消息判斷客戶端是否在線,但這個方法並沒有重連的機制
options.setKeepAliveInterval(30);
// 設置回調
// MqttTopic topic = client.getTopic(TOPIC);
//setWill方法,如果項目中需要知道客戶端是否掉線可以調用該方法。設置最終端口的通知消息
// options.setWill(topic, "close".getBytes(), 2, true);
SSLSocketFactory sslSocketFactory = null;
/* try {
sslSocketFactory = sslContextFromStream(mContext.getAssets().open("server.pem")).getSocketFactory();
} catch (Exception e) {
e.printStackTrace();
}
options.setSocketFactory(sslSocketFactory);*/
client.setCallback(new PushCallback());
client.connect(options);
Log.d(TAG,"ClientId="+client.getClientId());
} catch (MqttException e) {
e.printStackTrace();
Log.e(TAG, "connect: " + e );
}
}
/**
* 訂閱消息
* @param topic 訂閱消息的主題
*/
public void subscribeMsg(String topic,int qos){
if (client!=null) {
int[] Qos = {qos};
String[] topic1 = {topic};
try {
client.subscribe(topic1, Qos);
Log.d(TAG,"開始訂閱topic="+topic);
} catch (MqttException e) {
e.printStackTrace();
}
}
}
/**
* 發佈消息
* @param topic 發佈消息主題
* @param msg 消息體
* @param isRetained 是否爲保留消息
*/
public void publish(String topic,String msg,boolean isRetained,int qos) {
try {
if (client!=null) {
MqttMessage message = new MqttMessage();
message.setQos(qos);
message.setRetained(isRetained);
message.setPayload(msg.getBytes());
client.publish(topic, message);
Log.d(TAG,"topic="+topic+"--msg="+msg+"--isRetained"+isRetained);
}
} catch (MqttPersistenceException e) {
e.printStackTrace();
} catch (MqttException e) {
e.printStackTrace();
}
}
int count=0;
/**
* 發佈和訂閱消息的回調
*
*/
public class PushCallback implements MqttCallback {
public void connectionLost(Throwable cause) {
Log.e(TAG, "connectionLost: " + cause );
if (count<5) {
count++;//5次重連
Log.d(TAG,"斷開連接,重新連接"+count+"次"+cause);
try {
client.close();
connect();
} catch (MqttException e) {
e.printStackTrace();
}
}
}
/**
* 發佈消息的回調
*/
@Override
public void deliveryComplete(IMqttDeliveryToken token) {
//publish後會執行到這裏
Log.d(TAG,"發佈消息成功的回調"+token.isComplete());
}
/**
* 接收消息的回調方法
*/
@Override
public void messageArrived(final String topicName, final MqttMessage message)
throws Exception {
//subscribe後得到的消息會執行到這裏面
Log.d(TAG,"接收消息=="+new String(message.getPayload()));
if (callBack!=null) {
callBack.messageSuccess(topicName,new String(message.getPayload()));
}
}
}
/**
* 設置接收消息的回調方法
* @param callBack
*/
public void setMessageHandlerCallBack(MessageHandlerCallBack callBack){
this.callBack = callBack;
}
public MessageHandlerCallBack getMessageHandlerCallBack(){
if (callBack!=null) {
return callBack;
}
return null;
}
/**
* 斷開鏈接
*/
public void disconnect(){
if (client!=null&&client.isConnected()) {
try {
client.disconnect();
mqttManager=null;
} catch (MqttException e) {
e.printStackTrace();
}
}
}
/**
* 釋放資源
*/
public void release(){
if (mqttManager!=null) {
mqttManager=null;
}
}
/**
* 判斷服務是否連接
* @return
*/
public boolean isConnected(){
if (client!=null) {
return client.isConnected();
}
return false;
}
public SSLContext sslContextFromStream(InputStream inputStream) throws Exception {
CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
Certificate certificate = certificateFactory.generateCertificate(inputStream);
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
keyStore.load(null, null);
keyStore.setCertificateEntry("ca", certificate);
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
trustManagerFactory.init(keyStore);
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, trustManagerFactory.getTrustManagers(), null);
return sslContext;
}
}
調用:
MQTTManager instance = MQTTManager.getInstance(mContext);
instance.setMessageHandlerCallBack(new MessageHandlerCallBack() {
@Override
public void messageSuccess(String topicName, String s) {
Log.e(TAG, "messageSuccess: " + s);
}
});
instance.connect();
連接成功後,就可以實現和服務端消息的發送和接收。
項目地址
AserbaosAndroid
aserbao的個人Android總結項目,希望這個項目能成爲最全面的Android開發學習項目,這是個美好的願景,項目中還有很多未涉及到的地方,有很多沒有講到的點,希望看到這個項目的朋友,如果你在開發中遇到什麼問題,在這個項目中沒有找到對應的解決辦法,希望你能夠提出來,給我留言或者在項目github地址提issues,我有時間就會更新項目沒有涉及到的部分!項目會一直維護下去。當然,我希望是Aserbao’sAndroid 能爲所有Android開發者提供到幫助!也期望更多Android開發者能參與進來,只要你熟悉Android某一塊,都可以將你的代碼pull上分支供大家學習!
總結
mqtt Android客戶端的代碼很有限,沒有過多的操作!簡單的配置,連接,然後接受回調處理接受消息就可以了,協議內容今後有時間再細看吧!