分类: 其他 发表时间: 2020年06月04日

标题: go编译android使用的so库以及安卓的使用

下载ndk

编译android使用的so库必须通过android的ndk提供的c和c++来进行编译,ndk的下载地址https://developer.android.com/ndk/downloads

编写go源代码

go的源代码有几点注意:

  • 需要引入一个虚拟包”C”:import "C"
  • 导出的方法需要添加//export导出标识,注意//export之间不能有空格
  • func main() {} main方法需要留空

生成编译so库的工具链

进入到ndk的根目录cd /path/to/ndk,执行命令生成对应环境的工具链./build/tools/make-standalone-toolchain.sh --toolchain=x86_64-4.9 --platform=android-29 --install-dir=~/Library/toolchain-x86_64

注意:

  • --toolchain参数指定了该工具链的平台,可用平台可以在ndk根目录下的toolchains目录中查看
  • --install-dir参数指定了生成的工具链存放位置

平台架构标识说明:

  • x86 x86架构的32位版本
  • x86_64 x86架构的64位版本
  • arm arm架构的32位版本
  • aarch64 arm架构的64位版本

编译so库

编译时需要指定GOOSGOARCHCGO_ENABLEDCC等环境变量,这里尤其要注意,当GOOSandroid时,CGO_ENABLED会被设置为0,而CGO_ENABLED设置为0将会无法编译,提示错误go: no Go source files

编译命令env GOOS=android GOARCH=amd64 CGO_ENABLED=1 NDK_TOOLCHAIN=$TOOLCHAINX8664 CC=$TOOLCHAINX8664/bin/x86_64-linux-android-gcc go build -buildmode=c-shared -o=libc-shared.so ./src/main/c-shared.go

编译后如果没有问题会在当前目录下生成libc-shared.hlibc-shared.so两个文件,其中的so文件可被android加载

注意事项:

  • $TOOLCHAINX8664指向上一个步骤中编译出的工具链的根目录
  • CC使用的架构类型应该跟你要编译的目标平台一致

android使用jna加载so

android可以通过jna(jni的易用版)来加载so库,在安卓项目的app/build.gradle中的android配置下新增以下jni配置

  1. sourceSets {
  2. main {
  3. jniLibs.srcDirs = ['libs']
  4. }
  5. }

之后在app目录下新建一个文件夹libs,以及其子文件夹x86_64(对应到不同的架构),将编译好的so库文件放到对应架构的目录下

添加项目的jna依赖,将一下代码行加入到android项目app目录下的build.gradle文件中的dependencies部分

  1. implementation 'net.java.dev.jna:jna:5.5.0'

之后在这里https://github.com/java-native-access/jna/tree/master/dist下载对应平台的jar文件,android项目需要下载android-xxx.jar,具体取决于你支持的平台类型

下载后解压jar xf android-xxx.jar得到libjnidispatch.so,将该so库拷贝到android项目下的app/libs/x86_64目录下,并且将前边生成的libc-shared.so也拷贝进去

在项目中定义一个接口用于加载原生方法,示例代码:

  1. import com.sun.jna.Library;
  2. import com.sun.jna.Native;
  3. private interface GoToNet extends Library {
  4. GoToNet INSTANCE = Native.load("c-shared", GoToNet.class);
  5. String hello();
  6. }

其中hello方法即是用go编写的函数,该方法可以通过GoToNet.INSTANCE.hello()的形式来调用

注意:

  • 不同的平台架构需要不同架构的libjnidispatch.so以及libc-shared.so,分别下载或编译并拷贝过去就行了