22 Sep 2016, 15:39

Using Go mobile on iOS for real

Share

Go Mobile can generate native framework for iOS and Android using Go code, I was curious what could be achieved with it.
Most tutorials are Hello world and I wanted to test it with real code.
You can use it to generate a full app only using Go code, but I’m only interested by the bindings part (SDK applications), using a native ObjC/Swift app calling Go code.

I’m using some existing Go code regionagogo, (a geofence database), moderately complex since it uses BoltDB and Google S2 library.

Go Mobile is limited to a subset of types you can use, main reason is to be correctly transcribed to Java and ObjC.

So the first thing to do is to write some Go wrapper like you would do in ObjC to call some C++ code but first:

Functions must return either no results, one result, or two results where the type of the second is the built-in error type.
So far no major complication, but also note that you can’t return slices, that could be a major pain, there are some workaround solutions like go-mobile-collection that can generate an API to operate on slice.
You also have to respect some naming for your constructor like New...().

At the end your wrapper won’t look very Goish but it’s what it takes for it to be translated.

Knowing those constraints you can write a simple wrapper like this:

package mobile

type GeoDB struct {
	db regionagogo.GeoFenceDB
}

func NewGeoDB() *GeoDB {
	g := &GeoDB{}
	return g
}

func (g *GeoDB) OpenDB(path string) error {
	db, err := rbolt.NewGeoFenceBoltDB(path)
	if err != nil {
		return err
	}
	g.db = db
	return nil
}

...

Then use the gomobile command:

gomobile bind -target=ios github.com/akhenakh/regionagogo/mobile

It generates a native iOS Mobile.Framework, drop it into your XCode project and start using it.

  • GeoDB translates to GoMobileNewGeoDB() and returns a GoMobileGeoDB* in ObjC domain.
  • OpenDB(path string) error to - (BOOL)openDB:(NSString*)path error:(NSError**)error.

A simple example would be:

GoMobileGeoDB *db = GoMobileNewGeoDB();
NSString *resourcePath = [[NSBundle mainBundle] pathForResource:@"region" ofType:@"db"];
        
NSError *error;
[db openDB:resourcePath error:&error];
if (error != nil) {
    NSLog(@"error opening db %@", [error localizedDescription]);
    return;
}

It’s performing very well, on my iPhone 6, around 4,000 queries per second to test a position in a small fence, to 60,000 queries in a hit miss (calling Go overhead is not that big), while using a ridiculously small amount of memory.

I’ve made a demo iOS app where you can hit the map and it tells you in which fence you are.

app
Remember this is running locally on your phone without any network access (but the map), the geo computation and the Polygons are returned by Go code.

Until now I had to maintain libraries in both languages, Go mobile is a nice alternative!

Sources for the wrapper are available in regionagogo gomobile branch, and here is the iOS demo app.

comments powered by Disqus