Android告别JNI,使用JNA调用so库

778 阅读2分钟

常规的NDK开发绕不开JNI这个中间层,有没有其他的方式可以绕开JNI直接调用C的代码呢?答案是JNA

image.png

JNA是一个三方库,使用JNA就无需在写JNI相关代码,可以直接调用so库里面的代码,下边在Android项目中直接集成JNA:

第一步:下载对应cpu架构so库

image.png 按照项目需要下载对应的cpu架构的jar,然后解压,会得到统一命名的libjnidispatch.so文件,将这个文件放到libs或者jniLibs文件夹多对应的cpu架构目录下

image.png

第二步:添加项目依赖

image.png

api(group= "net.java.dev.jna", name= "jna", version= "5.13.0")

第三步:添加项目三方调用的so库

新建一个Module通过本地JNI编译so库的方式,生成一个so库作为调用库,也可以直接照ELF格式的so作为调用库
1.CMakeLists里面的配置:

image.png image.png

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文件:

image.png

将生成的文件拷贝到jniLibs目录下,并屏蔽CMakeLists里面的配置,注意:如果项目不是app而是一个module的话,需要这样做,是app目录下的话就不用拷贝了,本身app打包的时候就会将CMakeLists里面的配置编译成so并打包到apk里面,但是如果上边是一个单独的module的话就需要拷贝:

image.png

第四步:编写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)))

最后日志输出

image.png

本文参考:www.jianshu.com/p/fdd7777ca…

Demo: github.com/lycodeman/C…