一步一步使用Android调用Golang

Go

点击查看详情

前提需要了解的

  1. 在 Android 中运行 go 代码,需要用到一个工具gomobile,后面会说到安装方式。

  2. Go 开发环境,配置好 GOPATH 和 GOROOT 等。

  3. AndroidSDK 和 AndroidNDK

准备好 Go 代码

首先要准备好 GO 的开发坏境,并且配置好 GOPATH,咱们的项目叫mobilego

1
2
3
4
mkdir code/mobilego
cd code/mobilego
echo export GOPATH=\$GOPATH:$(pwd) >> ~/.zshrc # .zshrc 为你的bash地址
source ~/.zshrc

其中code/mobilego是咱们 go 项目地址。那么现在就可以准备 go 代码了,那么我们可以按照这个样子新建一个项目。

1
2
3
4
mobilego
└── src
└── mobile
└── mobile.go

其中,src 目录是必须要有的,因为 gomobile 需要从这个路径下查找包。其中mobile.go代码为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package mobile

import "fmt"

func SayHello() {
      fmt.Println("Hello Mobile")
}

func SayHelloWithParams(name string) {
      fmt.Println("Hello", name)
}

func SayHelloWithParamsAndReturn(name string) string {
      return "Hello" + name
}

func SayHelloWithParamsAndReturnAndException(name string) (string,
error) {
      return "Hello" + name, fmt.Errorf("some error")
}

这个mobile.go就是 java 和 go 文件通信的入口,其中 gomobile 会把这个文件的包名,编译成 java 对应符合 java 命名规范的类名(Mobile)。

mobile.go通过四个例子来演示 java 和 go 的通信。其中第一个无参数无返回值;第二个有参数无返回值;第三个有参数有返回值(同步返回);第四个有参数有返回值并且抛出一个异常。由于 java 不支持多返回值,如果 go 使用多个返回值的话,会报出错误。

准备 gomobile

gomobile 是一个可以为 go 编译成 android 和 ios 平台使用的工具,他的使用说明在https://github.com/golang/go/wiki/Mobile#tools可以找到。

  1. 首先下载这个工具
1
go get golang.org/x/mobile/cmd/gomobile

golang.org 的代码基本上都托管在 google 服务器,一般来说在国内都不会下载成功的。那么只好换成另外一种下载方式。在这里,我们把 golang.org/x/mobile/cmd/gomobile中的golang.org/x/换成github.com/golang/。如下所示:

1
go get github.com/golang/mobile/cmd/gomobile

这时候你会发现,这个包下载到了 GOPATH/github.com 下面了。我们要把它拷贝到 golang.org 目录下面

1
mv $GOPATH/src/github.com/golang/mobile $GOPATH/src/golang.org/x/mobile

然后重新执行:

1
go get golang.org/x/mobile/cmd/gomobile

不出意外,gomobile 已经安装完成了。执行gomobile version检查一下是否安装成功。

编译 go 代码

这一步要把 go 代码编译成 Android 平台使用的机器码。gomobile 是一个非常好用的工具,通过一个命令不仅能把 go 代码编译成平台码,同时还会使用 aar 包来包装它,也就是说,我们完全不用写恶心的 native 代码了,直接调用 gomobile 生成的 Java 代码就好了。

首先来到 go 项目目录下面,执行 gomobile 编译命令。gomobile 需要 NDK,再次确定一下是否安装 NDK。

1
gomobile bind -target=android mobile.go

mobile.go为入口文件。如果没什么问题的话,在项目目录下面就会多出两个文件。mobile.aarmobile-sources.jar。其中mobile.aar就是我们编译完成的文件。

Android 调用 Go

把上面的生成的mobile.aar拷贝到 Android 项目中的 lib 下面,同时修改build.gradle,在 dependencies 中加入或者修改一下代码,

默认值:

1
implementation fileTree(dir: 'libs', include: ['*.jar'])

修改后:

1
implementation fileTree(dir: 'libs', include: ['*.jar','*.aar'])

Sync 一下工程,通过 Java 测试一下我们的 go 代码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
internal class RunTask : AsyncTask<Void, Void, Any?>() {

    override fun doInBackground(vararg params: Void): Any? {
        Mobile.sayHello()
        Mobile.sayHelloWithParams("lecon")
        val result = Mobile.sayHelloWithParamsAndReturn("spawn")
        Log.d("AndroidGo",result)
        try {
            Mobile.sayHelloWithParamsAndReturnAndException("liucl")
        } catch (e:Exception) {
            e.printStackTrace()
        }
        return null
    }
}

运行结果:

1
2
3
4
2019-04-18 13:31:04.566 7925-7982/? D/AndroidGo: Hellospawn
2019-04-18 13:31:04.571 7925-7982/? W/System.err: at mobile.Mobile.sayHelloWithParamsAndReturnAndException(Native Method)
2019-04-18 13:31:04.590 7925-7987/? I/GoLog: Hello Mobile
2019-04-18 13:31:04.590 7925-7987/? I/GoLog: Hello lecon

这时候,你也许会发现,这几行代码的执行顺序是不确定的。因为 java 和 go 通信是跨进程调用,这几个方法有几个 log 是在 go 中输出,就不能保证执行顺序。

项目代码放到 github 上:https://github.com/leconio/AndroidCallGoDemo


 Gitalk评论