My previous post talks about implementing a simple business logic in Go and integrating it with a mobile application. As an application grows in complexity, there comes a need for a more complex data transfer mechanisms to exist between the app and the library. This post lists a few caveats that one needs to keep in mind while working on Gomobile.
Essentially, the communication with Go has to be two way. Communication from Java and Objective-C is via the public header generated by GoMobile and callbacks from Go are implemented using Go Interfaces. GoMobile translates Go interfaces into Protocols in iOS and Interfaces in Java. We can define a Communication Interface that has two methods onSuccess() and onError(), which will act as our callbacks. We create a class that implements this interface/protocol and pass an instance of this object as a parameter to Go. Go can use this object and callback into the respective platform on completion of the desired action. GoMobile also offers support for the Errors and Exceptions in Objective-C and Java respectively making it very easy to propagate errors from the library.
Gomobile has its shortcomings and the most prominent of all, is its restrictive datatype support. Gomobile only allows the use of the following datatypes.
- Signed integer and floating point types.
- String and boolean types.
- Byte slice types. Note the current implementation does not support data mutation of slices passed in as function arguments.
- Any function type all of whose parameters and results have supported types. Functions must return either no results, one result, or two results where the type of the second is the built-in ‘error’ type.
- Any interface type, all of whose exported methods have supported function types.
- Any struct type, all of whose exported methods have supported function types and all of whose exported fields have supported types.
Particularly, the lack of a slice datatype is very inhibiting and as mobile applications tend to deal with collections on a daily basis. There are a few workarounds for this problem.
There a few workarounds that can be made so that the data type restcitions doesn't inhibit us from using Gomobile
One solution is to generate data access methods for a wrapper object around a slice and pass it back and forth between Android/iOS and Go. This solution is presented here - https://github.com/golang/go/issues/13445#issuecomment-173660985
Another solution (which I use currently), is to define protocol buffers as contract objects between Go <> Application. So when Go wants to callback iOS/Android, it converts the complex data type into an array of bytes (which is a supported datatype in Gomobile) and on the application side, it can be converted back into an object. With the help of a few workflow changes, Gomobile can be easily used to pass on complex datatypes to the application.
Gomobile does not have support for bitcode that means that bitcode enabled iOS applications will not be able to integrate with Gomobile. That also means that Gomobile cannot be used with platforms like tvOS and watchOS.
Note - I noticed that this issue is being worked on currently, so hopefully we should have bitcode support soon :)