0

Problem description:

I am working on a small project in which i need to port the existing mqtt client library from Golang to Android. I found using gomobile repository as an option to prevent duplicating the same functionality in different programming languages (GO and Java).

To use this library we have two different options:

  1. Design the android app purely in Go and use "gomobile -build" to generate an APK file. An APK file then can be loaded to android device or emulator using adb tool.
  2. Implement some functionality and then bind them into existing Android project using "gomobile -bind". With this option there are some restriction for conversion and building Golang objects.

For my case I plan to pick the second option. Also trying to convert the following small sample GO implementation to Android (borrowed from here).

package main

import (
    "fmt"
    mqtt "github.com/eclipse/paho.mqtt.golang"
    "log"
    "time"
)

var messagePubHandler mqtt.MessageHandler = func(client mqtt.Client, msg mqtt.Message) {
    fmt.Printf("Received message: %s from topic: %s\n", msg.Payload(), msg.Topic())
}

var connectHandler mqtt.OnConnectHandler = func(client mqtt.Client) {
    fmt.Println("Connected")
}

var connectLostHandler mqtt.ConnectionLostHandler = func(client mqtt.Client, err error) {
    fmt.Printf("Connect lost: %v", err)
}

func main() {
    var broker = "broker.emqx.io"
    var port = 1883
    opts := mqtt.NewClientOptions()
    opts.AddBroker(fmt.Sprintf("tcp://%s:%d", broker, port))
    opts.SetClientID("go_mqtt_client")
    opts.SetUsername("emqx")
    opts.SetPassword("public")
    opts.SetDefaultPublishHandler(messagePubHandler)
    opts.OnConnect = connectHandler
    opts.OnConnectionLost = connectLostHandler
    client := mqtt.NewClient(opts)
    if token := client.Connect(); token.Wait() && token.Error() != nil {
        panic(token.Error())
    }

    sub(client)
    publish(client)

    client.Disconnect(250)
}

func publish(client mqtt.Client) {
    num := 10
    for i := 0; i < num; i++ {
        text := fmt.Sprintf("Message %d", i)
        token := client.Publish("topic/test", 0, false, text)
        token.Wait()
        time.Sleep(time.Second)
    }
}

func sub(client mqtt.Client) {
    topic := "topic/test"
    token := client.Subscribe(topic, 1, nil)
    token.Wait()
  fmt.Printf("Subscribed to topic: %s", topic)
}

My Question:

After converting the sample code, i am not sure how i can implement the listener side. the probelm is that "gomobile -bind" cannot convert all user data types (i.e client into Java). I can implement the connect, subscribe, and publish, but not the listener one (in other words, the "opts.SetDefaultPublishHandler(messagePubHandler)" is not repeatedly working when i call the corresponding method in Android)

Any suggestion?

This is what is tried, but it does not work

var Options *mqtt.ClientOptions
var ReceivedMsg string

func AddBroker(broker string, port int) {
    Options = mqtt.NewClientOptions()
    Options.AddBroker(fmt.Sprintf("tcp://%s:%d", broker, port))
}
var MessagePubHandler mqtt.MessageHandler = func(client mqtt.Client, msg mqtt.Message) {
    ReceivedMsg = " Message " + string(msg.Payload()) + " received on topic" + msg.Topic()
    fmt.Printf(ReceivedMsg)
}

 
func Listener(clientId string) {
    Options.SetClientID(clientId)
    Options.SetDefaultPublishHandler(MessagePubHandler)
    Options.OnConnect = ConnectHandler
    Options.OnConnectionLost = ConnectionLostHandler
}
Axy
  • 23
  • 4
  • could you set up a var in go that is updates on messagePubHandler that you then stream updates into android, using go channel to start the stream here is an example https://github.com/kdrag0n/binderlat – Nigel Savage Jun 10 '21 at 18:11
  • thanks @NigelSavage , i tried it, but the var msg string is not updated. I have a feeling that the go object is not live so listener is not active all the time. I made sure that it is called, but assume it will not stayed alive. I have updated the question with what i have tried. The ReceivedMsg is not updated in Android. – Axy Jun 10 '21 at 19:10
  • In your main method you need the app.Main(func(a app.App) { ... // listen events/channels here } I dont see that in your code, I think you have the mqtt set up OK, I think you need more of the go-mobile code see here https://github.com/golang/mobile/blob/7e972142eb43/example/basic/main.go – Nigel Savage Jun 10 '21 at 19:30
  • Thanks @NigelSavage , the link you kindly shared is an example of first approach in which we can use the "gomobile -build" to generate APK file being loaded on android device. My plan is to go with second approach since there are not many UI (i.e layout) support in pure Golang code for android platform. So instead of using app.Main(), i plan to define functions in Golang (i.e Connect(), Subscribe(), and Publish()) and call them inside MainAvtivity file of Android project. Something similar to https://rb.gy/ts9nav So connections and subscribe and publish works well, but not the listener – Axy Jun 10 '21 at 21:45
  • sorry you are correct, I guess what I am saying that there needs to be some kind of process where the listener in the golang code is running to listen for the message, the client.Disconnect(250) will terminate the connection after 250ms . I dont see any kind of loop in the main method that allows for a long running process to listen for messages, unless I am missing something the process with terminate 250ms after it reaches the end of the main method – Nigel Savage Jun 11 '21 at 10:22
  • @NigelSavage thanks. yeah you are right the connection will be delayed for 10 seconds i think because of the loop including wait for 10 iterations. So basically if i run it in go the listener works perfectly. But it does not work if i use mobile -bind and call it inside Android projects. I have a feeling that this because the the life time of the generated objects from the Golibrary. Since gomobile -bind converts method to method. so calling listener function is probably what i am looking for. I have tried to define a struct in go with some client objects, but they cannot be converted. – Axy Jun 11 '21 at 19:35

0 Answers0