Golang开发动态库的实现

我们平时使用的动态库都是由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目录

要创建一个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的,但是说得太少,感觉不可靠,直到我看到官方有写。

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

https://github.com/golang/mobile

读下去它会指引你去wiki

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

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

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

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

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

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

所以我们可以直接克隆mobile的库,就是上面的这个链接 https://github.com/golang/mobile

直接下载下来,除此之外,还需要tools,这些都在Go中,链接 https://github.com/golang/tools

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

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

然后输入命令

gomobile init

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

gomobile bind -help

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

我感觉文档写得还是不算清楚,但是它有告诉你用什么命令生成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里面是什么,解压

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

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

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

最后我们反编译class文件

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

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

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

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

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

(0)

相关推荐

  • 详解Golang利用反射reflect动态调用方法

    编程语言中反射的概念 在计算机科学领域,反射是指一类应用,它们能够自描述和自控制.也就是说,这类应用通过采用某种机制来实现对自己行为的描述(self-representation)和监测(examination),并能根据自身行为的状态和结果,调整或修改应用所描述行为的状态和相关的语义. 每种语言的反射模型都不同,并且有些语言根本不支持反射.Golang语言实现了反射,反射机制就是在运行时动态的调用对象的方法和属性,官方自带的reflect包就是反射相关的,只要包含这个包就可以使用. 多插一句,

  • Golang开发动态库的实现

    我们平时使用的动态库都是由C/C++开发最后生成的.so文件. 可以先看看一个JNI的开发过程. 一. 开发JNI 有两种方式,现在一种比较快的方式是AndroidStudio你在创建项目选择Module的时候它会给你个JNI的模板,直接使用那个就行. 但是我还是比较喜欢传统的方法. 简单来说传统的方式就是你用命令来把java文件变成C++的头文件 简单演示一遍,先写个java类 public class TestJni { static { System.loadLibrary("KylimT

  • Golang开发库的集合及作用说明

    目录 golang用于创建和发送电子邮件的库 golang处理日期和时间的库 数据库迁移 Go语言实现的数据库 golang通用数据结构及算法 golang用于进行配置解析的库 golang认证和授权库 golang用于操作音频的库 golang代码中嵌入其他语言的包 Go日志库 golang操作表单的库 Go实现消息系统的库 golang用于创建和发送电子邮件的库 douceur - HTML 邮件中的内联 CSS email - 一个健壮的.灵活的 email 库 Go-dkim - DKI

  • Golang使用CGO与Plugin技术运行加载C动态库

    目录 文章简介 技术背景 解决方案1 解决方案2 文章简介 本文介绍一种 Golang 程序在运行时加载 C 动态库的技术,跳过了 Golang 项目编译阶段需要链接 C 动态库的过程,提高了 Golang 项目开发部署的灵活性. 技术背景 Golang 程序调用 OpenCC 动态库的函数,执行文本繁体转简体操作. 需要在编译时不链接动态库,只在程序运行时加载 OpenCC 动态库. OpenCC 库是使用 C++ 编写的繁简体转换程序,提供 C 语言 API 接口. 开源项目地址 CGO 技

  • 详解dll动态库的开发与调用及文件的读写小程序

    详解dll动态库的开发与调用及文件的读写小程序 首先我们先来学习一下动态库的调用,先找到动态库的.dll和.lib文件并将其导入到同源文件相同级别的文件夹下面,然后在添加进其头文件,并右击项目处,然后点击链接,链接我们的lib文件(一定要是全名称包括扩展名),然后我们就可以调用动态库的函数了. Dll是我们具体的函数, lib使我们的函数描述文件. #include <stdio.h> #include <stdlib.h> /* 该代码是对文件读写操作的使用 */ #pragma

  • golang 调用c语言动态库方式实现

    下面我们自己在 Linux 下做一个动态库(.so 文件 - Shared Object),然在用 Go 来使用它.本文所用的操作系统为 Ubuntu18.04, 以 gcc 作为编译器. 1.实现头文件,声明文件中函数.这里创建一个add.h文件. #ifndef __ADD_H__ #define __ADD_H__ char* Add(char* src, int n); #endif 2.实现add主体函数add.c #include <string.h> #include <s

  • Flutter iOS开发OC混编Swift动态库和静态库问题填坑

    目录 引言 OC接入Swift 插件 静态库和 Framework 区别 新的问题: non-modular heade 不能在Framework Module中使用非Modular 的 Header 引言 Flutter 在 iOS 上的编译问题相信大家多多少少遇到过,不知道大家在搜索这方便的问题时,得到的答案是不是让你 clean 或者 install 多几次,很多时候就算解决完问题,也是处于薛定谔的状态,所以本篇也简单记录下 Flutter 开发中,OC 混编 Swift 遭遇动态库和静态

  • Golang如何调用windows下的dll动态库中的函数

    使用syscall调用 package main import ( "fmt" "syscall" "time" "unsafe" ) const ( MB_OK = 0x00000000 MB_OKCANCEL = 0x00000001 MB_ABORTRETRYIGNORE = 0x00000002 MB_YESNOCANCEL = 0x00000003 MB_YESNO = 0x00000004 MB_RETRYCANC

  • Linux下g++编译与使用静态库和动态库的方法

    在windows环境下,我们通常在IDE如VS的工程中开发C++项目,对于生成和使用静态库(*.lib)与动态库(*.dll)可能都已经比较熟悉,但是,在linux环境下,则是另一套模式,对应的静态库(*.a)与动态库(*.so)的生成与使用方式是不同的.刚开始可能会不适应,但是用多了应该会习惯这种使用,因为步骤上并没有VS下配置那么繁琐. 下面就分别总结下linux下生成并使用静态库与动态库的方法:(由于是C++项目,所以编译器用的g++,但是与gcc的使用是相通的) 首先是准备工作,把我们需

  • 分析Windows和Linux动态库

    摘要:动态链接库技术实现和设计程序常用的技术,在Windows和Linux系统中都有动态库的概念,采用动态库可以有效的减少程序大小,节省空间,提高效率,增加程序的可扩展性,便于模块化管理.但不同操作系统的动态库由于格式 不同,在需要不同操作系统调用时需要进行动态库程序移植.本文分析和比较了两种操作系统动态库技术,并给出了将Visual C++编制的动态库移植到Linux上的方法和经验. 1.引言 动态库(Dynamic Link Library abbr,DLL)技术是程序设计中经常采用的技术.

  • xcode 详解创建静态库和动态库的方法

    xcode 创建静态库和动态库 1.linux中静态库和动态库区别: 库从本质上来说是一种可执行代码的二进制格式,可以被载入内存中执行.库分静态库和动态库两种. 静态库:这类库的名字一般是libxxx.a:利用静态函数库编译成的文件比较大,因为整个函数库的所有数据都会被整合进目标代码中,他的优点就显而易见了,即编译后的执行程序不需要外部的函数库支持,因为所有使用的函数都已经被编译进去了.当然这也会成为他的缺点,因为如果静态函数库改变了,那么你的程序必须重新编译. 动态库:这类库的名字一般是lib

随机推荐