常规的NDK开发绕不开JNI这个中间层,有没有其他的方式可以绕开JNI直接调用C的代码呢?答案是JNA
JNA是一个三方库,使用JNA就无需在写JNI相关代码,可以直接调用so库里面的代码,下边在Android项目中直接集成JNA:
第一步:下载对应cpu架构so库
按照项目需要下载对应的cpu架构的jar,然后解压,会得到统一命名的libjnidispatch.so文件,将这个文件放到libs或者jniLibs文件夹多对应的cpu架构目录下
第二步:添加项目依赖
api(group= "net.java.dev.jna", name= "jna", version= "5.13.0")
第三步:添加项目三方调用的so库
新建一个Module通过本地JNI编译so库的方式,生成一个so库作为调用库,也可以直接照ELF格式的so作为调用库
1.CMakeLists里面的配置:
add_library(test SHARED
# List C/C++ source files with relative paths to this CMakeLists.txt.
test.cpp
test.h)
target_link_libraries(test
# List libraries link to the target library
android
log)
2.编写cpp和h文件:
test.cpp文件:
#include <math.h>
#include "test.h"
#include <string.h>
/**
* int
*/
int add (int x,int y){
return x+y;
}
/**
* int * 类型
*/
int getAge(int *age){
*age=18;
return 0;
}
/**
* char * 类型
*/
int getName(char *name,char * s) {
if(name==NULL||s==NULL){
return -1;
}
int result=strcmp(name, "大包子");
char dabaozi[40] ="大包子最帅!";
char other [40] = "其他人一般帅。。。";
if (result == 0) {
memcpy(s, dabaozi, strlen(dabaozi));
}
else {
memcpy(s, other, strlen(other));
}
return 0;
}
/**
* 结构体类型
*/
int getStructInfo(struct _Person * person){
person->age=18;
char name[10] ="大包子";
memcpy(person->name, name, strlen(name));
return 0;
}
test.h文件
#ifndef TEST_H_
#define TEST_H_
#ifdef __cplusplus
extern "C" {
#endif
struct _Person
{
int age;
char name[11];
char type[20];
}Person;
int add(int x,int y);
int getAge(int *age);
int getName(char *name,char * s);
int getStructInfo(struct _Person *Person);
#ifdef __cplusplus
};
#endif
#endif /* TEST_H_ */
然后build会生成对应的so文件:
将生成的文件拷贝到jniLibs目录下,并屏蔽CMakeLists里面的配置,注意:如果项目不是app而是一个module的话,需要这样做,是app目录下的话就不用拷贝了,本身app打包的时候就会将CMakeLists里面的配置编译成so并打包到apk里面,但是如果上边是一个单独的module的话就需要拷贝:
第四步:编写JNA接口并调用
import com.sun.jna.Library;
import com.sun.jna.Native;
import com.sun.jna.Structure;
import java.nio.ByteBuffer;
import java.nio.IntBuffer;
import java.util.Arrays;
import java.util.List;
public interface TestI extends Library {
public static final String JNA_LIBRARY_NAME = "test";
public static final TestI INSTANCE = (TestI) Native.loadLibrary(TestI.JNA_LIBRARY_NAME, TestI.class);
public static class _Person extends Structure {
public int age;
public byte[] name = new byte[11];
public byte[] type = new byte[20];
public _Person() {
super();
}
@Override
protected List<String> getFieldOrder() {
return Arrays.asList("age", "name", "type");
}
public _Person(int age, byte name[], byte type[]) {
super();
this.age = age;
if ((name.length != this.name.length)){
throw new IllegalArgumentException("Wrong array size !");
}
this.name = name;
if ((type.length != this.type.length)){
throw new IllegalArgumentException("Wrong array size !");
}
this.type = type;
}
public static class ByReference extends _Person implements Structure.ByReference {
};
public static class ByValue extends _Person implements Structure.ByValue {
};
};
int add(int x, int y);
int getAge(IntBuffer age);
int getName(ByteBuffer name, ByteBuffer s);
int getStructInfo(_Person Person);
}
4.调用
Log.e("TAG", "jna add: " + TestI.INSTANCE.add(Random.nextInt(5), Random.nextInt(6)))
最后日志输出
本文参考:www.jianshu.com/p/fdd7777ca…
Demo: github.com/lycodeman/C…