最近有一个问题,是在golang作为底层,想获取apk的版本号和版本号代码(通俗一点就是versionName和versionCode),如果这时java代码,可以很容易地通过
// please add try/catch ... ;-)
PackageInfo info = context.getPackageManager().getPackageInfo(getPackageName(), 0);
String versionName = info.versionName;
int versionCode = info.versionCode;
来获取,但是,如果你的主要程序都是go语言来写,需要在go语言中获取apk的版本号怎么处理呢?
主要的解决思路有三种:
一是在你的go程序初始化的时候,通过java上层传参的形式,将这些参数传递下来
二是通过gobind来直接调用java代码
三是通过cgo来写ndk代码,调用java方法
解决思路的分析
第一种java传参给go语言入口函数
优势在于写起来非常简单,只需要go语言的接口加参数即可,然后java调用go语言代码的时候加入参数即可,缺点就是以后有新需求来的时候,还需要加参数,可能参数会越来越长…
第二种通过gobind来直接调用java代码
gobind的官方代码有这么一段:
一开始我以为我也可以在上层直接将Java代码写好,context什么的直接通过重写Appliction类,得到一个static的context,就可以在go语言中直接使用啦,心里美滋滋的…
但是,直到我将代码都写好了之后,才发现,原来gobind并不支持import自己写的类,而是已知的Android API而已…
因此,这种思路尝试到了最后不得不放弃了
第三种通过cgo来调用java代码
可以说,这个方法算是不得以而为之吧,我也是看到了go语言针对asset资源目录的处理方式才有所顿悟:
有兴趣的自己翻来看一下,具体路径$GOPATH/src/golang.org/x/mobile/asset/asset_android.go。
虽然比较难看,但写起来还是那么酷酷的。
优点是,不需要去动java上层的代码,直接在cgo里边完成需求
缺点是,相对难以理解,对于不了解jni操作的人来说维护起来相对困难,调试也不太方便
示例:获取版本号
import "C"
var getVersionOnce sync.Once
func getVersionJni() {
e := app.RunOnJVM(func(vm, env, ctx uintptr) error {
C.getVersion(C.uintptr_t(vm), C.uintptr_t(env), C.jobject(ctx))
return nil
})
if e != nil {
log.Fatalf("getVersionJni: fatal: %s", e.Error())
}
}
func GetVersion() (v string) {
getVersionOnce.Do(getVersionJni)
log.Printf("GetVersion: versionCode: %d, versionName: %s", C.versionCode, C.GoString(C.pVersionName))
return strings.TrimSpace(C.GoString(C.pVersionName))
}
这里有一个技巧,由于versionName和versionCode几乎是在运行过程不会被修改的,所以使用sync.Once来确保getVersionJni函数只会被执行了一次,后续的直接从结果里边取出来就可以了。
提示:app.RunOnJVM如果找不到方法,你可能需要升级一下gomobile。
参考链接:



