引用
compile 'org.eclipse.paho:org.eclipse.paho.client.mqttv3:1.1.0'
compile 'org.eclipse.paho:org.eclipse.paho.android.service:1.1.1'
添加服务
自定义服务 保持mq的服务和自己的服务在同一进程中 不然会出bug
<service
android:name=".push.PushService"
android:exported="false"
android:process=":push" />
<service
android:name="org.eclipse.paho.android.service.MqttService"
android:process=":push" />
初始化
this.context = context;
exit = false
var uri = "tcp://$host:$port"
// var uri = "ssl://$host:$port"
mClient = MqttAndroidClient(context, uri, clientId)
mClient?.setCallback(this)
//mqtt连接参数设置
options = MqttConnectOptions();
//设置自动重连
options?.isAutomaticReconnect = false;
// 设置是否清空session,这里如果设置为false表示服务器会保留客户端的连接记录
// 这里设置为true表示每次连接到服务器都以新的身份连接
options?.isCleanSession = false;
// 设置超时时间 单位为秒
options?.connectionTimeout = 5;
// 设置会话心跳时间 单位为秒 服务器会每隔1.5*20秒的时间向客户端发送个消息判断客户端是否在线,但这个方法并没有重连的机制
options?.keepAliveInterval = 20;
//设定(持久订阅,不重复获取推送消息)
options?.setWill(clientId, ByteArray(100), 2, false);
/*连接成功之后设置连接断开的缓冲配置*/
disconnectedBufferOptions = DisconnectedBufferOptions();
//开启
disconnectedBufferOptions?.isBufferEnabled = true;
//离线后最多缓存100调
disconnectedBufferOptions?.bufferSize = 100;
//不一直持续留存
disconnectedBufferOptions?.isPersistBuffer = false;
//删除旧消息
disconnectedBufferOptions?.isDeleteOldestMessages = false;
链接
mClient?.connect(options, null, object : IMqttActionListener {
override fun onFailure(asyncActionToken: IMqttToken?, exception: Throwable?) {
Log.e(TAG, "链接失败")
}
override fun onSuccess(asyncActionToken: IMqttToken?) {
Log.e(TAG, "链接成功")
//订阅
subscribeToTopic()
}
})
消息订阅
消息订阅一定要放到链接成功之后
mClient?.setBufferOpts(disconnectedBufferOptions)
//主题、QOS、context,订阅监听,消息监听. 这里用clientID
var token = mClient?.subscribe(mClient?.clientId, 2, null, object : IMqttActionListener {
override fun onSuccess(asyncActionToken: IMqttToken?) {
Log.e(TAG, "订阅成功")
}
override fun onFailure(asyncActionToken: IMqttToken?, exception: Throwable?) {
Log.e(TAG, "订阅失败")
}
}) { topic, message ->
Log.e(TAG, "$topic 消息到达 $message")
showMessage(message = message.toString())
}
Log.e(TAG, "token ${token?.isComplete}")
消息到了显示的通知栏,这里用之前项目中极光推送,显示的话百度.
源码
自定义的服务
class PushService : Service() {
private val TAG = PushService::class.java.simpleName
var pushClient: PushClient? = null
companion object {
fun start(context: Context) {
var bundle = Bundle()
bundle.putSerializable(Constant.PUSH_ACTION, Action.START)
var intent = Intent(context, PushService::class.java);
intent.putExtras(bundle)
Log.e("PushService", "开始服务")
context.startService(intent)
}
fun connect(context: Context, userId: String) {
var bundle = Bundle()
bundle.putSerializable(Constant.PUSH_ACTION, Action.CONNECT)
bundle.putString(Constant.KEY_USER_ID, userId)
var intent = Intent(context, PushService::class.java);
intent.putExtras(bundle)
Log.e("PushService", "链接服务")
context.startService(intent)
}
fun stop(context: Context) {
var bundle = Bundle()
bundle.putSerializable(Constant.PUSH_ACTION, Action.STOP)
var intent = Intent(context, PushService::class.java);
intent.putExtras(bundle)
context.startService(intent)
}
}
override fun onBind(intent: Intent?): IBinder? {
return null
}
override fun onCreate() {
Log.e(TAG, "onCreate")
super.onCreate()
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
Log.e(TAG, "onStartCommand" + System.currentTimeMillis())
handleAction(intent)
return super.onStartCommand(intent, flags, startId)
}
private fun handleAction(intent: Intent?) {
var bundle = intent?.extras
var action = bundle?.getSerializable(Constant.PUSH_ACTION)
when (action) {
Action.START -> {
Log.e(TAG, "action start")
}
Action.CONNECT -> {
Log.e(TAG, "action connect")
connect(bundle!!.getString(Constant.KEY_USER_ID))
}
Action.STOP -> {
Log.e(TAG, "action stop")
disConnect()
}
}
}
fun connect(userId: String) {
if (pushClient == null) {
Log.e(TAG, "pushClient create")
pushClient = PushClient.create(Constant.PUSH_HOST, 1883, this, userId)
} else {
Log.e(TAG, "pushClient exists")
}
pushClient?.connect()
}
fun disConnect() {
pushClient?.disConnect()
pushClient = null
}
override fun onDestroy() {
Log.e(TAG, "服务销毁")
super.onDestroy()
}
}
枚举
enum class Action {
START,
CONNECT,
STOP
}
pushClient 加了重连 网络监听,
class PushClient : MqttCallback {
private val TAG = "PushClient"
//mqtt连接client
var mClient: MqttAndroidClient? = null
//mqtt连接参数设置
var options: MqttConnectOptions? = null;
/*连接成功之后设置连接断开的缓冲配置*/
var disconnectedBufferOptions: DisconnectedBufferOptions? = null
var context: Context? = null
var countDownTimer: CountDownTimer? = null//倒计时重连
var exit = false//是否退出
//重连时间间隔 ,分别是 1、2、4、8、16、32、64、128、256、512 秒后
var array: Array<Long> = arrayOf(1000, 2000, 4000, 8000, 16000, 32000, 64000, 128000, 256000, 512000)
var iterator: Iterator<Long>? = null
var connecting = false
constructor(host: String, port: Int, context: Context, clientId: String) {
this.context = context;
exit = false
var uri = "tcp://$host:$port"
// var uri = "ssl://$host:$port"
mClient = MqttAndroidClient(context, uri, clientId)
mClient?.setCallback(this)
//mqtt连接参数设置
options = MqttConnectOptions();
//设置自动重连
options?.isAutomaticReconnect = false;
// 设置是否清空session,这里如果设置为false表示服务器会保留客户端的连接记录
// 这里设置为true表示每次连接到服务器都以新的身份连接
options?.isCleanSession = false;
// 设置超时时间 单位为秒
options?.connectionTimeout = 5;
// 设置会话心跳时间 单位为秒 服务器会每隔1.5*20秒的时间向客户端发送个消息判断客户端是否在线,但这个方法并没有重连的机制
options?.keepAliveInterval = 20;
//设定(持久订阅,不重复获取推送消息)
options?.setWill(clientId, ByteArray(100), 2, false);
/*连接成功之后设置连接断开的缓冲配置*/
disconnectedBufferOptions = DisconnectedBufferOptions();
//开启
disconnectedBufferOptions?.isBufferEnabled = true;
//离线后最多缓存100调
disconnectedBufferOptions?.bufferSize = 100;
//不一直持续留存
disconnectedBufferOptions?.isPersistBuffer = false;
//删除旧消息
disconnectedBufferOptions?.isDeleteOldestMessages = false;
initReceiver()
iterator = array.iterator()
}
companion object {
fun create(host: String, port: Int, context: Context, clientId: String): PushClient {
return PushClient(host = host, port = port, context = context, clientId = clientId)
}
}
/**
* 链接
*/
fun connect() {
if (connecting) {
Log.e(TAG, " 正在链接中请等待")
return
}
connecting = true
Log.e(TAG, "链接${mClient?.serverURI}")
mClient?.connect(options, null, object : IMqttActionListener {
override fun onFailure(asyncActionToken: IMqttToken?, exception: Throwable?) {
Log.e(TAG, "链接失败")
connecting = false
resetConnect()
}
override fun onSuccess(asyncActionToken: IMqttToken?) {
connecting = false
Log.e(TAG, "链接成功")
if (countDownTimer != null) {
countDownTimer?.cancel()
countDownTimer = null
}
//订阅
subscribeToTopic()
//重置重连时间
resetConnectTime()
}
})
}
/**
* 注册网络监听
*/
fun initReceiver() {
var timeFilter = IntentFilter();
// timeFilter.addAction("android.net.ethernet.ETHERNET_STATE_CHANGED");
// timeFilter.addAction("android.net.ethernet.STATE_CHANGE");
// timeFilter.addAction("android.net.conn.CONNECTIVITY_CHANGE");
// timeFilter.addAction("android.net.wifi.WIFI_STATE_CHANGED");
// timeFilter.addAction("android.net.wifi.STATE_CHANGE");
// timeFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
timeFilter.addAction("android.net.conn.CONNECTIVITY_CHANGE");
context?.registerReceiver(object : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
Log.e(TAG, "网络发生变化")
resetConnectTime()
if (!mClient!!.isConnected) {
resetConnect()
}
}
}, timeFilter);
}
fun resetConnectTime() {
if (countDownTimer != null) {
countDownTimer?.cancel()
countDownTimer = null
}
iterator = array.iterator()
}
/**
* 重新链接
*/
fun resetConnect() {
if (countDownTimer != null) {
countDownTimer?.cancel()
countDownTimer = null
}
if (connecting) {
Log.e(TAG, " 正在链接中请等待 稍后重连")
return
}
if (iterator != null && iterator?.hasNext()!!) {
countDownTimer = object : CountDownTimer(iterator?.next()!!, 1000) {
override fun onTick(millisUntilFinished: Long) {
Log.e(TAG, "等待重新链接 $millisUntilFinished")
}
override fun onFinish() {
Log.e(TAG, "重新链接")
connect()
}
}.start()
} else {
Log.e(TAG, " 重连次数到上限 暂不重连 ")
}
}
override fun messageArrived(topic: String?, message: MqttMessage?) {
Log.e(TAG, "messageArrived")
}
/**
* @desc 连接断开回调
* 可在这里做一些重连等操作
*/
override fun connectionLost(cause: Throwable?) {
Log.e(TAG, "connectionLost")
if (!exit) {
resetConnect()
}
}
override fun deliveryComplete(token: IMqttDeliveryToken?) {
Log.e(TAG, "deliveryComplete")
}
/**
* 断开链接
*/
fun disConnect() {
exit = true
if (countDownTimer != null) {
countDownTimer?.cancel()
countDownTimer = null
}
Log.e(TAG, "断开链接")
mClient?.disconnect(null, object : IMqttActionListener {
override fun onFailure(asyncActionToken: IMqttToken?, exception: Throwable?) {
Log.e(TAG, "断开链接失败")
}
override fun onSuccess(asyncActionToken: IMqttToken?) {
Log.e(TAG, "断开链接成功")
}
})
}
/**
* 订阅主题
*/
var set = false
fun subscribeToTopic() {
Log.e(TAG, "消息订阅${mClient?.clientId}")
mClient?.setBufferOpts(disconnectedBufferOptions)
//主题、QOS、context,订阅监听,消息监听
var token = mClient?.subscribe(mClient?.clientId, 2, null, object : IMqttActionListener {
override fun onSuccess(asyncActionToken: IMqttToken?) {
Log.e(TAG, "订阅成功")
}
override fun onFailure(asyncActionToken: IMqttToken?, exception: Throwable?) {
Log.e(TAG, "订阅失败")
}
}) { topic, message ->
Log.e(TAG, "$topic 消息到达 $message")
showMessage(message = message.toString())
}
Log.e(TAG, "token ${token?.isComplete}")
}
/**
* 是否链接
*/
fun isConnected(): Boolean {
return if (mClient == null) {
false
} else {
mClient!!.isConnected
}
}
private fun showMessage(message: String) {
val jsonObject = JSONObject(message)
val ln = JPushLocalNotification()
ln.extras = message
ln.builderId = 0
ln.content = jsonObject.getString("content")
ln.title = jsonObject.getString("title")
ln.notificationId = System.currentTimeMillis()
ln.broadcastTime = System.currentTimeMillis() + 1000 * 1
JPushInterface.addLocalNotification(context, ln)
}
}
使用方法
PushService.start
PushService.connect
PushService.stop