I use pahoo mqtt on android side and implement it on flutter to make it run when the app was closed. However the client are still connected and still get the message from brokker after i close the app.
But when i open the app again it seems it failed to invoke method from android side when message is arrive mBackgroundChannel.invokeMethod("mqttMessageArrive", strMessage)
and get this warning message Tried to send a platform message to Flutter, but FlutterJNI was detached from native C++. Could not send. Channel: com.example.research_cahyo/method_dart. Response ID: 0
.
I also got this error after i close the app
2020-06-18 17:27:16.751 27939-27939/com.example.research_cahyo E/ActivityThread: Activity com.example.research_cahyo.MainActivity has leaked ServiceConnection org.eclipse.paho.android.service.MqttAndroidClient$MyServiceConnection@4c11377 that was originally bound here
android.app.ServiceConnectionLeaked: Activity com.example.research_cahyo.MainActivity has leaked ServiceConnection org.eclipse.paho.android.service.MqttAndroidClient$MyServiceConnection@4c11377 that was originally bound here
at android.app.LoadedApk$ServiceDispatcher.<init>(LoadedApk.java:1813)
at android.app.LoadedApk.getServiceDispatcherCommon(LoadedApk.java:1685)
at android.app.LoadedApk.getServiceDispatcher(LoadedApk.java:1664)
at android.app.ContextImpl.bindServiceCommon(ContextImpl.java:1732)
at android.app.ContextImpl.bindService(ContextImpl.java:1661)
at android.content.ContextWrapper.bindService(ContextWrapper.java:715)
at org.eclipse.paho.android.service.MqttAndroidClient.connect(MqttAndroidClient.java:425)
at com.example.research_cahyo.mqtt.MQTTConnection.doConnect(MqttConnection.kt:32)
at com.example.research_cahyo.MyPlugin.doStartMqttService(MyPlugin.kt:69)
at com.example.research_cahyo.MyPlugin.onMethodCall(MyPlugin.kt:149)
at io.flutter.plugin.common.MethodChannel$IncomingMethodCallHandler.onMessage(MethodChannel.java:231)
at io.flutter.embedding.engine.dart.DartMessenger.handleMessageFromDart(DartMessenger.java:93)
at io.flutter.embedding.engine.FlutterJNI.handlePlatformMessage(FlutterJNI.java:642)
Bellow this is my mainactivity.kt
class MainActivity : FlutterActivity() {
private val TAG = "MAIN ACTIVITY";
override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
startForegroundService(Intent(activity.applicationContext, NotificationService::class.java))
} else {
startService(Intent(activity.applicationContext, NotificationService::class.java))
}
GeneratedPluginRegistrant.registerWith(flutterEngine);
Storage.initValue(this.applicationContext)
val binaryMessenger = flutterEngine.getDartExecutor().getBinaryMessenger()
MethodChannel(binaryMessenger, INVOKE_METHOD_ANDROID)
.setMethodCallHandler(MyPlugin(this, binaryMessenger))
}
}
and this is myplugin.kt
class MyPlugin(private val activity: Activity, binaryMessenger: BinaryMessenger) : MethodChannel.MethodCallHandler, IMqttCallback {
private var mBackgroundChannel: MethodChannel
private lateinit var subscribeTopic: String
init {
mBackgroundChannel = MethodChannel(binaryMessenger, INVOKE_METHOD_DART)
}
fun onPublishMessage(call: MethodCall, rawResult: MethodChannel.Result) {
val params = call.arguments<Map<String, String>>()
if (params.containsKey("messages") && params.containsKey("topic")) {
val messages = params["messages"] ?: ""
val topic = params["topic"] ?: ""
MQTTConnection.instance?.doPublishMessages(messages, topic)
rawResult.success(true)
} else {
rawResult.error("INCOMPLETE ARGS", "ARGUMEN ARE INCOMPLETE", null);
}
}
fun doCheckMqttStatus(result: MethodChannel.Result) {
result.success(MQTTConnection.instance?.isConnected)
}
fun doUnSubscribeTopic(call: MethodCall, result: MethodChannel.Result) {
val param: Map<String, String> = call.arguments();
val topic: String = param.get("topic") ?: ""
if (topic.isNotEmpty()) {
MQTTConnection.instance?.doUnSubscribeTopic(topic, this)
}
}
fun doStartMqttService(call: MethodCall, result: MethodChannel.Result) {
val param: Map<String, String> = call.arguments();
val serverUri: String = param.get("serverUri") ?: ""
val clientId: String = param.get("clientId") ?: ""
val clientUsername: String = param.get("clientUsername") ?: ""
val clientPassword: String = param.get("clientPassword") ?: ""
subscribeTopic = param.get("subscribeTopic") ?: ""
val valid = serverUri.length > 0 && clientId.length > 0 &&
clientUsername.length > 0 && clientPassword.length > 0 &&
subscribeTopic.length > 0
if (valid) {
Storage.saveValue(MQTTOPTIONS_STORAGE_KEY, "$serverUri,$clientId,$clientUsername,$clientPassword,$subscribeTopic")
}
if (valid && !(MQTTConnection.instance?.isConnected ?: false)) {
MQTTConnection.instance?.doConnect(activity, serverUri, clientId, clientUsername, clientPassword, this)
result.success("Start mqtt invoked")
} else {
result.error("Invalid Arguments", "Mqtt failed to invoked", null)
}
}
fun doStopMqttService(result: MethodChannel.Result) {
MQTTConnection.instance?.doDisConnect(true)
result.success("Stop mqtt invoked")
}
fun onGetNotifications(result: MethodChannel.Result) {
val listMessage = (Storage.getValue(NOTIFICATION_STORAGE_KEY) as List<*>).map { it.toString() }
result.success(listMessage)
}
fun onSetNotification(call: MethodCall, result: MethodChannel.Result) {
try {
val params = (call.arguments() as List<*>).map { it.toString() };
Storage.saveValue(NOTIFICATION_STORAGE_KEY, params)
} catch (e: Exception) {
result.error("Set storage error", "Set Notification Error", null);
}
}
override fun onMQTTConnectionSuccess() {
if (!(MQTTConnection.instance?.hasTopic(subscribeTopic) ?: false)) {
MQTTConnection.instance?.doSubscribeTopic(subscribeTopic, this)
}
}
override fun onMQTTSubscribeTopicSuccess() {
MQTTConnection.instance?.doMessageListen(this)
}
override fun onMQTTSubscribeTopicFailed(messages: String?) {
mBackgroundChannel.invokeMethod("mqttSubscribeFailed", messages)
}
override fun onMQTTConnectionFailed(messages: String?) {
mBackgroundChannel.invokeMethod("mqttConnectFailed", messages)
}
override fun onMQTTMessagesArrived(mqttMessage: MqttMessage?) {
mqttMessage?.let {
val strMessage = String(it.payload)
mBackgroundChannel.invokeMethod("mqttMessageArrive", strMessage)
val listMessage = (Storage.getValue(NOTIFICATION_STORAGE_KEY) as MutableList<*>).map {
it.toString()
}.toMutableList()
listMessage.add(strMessage)
Storage.saveValue(NOTIFICATION_STORAGE_KEY, listMessage)
Log.d(TAG, "message has arrived")
val notificationBuilder = NotificationCompat.Builder(activity.applicationContext, Constant.CHANNEL_ID)
notificationBuilder.setSmallIcon(R.drawable.ic_launcher_foreground)
.setContentTitle("Message")
.setContentText(strMessage)
.setVibrate(arrayListOf(1000L, 1000L, 1000L, 1000L).toLongArray())
val notification = notificationBuilder.build()
with(NotificationManagerCompat.from(activity.applicationContext)) {
this.notify(Random.nextInt(0, 100), notification)
}
}
}
override fun onMQTTUnsubscribeSuccess() {
mBackgroundChannel.invokeMethod("mqttUnsubscribeSuccess", "Mqtt unsubscribe success")
}
override fun onMQTTUnsubscribeFailed() {
mBackgroundChannel.invokeMethod("mqttUnsubscribeFailed", "Mqtt unsubscribe failed")
}
override fun onMethodCall(call: MethodCall, result: MethodChannel.Result) {
when (call.method) {
"publishMessage" -> onPublishMessage(call, result)
"startMqttService" -> doStartMqttService(call, result)
"stopMqttService" -> doStopMqttService(result)
"checkMqttStatus" -> doCheckMqttStatus(result)
"unsubscribeTopic" -> doUnSubscribeTopic(call, result)
"getNotification" -> onGetNotifications(result)
"setNotification" -> onSetNotification(call, result)
else -> result.notImplemented()
}
}
}
can anyone solve this,,, sorry for bad english