您现在的位置是:网站首页> Go语言

Go经验总结

摘要

Go显示和设置Go的环境变量

golang打包成android

项目目录下编译

Go生成go动态库或静态库的方法

Go不定参数


项目目录下编译

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编译错误处理

配置环境变量

1.png

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...)


}


Top