请教.net上怎么gradle 引用第三方so*so文件中的库

Java框架JNA调用C方法(windows链接库dll文件、linux链接库so文件)
介绍给大家介绍一个最新的访问本机代码的Java框架—JNA。JNA(Java Native Access)框架是一个开源的Java框架,是SUN公司主导开发的,建立在经典的JNI的基础之上的一个框架。JNA项目地址:https://jna.dev.java.net/非常强大、易用,功能上类似与.NET的P/Invoke。&不堪回首的JNI我们知道,使用JNI调用.dll/.so共享类库是非常非常麻烦和痛苦的。如果有一个现有的.dll/.so文件,如果使用JNI技术调用,我们首先需要另外使用C语言写一个.dll/.so共享库,使用SUN规定的数据结构替代C语言的数据结构,调用已有的 &dll/so中公布的函数。然后再在Java中载入这个适配器dll/so,再编写Java & native函数作为dll中函数的代理。经过2个繁琐的步骤才能在Java中调用本地代码。因此,很少有Java程序员愿意编写调用dll/.so库中的原生函数的java程序。这也使Java语言在客户端上乏善可陈。可以说JNI是Java的一大弱点!.NET平台上强大的P/Invoke而在.NET平台上,强大的P/Invoke技术使我们Java程序员非常羡慕。使用P/Invoke技术,只需要使用编写一个.NET函数,再加上一个声明的标注,就可以直接调用dll中的函数。不需要你再使用C语言编写dll来适配。&不逊于P/Invoke的JNA现在,不需要再羡慕.NET的P/Invoke机制了。JNA把对dll/.so共享库的调用减少到了和P/Invoke相同的程度。使用JNA,不需要再编写适配用的.dll/.so,只需要在Java中编写一个接口和一些代码,作为.dll/.so的代理,就可以在Java程序中调用dll/so。JNA快速启动& & &现在让我们直接进入JNA的世界。你只需要下载一个jar包,就可以使用JNA的强大功能方便地调用动态链接库中的C函数。import com.sun.jna.Limport com.sun.jna.Nimport com.sun.jna.P/** * @description: TODO * @author Somnus date 日 下午1:26:56 */public class HelloWorld {
public interface CLibrary extends Library {
CLibrary INSTANCE = (CLibrary) Native.loadLibrary(
(Platform.isWindows() ? &msvcrt& : &c&),
CLibrary.class);
void printf(String format, Object... args);
public static void main(String[] args) {
CLibrary.INSTANCE.printf(&Hello, World/n&);
for (int i = 0; i & args. i++) {
CLibrary.INSTANCE.printf(&Argument %d: %s/n&, i, args[i]);
}}可以看到控制台中打印出了Hello, World&& & 但是,请注意,这个程序实际上是使用msvcrt.dll这个C运行时库中的printf函数打印出上面这些字符的。&& & 看,多简单,不需要写一行C代码,就可以直接在Java中调用外部动态链接库中的函数!JNA技术解密JNA工作原理JNA是建立在JNI技术基础之上的一个Java类库,它使您可以方便地使用java直接访问动态链接库中的函数。原来使用JNI,你必须手工用C写一个动态链接库,在C语言中映射Java的数据类型。JNA中,它提供了一个动态的C语言编写的转发器,可以自动实现Java和C的数据类型映射。你不再需要编写C动态链接库。当然,这也意味着,使用JNA技术比使用JNI技术调用动态链接库会有些微的性能损失。可能速度会降低几倍。但影响不大。&JNA技术难点1,当前路径是在项目下,而不是bin输出目录下。2,数据结构的对应关系:Java—C和操作系统数据类型的对应表Java TypeC TypeNative Representationbooleanint32-bit integer (customizable)bytechar8-bit integercharwchar_tplatform-dependentshortshort16-bit integerintint32-bit integerlonglong long, __int6464-bit integerfloatfloat32-bit floating pointdoubledouble64-bit floating pointBufferPointerpointerplatform-dependent (32- or 64-bit pointer to memory)&T&[] (array of primitive type)pointerarray32- or 64-bit pointer to memory (argument/return)contiguous memory (struct member)除了上面的类型,JNA还支持常见的数据类型的映射。Stringchar*NUL-terminated array (native encoding or&jna.encoding)WStringwchar_t*NUL-terminated array (unicode)String[]char**NULL-terminated array of C stringsWString[]wchar_t**NULL-terminated array of wide C stringsStructurestruct*structpointer to struct (argument or return) (or explicitly)struct by value (member of struct) (or explicitly)Unionunionsame as&StructureStructure[]struct[]array of structs, contiguous in memoryCallback&T& (*fp)()function pointer (Java or native)NativeMappedvariesdepends on definitionNativeLonglongplatform-dependent (32- or 64-bit integer)PointerTypepointersame as&Pointer&JNA编程过程JNA把一个dll/.so文件看做是一个Java接口。Dll是C函数的集合、容器,这正和接口的概念吻合。我们定义这样一个接口,public interface TestDll1 extends Library {
* 当前路径是在项目下,而不是bin输出目录下。
TestDll1 INSTANCE = (TestDll1)Native.loadLibrary(&TestDll1&, TestDll1.class);
public void say(WString value);
} 如果dll是以stdcall方式输出函数,那么就继承StdCallLibrary。否则就继承默认的Library接口。接口内部需要一个公共静态常量:instance。TestDll1 INSTANCE = (TestDll1)Native.loadLibrary(&TestDll1&, TestDll1.class);通过这个常量,就可以获得这个接口的实例,从而使用接口的方法。也就是调用外部dll的函数!&注意:1、Native.loadLibrary()函数有2个参数:& & & dll或者.so文件的名字,但不带后缀名。这符合JNI的规范,因为带了后缀名就不可以跨操作系统平台了。& & & & & 搜索dll的路径是:& & & & & & & 项目的根路径& & & & & & & 操作系统的全局路径、& & & & & & & path指定的路径。& & &第二个参数是本接口的Class类型,JNA通过这个Class类型,根据指定的dll/.so文件,动态创建接口的实例。2,接口中你只需要定义你需要的函数或者公共变量,不需要的可以不定义。public void say(WString value);参数和返回值的类型,应该和dll中的C函数的类型一致。这是JNA,甚至所有跨平台调用的难点。这里,C语言的函数参数是:wchar_t*。JNA中对应的Java类型是WStirng。这里面提到一点,我在项目用出现过这种类型,jna调用C的时候如何去获取C中输出参数的值OpenSSL_DeriveKey(
// 输出参数,保存导出的密钥的缓存
unsigned int uiLen,
// 输入参数,要求导出的密钥的长度,此时调用者需要保证缓存 pszKey 的大小
const char * pszInitKey,
// 输入参数:初始密钥
unsigned int uiInitKeyLen,
// 输入参数:初始密钥的长度
为 0 时,当 pszInitKey 为字符串,自动取该字符串的长度
const char * pszSalt,
// 输入参数:盐(属于干扰信息)
unsigned int uiSaltLen,
// 输入参数:盐的长度
为 0 时,当 pszSalt 为字符串,自动取该字符串的长度
unsigned int uiIterationCount // 重复次数
); // 0:成功,其它:失败对应的Java代码int OpenSSL_DeriveKey(String pszKey , int uiLen, String pszInitKey, int uiInitKeyLen, String pszSalt,
int uiSaltLen, int uiIterationCount);java调用的时候怎么得到pszkey的值呢这时候有个Pointer类以及它的子类Memory可以帮助到我们,具体的可以查看相关api,这里我只给出一个例子/*生成MAC校验*//*************参数说明:输入参数:
:算法模式 0-恒生(默认)
:待生成MAC串
: databuf串的最小8的整数倍长度(例如:如果databuf长度为7,datalen=8。
如果databuf长度为13,则datalen=16)
:生成的MAC
*************/char *GenerateMAC(int method, char *databuf, int datalen, char *key, char *MAC);这里我们需要获取MAC的值,Java代码如下public class JNAUtil {
public interface NativeInterface extends Library {
public static final NativeInterface INATANCE = (NativeInterface) Native.loadLibrary(&HsDes&, NativeInterface.class);
* 恒生MAC算法::填写MAC_HS
* @param method
算法模式 0-恒生(默认)1-标准
* @param dataBuf
待生成MAC串
* @param dataLen
databuf串的最小8的整数倍长度(例如:如果databuf长度为7,datalen=8。如果databuf长度为13,则datalen=16)
* @param key
* @param mac
* 注:(方法名必须和C底层一样,不能采取驼峰命名方式)
public String GenerateMAC(int method, Pointer databuf, int datalen, String key, Pointer mac) throws E
* @param method
* @param databuf
* @param datalen
* @param key
* @throws Exception
public static String generateMAC(int method, String databuf, int datalen, String key) throws Exception{
byte[] sb = databuf.getBytes(&GB2312&);
int len = sb.
if(len%8 != 0){
len = (len/8 +1)*8;
Pointer sp = new Memory(len);
for(int i=0;i&i++){
if(i & sb.length){
sp.setByte(i, sb[i]);
sp.setByte(i, (byte)0x00);
Pointer p = new Memory(8);
NativeInterface.INATANCE.GenerateMAC(method, sp, datalen, key, p);
byte[] result = p.getByteArray(0,8);
return StringUtils.rightPad(byte2hex(result).toUpperCase(), 32, '0');
// 从字节数组到十六进制字符串转换
private static String byte2hex(byte[] arr) {
StringBuffer sb = new StringBuffer();
for (int i = 0; i & arr. ++i) {
final String HEX = &abcdef&;
// 取出这个字节的高4位,然后与0x0f与运算,得到一个0-15之间的数据,通过HEX.charAt(0-15)即为16进制数
sb.append(HEX.charAt((arr[i] && 4) & 0x0f));
// 取出这个字节的低位,与0x0f与运算,得到一个0-15之间的数据,通过HEX.charAt(0-15)即为16进制数
sb.append(HEX.charAt(arr[i] & 0x0f));
return sb.toString();
}}&所有跨平台、跨语言调用的难点有过跨语言、跨平台开发的程序员都知道,跨平台、语言调用的难点,就是不同语言之间数据类型不一致造成的问题。绝大部分跨平台调用的失败,都是这个问题造成的。关于这一点,不论何种语言,何种技术方案,都无法解决这个问题,这需要程序员的仔细开发和设计。这是程序员的责任。&常见的跨平台调用有:Java调用C语言编写的dll、.so动态链接库中的函数。NET通过P/Invoke调用C语言编写的dll、.so动态链接库中的函数。通过WEBService,在C,C++,Java,.NET等种种语言间调用。WebService传递的是xml格式的数据。即使是强大的P/Invoke或者WebService,在遇到复杂的数据类型和大数据量的传递时,还是会碰到很大的困难。&因为,一种语言的复杂的数据类型,很难用另一种语言来表示。这就是跨平台调用问题的本质。如,WEBService调用中,很多语言,如Java,.NET都有自动实现的Java/.NET类型和XML类型之间的映射的类库或者工具。但是,在现实的编程环境中,如果类型非常复杂,那么这些自动转换工具常常力不从心。要么Object-XML映射错误。要么映射掉大量的内存。&因此,我个人对这些Object-XML映射框架相当不感冒。我现在使用WEBService,都是直接手工使用xml处理工具提取xml中的数据构建对象。或者反过来,手工根据Object中的属性值构建xml数据。&Java和C语言之间的调用问题,也是如此。Java要调用C语言的函数,那么就必须严格按照C语言要求的内存数量提供Java格式的数据。要用Java的数据类型完美模拟C语言的数据类型。JNA已经提供了大量的类型匹配C语言的数据类型。&跨平台、跨语言调用的第一原则:就是尽量使用基本、简单的数据类型,尽量少跨语言、平台传递数据!只有你才能拯救你自己。如果在你的程序中,有复杂的数据类型和庞大的跨平台数据传递。那么你必须另外写一些Fa?ade接口,把需要传递的数据类型简化,把需要传递的数据量简化。否则,不论是实现的难度还是程序的性能都很难提高。&JNI还是不能废我们已经见识了JNA的强大。JNI和它相比是多么的简陋啊!但是,有些需求还是必须求助于JNI。JNA是建立在JNI技术基础之上的一个框架。使用JNI技术,不仅可以实现Java访问C函数,也可以实现C语言调用Java代码。而JNA只能实现Java访问C函数,作为一个Java框架,自然不能实现C语言调用Java代码。此时,你还是需要使用JNI技术。JNI是JNA的基础。是Java和C互操作的技术基础。
最新教程周点击榜
微信扫一扫14168人阅读
JNI相关(11)
1,在项目根目录下建立文件夹libs/armeabi文件夹
2,将so库放入&libs/armeabi文件夹
注意事项:
1,如果采用静态注册的方式请注意C文件中严格按照命名规则&Java_packageName_className_method()的方式命名
2,在Android项目中建立同上述命名规则中packageName中相同的包名,在此包名下建立同上述命名规则中className相同的类名
3,在className声明native方法
4,程序中加载so库&System.loadLibrary(&data/data/xxx.xxx.xxx/lib/xx.so&)或者&System.loadLibrary(&xx&),例如:System.loadLibrary(&data/data/com.dtBank.app.service/lib/libjnixcld.so&);
推荐用:System.loadLibrary(&xx&)
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:273424次
积分:3200
积分:3200
排名:第8193名
原创:41篇
转载:181篇
评论:23条
(1)(10)(3)(11)(10)(1)(2)(5)(12)(3)(1)(8)(15)(19)(10)(35)(29)(12)(32)(3)5533人阅读
技术(21)
是否JNI可以调用C++的动态库,但C++动态库必须是自己写的。现实中,我们常常会使用供应商提供的动态库文件(.dll/.so),通过其提供的接口实现相关业务,如果直接使用JNI调用,恐怕不能实现。在这种情况下怎么办呢?
我们可以这样实现:
1.通过JNI,java调用一个自己写的C++动态库(A.so);
2.通过自己的动态库(A.so)调用第三方的动态库(B.so);
这样可以间接实现java调用第三方的动态库(B.so).
java调用自己的动态库方法可以参考我以前文章,在此介绍一下自己的动态库调用第三方动态库的方法。
我们就在Linux环境下以lame(MP3压缩程序)为例,做个简单的介绍:
// lame_inittypedef lame_global_flags*(*FuncLameInit)();
// 说明:       &              &     &
//&&&&&&&&&&&&&&&&&&&&&&返回值          自定义的  参数
// id3tag_inittypedef void(*FuncId3tag)(lame_global_flags *);
// 说明:  &      &           &
//&&&&&&&&&&返回值   自定义的 &&&&&&&&&  参数
// lame_set_presettypedef int(*FuncSetPreset)(lame_global_flags *, int);
void test(){
&&& // open the libmp3lame.so
&&& void * handle = dlopen ("libmp3lame.so", RTLD_LAZY);
&&& // declare the functions
&&& FuncLameInit lame_init = (FuncLameInit)dlsym (handle, "lame_init");&&& FuncId3tag id3tag_init = (FuncId3tag)dlsym (handle, "id3tag_init");&&& FuncSetPreset lame_set_preset = (FuncSetPreset)dlsym(handle, "lame_set_preset");
&&& // using
&&& // set param&&& lame_global_flags* gfp = lame_init();&&& id3tag_init(gfp);&&& lame_set_preset(gfp, nCompressRate);
  // close
&&& dlclose(handle);
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:94464次
积分:1385
积分:1385
排名:千里之外
原创:43篇
转载:20篇
评论:23条
(1)(2)(1)(1)(5)(2)(1)(2)(1)(4)(1)(2)(4)(4)(3)(7)(3)(2)(8)(6)(2)(1)2346人阅读
intellij idea13(1)
android(35)
如下图所示,在modules名称上右键,open modules settings,选择左边的modules,再选择中间的modules名称下的Android,接着选择右边的stucture标签,native libs directory即为so文件所在路径(so文件不必在此路径的根目录)
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:127463次
积分:2178
积分:2178
排名:第13680名
原创:87篇
转载:18篇
评论:77条
(4)(1)(2)(3)(4)(1)(4)(1)(1)(6)(2)(1)(2)(3)(4)(4)(1)(6)(3)(2)(1)(1)(5)(9)(2)(5)(4)(1)(1)(5)(1)(16)匿名用户不能发表回复!|
每天回帖即可获得10分可用分!小技巧:
你还可以输入10000个字符
(Ctrl+Enter)
请遵守CSDN,不得违反国家法律法规。
转载文章请注明出自“CSDN(www.csdn.net)”。如是商业用途请联系原作者。

我要回帖

更多关于 mk文件引用aar so报错 的文章

 

随机推荐