Android apps with Gomobile

5 February 2017

Daniel Esteban

Video

This talk was presented at the FOSDEM 2017 - Go Devroom

Watch the talk on Youtube
Mirror
(Due to a small problem with the camera, the recording start a few minutes late)

2

Caution

The Gomobile project is experimental. Use this at your own risk.

3

Motivation

4

How is it possible?

Gomobile is a toolkit that automates and ease a lot the process for mobile platforms. It provides bindings of Android and iOS through cgo

5

Two strategies

6

Native applications

7

In short

Build with

$ gomobile build -target=android path/to/your/project
$ gomobile build -target=ios path/to/your/project
8

SDK applications (what this talk is really about)

9

Advantages

10

Disadvantages

11

Before we start

$ go get golang.org/x/mobile/cmd/gomobile
$ gomobile init # it might take a few minutes
12

Binding in action (summary)

Go Java
Package Abstract class
Exported Function Static method
Struct Class
Struct fields
Exported vars
Getter/Setter
Method Method
Error Exception

Example at github.com/conejoninja/gobindings

13

Binding in action

Go code

package mygolibrary

func Hello(name string) string {
    return "Hello " + name + "! (from go)"
}

Generated Java bindings

public abstract class Mygolibrary {
    public static native String hello(String name);
    ...
}

Compile with

$ gomobile bind -target android -o mygolibrary.aar -v .
14

More binding (structs)

Go code

package mygolibrary

type Counter struct {
    Value int64
}

func (c *Counter) Inc() {
    c.Value++
}

func NewCounter() *Counter {
    return &Counter{}
}
15

Generated Java bindings

public final class Counter implements Seq.Proxy {
    public native void inc();

    public final native long getValue();
    public final native void setValue(long v);
    ...
}

public abstract class Mygolibrary {
    public static native Counter newCounter();
    ...
}

Use it from Java

Counter counter = newCounter();
counter.setValue(12345);
counter.inc();
16

Calling Go from Java

mygolibrary.go

package mygolibrary

func Hello(name string) string {
    return "Hello " + name + "! (from go)"
}

MainActivity.java

import mygolibrary.Mygolibrary;

public class MainActivity {
    ...
    private void someJavaFunction()
    {
            String resultFromGo = Mygolibrary.hello("JAVA");
            Log.d(TAG, resultFromGo);
    }
    ...
}
17

Calling Go from Java (with errors)

mygolibrary.go

package mygolibrary

func HelloWithError(name string) (string, error) {
    return "Hello " + name + "! (from go)", nil
}

MainActivity.java

    ...
    private void someJavaFunction()
    {
            try {
                String resultFromGo = Mygolibrary.helloWithError("JAVA");
                Log.d(TAG, resultFromGo);
            } catch(Exception e) { // If error != nil in Go, will enter the catch
                Log.e(TAG, e.toString());
            }
    }
    ...
18

Calling Java from Go (1/3)

We create an interface in Go that will be exported (gomobile bind) to Java and we need to implement it

mygolibrary.go

package mygolibrary

var jc JavaCallback

type JavaCallback interface {
    OneMethod()
    AnotherMethod(string)
}

func RegisterJavaCallback(c JavaCallback) {
    jc = c
}
19

Calling Java from Go (2/3)

Implement our callback in Java

GoCallback.java

import mygolibrary.JavaCallback;

public class GoCallback implements JavaCallback {

    public void oneMethod() {
        ...
    }

    public void anotherMethod(String data) {
        ...
    }

}
20

Calling Java from Go (3/3)

Register your callback (in Java)

// REGISTER CALLBACK
GoCallback gocb = new GoCallback();
Mygolibrary.registerJavaCallback(gocb);

After that point, you could call Java from Go

jc.OneMethod();
jc.AnotherMethod("Some string here");
21

How to build

$ gomobile bind -target android -o mygolibrary.aar -v .

In your android project:

android/settings.gradle

include ':app', ':mygolibrary'

android/app/build.gradle

dependencies {
    ...
    compile project(':mygolibrary')
}

mygolibrary/build.gradle

configurations.maybeCreate("default")
artifacts.add("default", file('mygolibrary.aar'))

(or in Android Studio: File > New > New Module > Import .JAR/.AAR Package)

22

Problem: it doesn't add changes made to go code

If you modify mygolibrary.aar it will not add the new changes to the project

23

Solution

We need to make gradle to recompile it

android/build.gradle (add)

repositories {
    ...
    flatDir {
        dirs "$rootDir/mygolibrary"
    }
}

android/app/build.gradle (modify)

dependencies {
    ...
    compile (':mygolibrary@aar') { changing = true }
}
24

Success story

Password Manager for TREZOR on Android devices

25

Password Manager (continuation)

26

Password Manager (continuation)

How to glue things together

27

Other successful stories

Ivy
- Ivy is an interpreter for an APL-like language
- Written by Rob Pike
- Source at github.com/robpike/ivy
- Google Play Store play.google.com/store/apps/details?id=org.golang.ivy

Goku
- Sudoku solver
- React-native as UI
- Written by Miguel Espinoza
- Source at github.com/miguelespinoza/react-goku
- Google Play Store play.google.com/store/apps/details?id=com.miguelespinoza.goku

28

Some tips (based in our experience)

func CallThisFromJava() {
    go runThisAsync()
}
func runThisAsync() {
    /* your code here */
}
29

Some notes

Before Now
Uppercase names
Mygolibrary.Hello("Java Cup")
Lowercase names
Mygolibrary.hello("Java Cup")
import package (in Java)
import go.mygolibrary.Mygolibrary;
import mygolibrary.Mygolibrary;
30

Notes

31

Links

32

Thank you

Daniel Esteban

Use the left and right arrow keys or click the left and right edges of the page to navigate between slides.
(Press 'H' or navigate to hide this message.)