您现在的位置是:网站首页> Go语言
Go经验总结
- Go语言
- 2022-04-23
- 1235人已阅读
项目目录下编译
go build .
Go显示和设置Go的环境变量
go env
go env -w GO111MODULE=auto
golang打包成android
本文只讲述如果使用将golang工程打包成jar/aar/apk,适用于android开发者需要集成一些golang开发的微服务或者其他golang语言实现的功能。
环境安装
1. golang开发环境安装
安装包下载地址:下载,windows建议下载msi文件,直接安装之后环境变量都配置好了。 创建一个go的workspace,然后创建一个hello.go
//hello.go
//包名
package hello
//引入模块
import "fmt"
//main函数/程序入口
func main() {
fmt.Println("Hello, World!")
}
执行命令:go run hello.go
2. Android 开发环境安装
android studio 已默认安装了编译需要的ndk,但是路径并没有添加到path中,所以执行ndk-build时会提示找不到命令,这时只要找到ANDROID_SDK_ROOT/ndk和ANDROID_SDK_ROOT/ndk-bundle,将其添加到path中,这时的环境已经能满足下一步的要求了。
3. gomobile安装
要将go打包成aar/jar/apk以及IOS应用(需要xcode环境),则需要一个go的打包工具gomobile, 安装方式有两种
#方法1:
使用命令:`go get golang.org/x/mobile/cmd/gomobile`(需要翻墙)
#方法2:
#下载源码包:
git clone https://github.com/golang/mobile.git
#将源码拷贝到 $GOPATH/src/golang.org/x
#执行命令:
go build golang.org/x/mobile/cmd/gomobile
#这时会在C:\Users\username\go\bin下生成gobind和gomobile两个文件
#gomobile的初始化,
gomobile init
4. 打包示例
#将hello工程目录拷贝到C:\Go\src下面
#打包sdk
gomobile bind -target=android hello
#会在当前目录下生成hello.arr 和 hello.jar 两个sdk包
#打包apk
gomobile build -target=android hello
#会在当前目录下直接生成hello.apk
gomobile编译
(1.)下载代码,并生成二进制文件,gomobile和gobind
go get golang.org/x/mobile/cmd/gomobile
或者
git clone https://github.com/golang/mobile
copy到$GOPATH/src/golang.org/x/
//编译生成gobind二进制文件
cd mobile/cmd/gobind
go build .
拷贝gobind到$GOPATH/bin目录,并加入环境变量
//编译生成gomobile二进制文件
cd mobile/cmd/gomobile
go build .
拷贝gomobile到$GOPATH/bin目录,并加入环境变量
//查看是否安装成功
gomobile version
gomobile example测试
gomobile init
//此命令会生成名为basic的apk安装包
gomobile build -target=android golang.org/x/mobile/example/basic
//此命令将安装apk包到已连接的android设备
gomobile install golang.org/x/mobile/example/basic
//生成jar、aar文件
gomobile bind -target=android golang.org/x/mobile/example/bind/hello
或 D:\go\src\golang.org\x\mobile\example\bind>gomobile bind -target=android ./hello
gomobile example编译错误处理
配置环境变量
gomobile-ipfs编译
(1.)go代码中编译
代理路径: https://github.com/ipfs-shipyard/gomobile-ipfs
cd /go/bind/
gomobile bind -target=android ./ipfs
生成jar和aar文件
gomobile bind -target=android hello
生成hello.aar文件和hello-sources.jar文件,放到Android工程的libs目录里,aar文件供调用,source.jar可以看源码。
// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package hello is a trivial package for gomobile bind example.
package hello
import "fmt"
func Greetings(name string) string {
fmt.Printf("hello go,this is log\n")
return fmt.Sprintf("Hello aaa, %s!", name)
}
func Test1(buf []byte) []byte{
fmt.Printf("in buf is:%x\n",buf)
outbuf := []byte{0x31,0x32,0x33,0x34}
return outbuf
}
然后应用里就可以很爽的调用:
/*
* Copyright 2015 The Go Authors. All rights reserved.
* Use of this source code is governed by a BSD-style
* license that can be found in the LICENSE file.
*/
package org.golang.example.bind;
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.widget.TextView;
import hello.Hello;
public class MainActivity extends Activity {
private TextView mTextView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mTextView = (TextView) findViewById(R.id.mytextview);
// Call Go function. test String
String greetings = Hello.greetings("Android and Gopher aaa11");
mTextView.setText(greetings);
// Call Go function. test byte[]
byte[] inbuf = new byte[6];
inbuf[0] = 0x39;
inbuf[1] = 0x38;
inbuf[2] = 0x37;
inbuf[3] = 0x36;
byte[] outbuf = Hello.test1(inbuf);
System.out.println(outbuf);
}
}
AndroidStdio的配置麻不麻烦呢?也不麻烦。配置下引用外部库即可。
dependencies {
implementation fileTree(include: ['*.jar'], dir: 'libs')
implementation fileTree(include: ['*.aar'], dir: 'libs')
implementation 'com.android.support:appcompat-v7:22.1.1'
//implementation project(':hello')
implementation files('libs/hello.aar')
}
最后再来说下环境,也很简单,只需配置一次即可。
总结下:
直接用AndroidNDK编写SDK,需要自己写JNI。而gomobile一个命令,把脏活累活都给弄好了。
可以一份代码支持Android和iOS,维护上比较方便。
体积上,gomobile的so最起码有2.8MB,比C要大不少,也还能接受。因为效率高啊。
如果再有人找我封装JNI层的.so?我想,我想用go来做!
至于执行的效率,可反编译过来看下,其实内部还是调的c的JNI,只不过gomobile命令把这些繁琐的事做了。
效率应差不了多少。至于稳定性,虽然gomobile是谷歌内部的一个实验性项目,但是你只使用gobind做native层的工作,这部分已经很稳定了。
gomobile init之前需要环境变量中配置了ndk环境,可把ndk环境加到系统环境变量,或者通过ndk标签指定ndk目录gomobile init -ndk 指定。注意,要求ndk版本是在19以上才行
Go生成go动态库或静态库的方法
预备知识
plugin模式
插件运行方式
go plugin包使用
相关知识(推荐:go语言教程)
go build 可以指定buildmode。分为了多种模式。具体模式如下。
模式 说明
当前go版本 1.10.3
archive 编译成二进制文件。一般是静态库文件。 xx.a
c-archive 编译成C归档文件。C可调用的静态库。xx.a。注意要编译成此类文件需要import C 并且要外部调用的函数要使用 “//export 函数名” 的方式在函数上方注释。否则函数默认不会被导出。
c-shared 编译成C共享库。同样需要 import “C” 和在函数上方注释 // export xxx
default 对于有main包的直接编译成可执行文件。没有main包的,编译成.a文件
exe 编译成window可执行程序
plugin 将main包和依赖的包一起编译成go plugin。非main包忽略。【类似C的共享库或静态库。插件式开发使用】
实例
结构:
-softplugin //根目录
-soft //软件目录
-plugins //插件目录
-itf //接口目录
无自定义数据
// plugins/hello.go
package main
import "fmt"
func Hello(){
fmt.Println("hello")
}
// go build -buildmode=plugin -o hello.so hello.go
// soft/basetype.go
package main
import (
"os"
"path"
"plugin"
"fmt"
)
func main(){
//加载插件
pluginDir := "../plugins"
//扫描文件夹下所有so文件
f, err := os.OpenFile(pluginDir, os.O_RDONLY, 0666)
if err != nil {
panic(err)
}
fi, err := f.Readdir(-1)
if err != nil {
panic(err)
}
plugins := make([]os.FileInfo, 0)
for _, ff := range fi {
if ff.IsDir() || path.Ext(ff.Name()) != ".so" {
continue
}
plugins = append(plugins, ff)
pdll, err := plugin.Open(pluginDir + "/" + ff.Name())
if err != nil {
fmt.Println(err)
continue
}
plg, err := pdll.Lookup("Hello")
if err != nil {
panic(err)
}
plg.(func())()
}
}
// go run basetype.go
定义插件接口 interface。
//------------------------------------------------------
// itf/itf1.go
package itf
type Printor interface{
Print(v interface{})
}
//------------------------------------------------------
// plugins/p1.go
package main
import (
"fmt"
"softplugin/itf"
)
type ScreenPrintor struct{}
func (ScreenPrintor)Print(v interface{}){
fmt.Println("p1p1 ",v)
}
func Install() Printor{
return &ScreenPrintor{}
}
//-----------------------------------------------------
// soft/s1.go
package main
import (
"softplugin/itf"
"os"
"path"
"plugin"
"fmt"
)
var(
printors = make([]itf.Printor, 0)
)
func main(){
//加载插件
pluginDir := "../plugins"
//扫描文件夹下所有so文件
f, err := os.OpenFile(pluginDir, os.O_RDONLY, 0666)
if err != nil {
panic(err)
}
fi, err := f.Readdir(-1)
if err != nil {
panic(err)
}
plugins := make([]os.FileInfo, 0)
for _, ff := range fi {
if ff.IsDir() || path.Ext(ff.Name()) != ".so" {
continue
}
plugins = append(plugins, ff)
pdll, err := plugin.Open(pluginDir + "/" + ff.Name())
if err != nil {
fmt.Println(err)
continue
}
plg, err := pdll.Lookup("Hello")
if err != nil {
panic(err)
}
printors = append(printors, (plg.(func() itf.Printor))())
}
for _, p := range printors {
p.Print("pppp")
}
}
Go不定参数
package main
import "fmt"
func MyPrintf(args ...interface{}) {
for _, arg := range args {
switch arg.(type) {
case int:
fmt.Println(arg, "is an int value.")
case string:
fmt.Println(arg, "is a string value.")
case int64:
fmt.Println(arg, "is an int64 value.")
default:
fmt.Println(arg, "is an unknown type.")
}
}
}
func main() {
var v1 int = 1
var v2 int64 = 1111
var v3 string = "hello world!"
var v4 float32 = 1.1111
MyPrintf(v1, v2, v3, v4)
}
func P (v... string) {
for _,item := range v {
fmt.Println("item:",item)
}
}
func main() {
var l []string
l = append(l,"a")
l = append(l,"b")
fmt.Println("l is ",l)
P(l...)
}
下一篇:go编译树莓派上运行的程序