Building Digital Carrot: A Year of Go Mobile with Flutter
Using Go for Mobile Apps

I spent a year building Digital Carrot using Go Mobile for business logic and Flutter for the UI. This setup lets me leverage Go's strong libraries and seamless server integration while keeping the presentation layer flexible. By using Protobuf for communication, I achieved a clean separation of concerns that simplifies testing and allows the backend to run efficiently as a standalone daemon on any platform.
I can be reasonably sure that Go will never disappear, but who can say what will happen in the wacky world of UI.
- iamcalledrob
I've built and shipped some native-UI cross-platform apps to millions of devices, powered by a Go shared library. It works. It's fantastic to use the same language on client and server, and the end-to-end testing story is really strong.
However, in my opinion, "Go Mobile" is a bit of a red herring if you just want a cross-platform shared library. I wouldn't recommend starting there.
It's optimised for writing and packaging an entire app in Go. Incremental builds don't work well (or at all), and cobbled-together "build system" is more to debug. It's also oriented around iOS and Android, which isn't great if you eventually want a native desktop app too. The generated bindings are okay, but the author's approach of using Protobuf (or some kind of wire format + simple API) means you don't really need them.
I found that it's more straightforward to just compile Go code into a library that can be called from C -- and thus can be called from anywhere. Call into it natively from Swift, and via JNI on Android and desktop JVM. With the right toolchain, you can cross-compile pretty easily too.
The biggest issue is that on Android you often want to talk to the OS, but the OS only speaks JVM. https://github.com/timob/jnigi "solves" this, although you will hate your life manually constructing JVM calls that you can't easily test.
- dizhn
I don't get why with all the plumbing the author already set up, Go had to be part of the mobile app at all. Could have been a clean flutter/dart UI with a Go backend. (All of these they already have but somehow they have to deal with passing binary data between Go mobile and dart?)
- ventana
The author uses Flutter for UI, Golang binary for the app backend, and uses channels passing serialized protobuf messages between them. Since adding a new API call requires changes in multiple places, they ended up defining a "god message" which has a oneof with all possible options:
message CarrotAPI {
oneof api {
Function1API function1 = 10;
Function2API function2 = 11;
}
}
message Function1API {
message Request {}
message Response {}
Request request = 1;
Response response = 2;
}
and then dispatch the call using switch to check the value of the api field.
This is... not really a good API design. I wonder if the problem of "multiple places to be edited" can be solved in an easier way by making a custom protoc plugin [1] which will take care of generating all the boilerplate for both Dart and Golang. This is how support for new languages and use cases is normally added to protoc.