一步一步使用Android呼叫Golang
前提需要了解的
-
在Android中執行go程式碼,需要用到一個工具
gomobile
,後面會說到安裝方式。 -
Go開發環境,配置好GOPATH和GOROOT等。
-
AndroidSDK和AndroidNDK
準備好Go程式碼
首先要準備好GO的開發壞境,並且配置好GOPATH,咱們的專案叫mobilego
mkdir code/mobilego cd code/mobilego echo export PATH=\$PATH:$(pwd) >> ~/.zshrc # .zshrc 為你的bash地址 source ~/.zshrc
其中code/mobilego
是咱們go專案地址。那麼現在就可以準備go程式碼了,那麼我們可以按照這個樣子新建一個專案。
mobilego └── src └── mobile └── mobile.go
其中,src目錄是必須要有的,因為gomobile需要從這個路徑下查詢包。其中mobile.go
程式碼為:
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
可以找到。
- 首先下載這個工具
go get golang.org/x/mobile/cmd/gomobile
golang.org的程式碼基本上都託管在google伺服器,一般來說在國內都不會下載成功的。那麼只好換成另外一種下載方式。在這裡,我們把golang.org/x/mobile/cmd/gomobile
中的golang.org/x/
換成github.com/golang/
。如下所示:
go get github.com/golang/mobile/cmd/gomobile
這時候你會發現,這個包下載到了GOPATH/github.com下面了。我們要把它拷貝到golang.org目錄下面
mv $GOPATH/src/github.com/golang/mobile $GOPATH/src/golang.org/x/mobile
然後重新執行:
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。
gomobile bind -target=android mobile.go
mobile.go
為入口檔案。如果沒什麼問題的話,在專案目錄下面就會多出兩個檔案。mobile.aar
和mobile-sources.jar
。其中mobile.aar
就是我們編譯完成的檔案。
Android呼叫Go
把上面的生成的mobile.aar
拷貝到Android專案中的lib下面,同時修改build.gradle
,在dependencies中加入或者修改一下程式碼,
預設值:
implementation fileTree(dir: 'libs', include: ['*.jar'])
修改後:
implementation fileTree(dir: 'libs', include: ['*.jar','*.aar'])
Sync一下工程,通過Java測試一下我們的go程式碼。
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 } }
執行結果:
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