欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Golang开发动态库的实现

程序员文章站 2022-05-25 22:06:03
我们平时使用的动态库都是由c/c++开发最后生成的.so文件。 可以先看看一个jni的开发过程。 一. 开发jni 有两种方式,现在一种比较快的方式是androidstudio你...

我们平时使用的动态库都是由c/c++开发最后生成的.so文件。

可以先看看一个jni的开发过程。

一. 开发jni

有两种方式,现在一种比较快的方式是androidstudio你在创建项目选择module的时候它会给你个jni的模板,直接使用那个就行。

但是我还是比较喜欢传统的方法。

简单来说传统的方式就是你用命令来把java文件变成c++的头文件

简单演示一遍,先写个java类

public class testjni {

  static {
    system.loadlibrary("kylimtest");
  }

  public static native string getmsg();

}

定义了一个native修饰的方法,在代码调用这个方法之后jni就会自动调用到动态库中相应的方法。

将这个类用命令生成头文件,来到文件夹路径下输入命令

javah -jni 包名.类名

可以看到默认会生成一个.h的头文件,自动命名为 包名_类名.h

/* do not edit this file - it is machine generated */
#include <jni.h>
/* header for class com_kylim_nativetest_testjni */

#ifndef _included_com_kylim_nativetest_testjni
#define _included_com_kylim_nativetest_testjni
#ifdef __cplusplus
extern "c" {
#endif
/*
 * class:   com_kylim_nativetest_testjni
 * method:  getmsg
 * signature: (i)ljava/lang/string;
 */
jniexport jstring jnicall java_com_kylim_nativetest_testjni_getmsg
 (jnienv *, jclass);

#ifdef __cplusplus
}
#endif
#endif

主要的核心就是这句

jniexport jstring jnicall java_com_kylim_nativetest_testjni_getmsg
 (jnienv *, jclass);

其它的我也不清楚,都是c相关的, 如果你嫌用命令生成麻烦,你可以自己创建一个.h文件然后方法命名就按照这样的规范去写

头文件只是为了定义,我们需要自己写原文件,所以要创建一个.cpp结尾的文件

#include "com_kylim_nativetest_testjni.h"

jniexport jstring jnicall java_com_kylim_nativetest_testjni_getmsg
    (jnienv *env, jclass cls){

  jstring result = env->newstringutf("结果是");
  return result;
}

方法命名是有规范的,看demo也知道怎么规范了,没必要多解释,这样两端的代码就写完了,但是仅仅这样是无法运行项目的。

还需要些一些配置,因为在androidstudio中是gradle去帮我们编译c++的代码,所以需要写这些配置。如果你不是用as开发,你用其它工具开发直接生成.so文件再丢进as中的话,可以忽略这一步。

先看看我的jni目录

Golang开发动态库的实现

要创建一个android.mk

#固定写法
local_path:=$(call my-dir)
#固定写法
include $(clear_vars)
#生成so名称
local_module := kylimtest
local_src_files := testone.cpp
#固定写法
include $(build_shared_library)

具体的配置可自行去查找,这里不是主要讲jni的,所以就不讲这么细。

还需要一个application.mk

# 选择不同的 abi,多个使用空格作为分隔符,全部是all
# app_abi := armeabi armeabi-v7a
app_abi := armeabi-v7a

# 指定要使用的运行时
app_stl := c++_static

当然这样还不行,都说了是gradle进行编译,那么肯定还要在gradle中写一些配置

android {
   defaultconfig {
        ndkbuild {
        //指定 application.mk 的路径
        arguments "ndk_application_mk:=src/main/jni/application.mk"
        //指定生成哪些平台的 so 文件
        abifilters "armeabi-v7a"
        //cflags 和 cppflags 是用来设置环境变量的, 一般不需要动
        cflags "-dtest_c_flag1", "-dtest_c_flag2"
        cppflags "-dtest_cpp_flag2", "-dtest_cpp_flag2"
      }
   }

  sourcesets { main { jni.srcdirs = ['src/main/jni'] } }

  externalnativebuild {
    ndkbuild {
      path file('src/main/jni/android.mk')
    }
  }

}

这样就能简单的跑一个jni的demo,总的来说就是java这边写一个类定义一些native方法和加载,c++这边写具体的方法实现。

二.用go开发动态库

上面说的原生方法是用c/c++进行开发的,那么如果你不会c++的话怎么办,c++的学习也并非这么容易,就拿两边的类型来说,一开始新手肯定会碰到类型转换的问题,往往会先劝退一些人,但是go不一样,有java基础的话学起go还是挺快的。

那么用go开发的动态库是怎样的?也是so文件吗,是不是也像c++一样,编译后经过某步操作生成so文件。

我看到网上有些文章确实是写怎么生成so的,但是说得太少,感觉不可靠,直到我看到官方有写。

Golang开发动态库的实现

可以在官方中看到是有一个mobile的库的

读下去它会指引你去wiki

https://github.com/golang/go/wiki/mobile

Golang开发动态库的实现

可以看出它会打出一个aar的文件,那么aar对于我们接入来说确实很方法,但我很想探究这个aar里面究竟是什么,所以我们需要打出一个aar然后解压看看它里面到底是什么

这里先说一下,下载这个库之前,你本地肯定先要配置好go的环境

然后按照这里的流程就行下载

go get -d golang.org/x/mobile/example/basic

但这输入这条命令需要*的方式才能下载,总的来说很麻烦。

所以我们可以直接克隆mobile的库,就是上面的这个链接

直接下载下来,除此之外,还需要tools,这些都在go中,链接

将这两个下载下来,然后拷贝到你的go的以下路径

go/src 创建一个文件夹golang.org/x ,把这两个文件夹丢进去

然后输入命令

gomobile init

可以输入命令 查看安装配置是否成功

gomobile bind -help

如果配置成功会给你一些提示

Golang开发动态库的实现

我感觉文档写得还是不算清楚,但是它有告诉你用什么命令生成aar

gomobile bind -o app/hello.aar -target=android golang.org/x/mobile/example/bind/hello

你在gopath中创建一个go文件,我是用goland进行开发的,项目的目录设置成gopath,编写完之后,可以直接在文件中运行

gomobile bind -o 输入文件名.aar -target=android

这样就能在文件夹中生成一个aar

接着我们看看aar里面是什么,解压

Golang开发动态库的实现

首先可以看到生成这些abi的so文件,再看看manifest

Golang开发动态库的实现

这里有限制最低版本,所以如果你的版本比他还低的话就需要注意一下了

然后res里面是可以看到没有文件的。

最后我们反编译class文件

Golang开发动态库的实现

因为这不是demo,直接是写公司的项目,所以有些地方要码,但是不影响。

从这里看得出,go帮我们生成了一个java文件,这个java文件定义了再go中命名的原生方法。

其实从这里就可以看出,go用的也基本是我们最上面写的jni的方法,只是他帮你封装起来了而已

但是他的原生代码是不是转成c++的我就不清楚了,因为我不会反编译so文件。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。