Meet the coolest tech marriage: Flutter & Go!

Brick Pop
Stack Me Up
Published in
7 min readJan 13, 2020
Photo by Luca Florio on Unsplash

As a trendy developer, you may have heard of Flutter, the mighty framework to build native like mobile, web and desktop apps. After using it for 9 months now, I’m confident to say that it’s here to stay.

Flutter

Its main features:

However, if you come from React Native there’s a good chance that the NPM packages that made your life easier do not have a Dart version.

In such scenario, you have a few options:

- Rewrite them yourself

Rewriting JS into Dart may be time-consuming for large dependencies. If you are on a deadline or can’t afford to maintain the ported package, this might not be your best option.

- Find a way to run Javascript within a Flutter app

I have made several attempts to run a “headless” web view within Flutter and enqueue requests by sending messages back and forth. However, the approach would not be solid enough and hidden web views would lead to unintended side effects. Great for use in a hackathon, but foolish to ship in production.

- Find native implementations

What if the functionality you need is on Cocoa Pods or Maven? Well, jumping into Objective C and Java is fine, but this would defeat the main advantage of Flutter, forcing us to write things twice…

But hey, what if we don’t have to?

Golang to the rescue

The Go language is intended for systems programming and 10 years after it was announced, its package ecosystem is quite healthy. The downside for us is that it is designed to build Linux, Unix, macOS and Windows binaries.

Luckily, a few years ago Google released a precious package that I didn’t hear about until recently: Go Mobile.

Go Mobile lets you build entire applications as well as native libraries that can be imported on XCode or Android Studio. Doesn’t it sound great?

The plan

Our goal is to develop mobile apps using the Flutter tools we know and love. Instead of embedding any libraries manually on our project, we will keep things modular by creating a plugin, writing once in Dart, reusing Go packages and importing our plugin wherever we need it.

Our plugin will contain:

  • The compiled Go bindings
  • A Dart module so we can export our methods
  • iOS and Android projects, with simple glue code to forward requests from Dart to Go
  • An example project to test the plugin features right away

Get started

Make sure you have XCode, Android Studio (with NDK, CMake and LLDB), Go, GoMobile, Cocoa Pods and Flutter installed.

Let’s create the plugin:

$ flutter create --org com.mylib --template=plugin mylib

This will scaffold a starter Flutter plugin on your computer named mylib. Make sure that the name of your plugin is not the same as any Go dependency, since this would cause naming collisions on XCode.

If we run cd example and flutter run, we will get an already functional dummy plugin invoking Swift code:

Go library

Next, let’s fetch the Go library we want to use:

$ export GOPATH=~/go
$ go get github.com/divan/num2words

On ~/go/src/github.com/divan/num2words/num2words.go you should see the exported function Convert, which accepts an number and returns it as text.

Go bindings

Let’s compile this into iOS and Android libraries.

On the plugin folder:

$ mkdir ios/Frameworks
$ cd ios/Frameworks
$ gomobile bind -target ios github.com/divan/num2words

You should see Num2words.framework on <plugin-folder>/ios/Frameworks. Easy, right? Now the same for Android:

$ mkdir android/libs
$ cd android/libs
$ gomobile bind -target android github.com/divan/num2words

Your should now see num2words.aar and num2words-sources.jar on <plugin-folder>/android/libs.

We are done with Go!

Importing the bindings on iOS

Now, let’s tell XCode and Gradle to use the bindings.

For iOS, edit ./ios/mylib.podspec and append the vendored_frameworks line near the end:

This will trigger a pod install, copying the framework file when we use the Flutter plugin in the future.

Now open ios/Classes/SwiftMylibPlugin.swift, import the bindings library and adapt the handle function to accept our new convert request:

call.method contains a string with the name of the operation we are requesting, while call.arguments has a generic type that we will need to check and cast on runtime.

Note how gomobile has renamed the Convert function into Num2wordsConvert.

Importing the bindings on Android

Doing the same for Android is no different.

Edit android/build.gradle and add the following line within the dependencies directive:

This will import any *.aar file that we place on the android/libs folder.

Next, let’s handle our requests to execute Convert. First, import the package of the Go library:

And next, add an if statement to capture our new requests:

Note how in this case, we need to reference the Go function as Num2words.convert (lowercase). Not sure why names can’t be kept as they were.

First build

If we head back to the example folder, run flutter build ios, flutter build apk and get no warnings, this means that we compiled our first Flutter Go plugin!

Implementing the plugin logic

Our native part is now ready. Let’s send requests to it and see how it works.

Edit lib/mylib.dart so that our Flutter plugin exposes a Dart method to the outer world:

Now, every time we import the Flutter plugin and call num2String(...), Flutter will do the heavy lifting for us and translate our call into a message for Swift/Java for which we just implemented a handler.

We can pass up to one argument, and such argument has to be a boolean, integer, string, List or Map. The Lists and Map values should be booleans, integers or strings. Or we could simply pass custom JSON data serialized into a string.

Running our plugin

Finally, we are ready to use our shiny Flutter plugin!

Edit example/lib/main.dart to make use of it:

  • We import the Dart package of our plugin
  • We call the Go method on the native side when the Widget initializes and update the Widget state
  • We render the result

Finally, open the iPhone and Android simulators and run:

$ flutter run -d all

Wohooo! 🎉🎊

Photo by Keith Luke on Unsplash

Yes, we can

On more real-life projects, what could we do with that?

By using Go, we get access to a wide ecosystem of libraries for free. They can be great if you need to do:

  • Image/video processing
  • Media transcoding
  • Using math libraries
  • Write once, use everywhere
  • Run heavy operations where smartphones would have a hard time with interpreted languages

Considerations:

  • If your Go methods are renamed and you can’t work out their name on iOS, you can have a look at the generated header file ios/Frameworks/Num2words.framework/Headers/Num2words.objc.h
  • On Android, you can explore within the android/libs/num2words-sources.jar package with Android Studio

Current limitations:

  • As mentioned, the Go methods exported for iOS/Android may not pass data beyond integers, booleans, strings, maps or lists. However, these methods can pass any type of data they need with the rest of the library.
  • Since mobile and desktop operating systems don’t have equal capabilities, it’s possible that very specific API’s refuse to compile. Don’t expect to compile a library to send signals to other processes or fetch the process list on iOS.

If you liked what you found, please consider clapping 👏 out loud, smiling 😊, loving ❤️ and spreading the word 📤 to anyone who might be happy to read it too.

Until the next time!

--

--

Brick Pop
Stack Me Up

Full stack tech, thoughts and life. Personal journey is underway. The future is now.