Android Studio 如何使用JNI

(一) 什么是JNI?

JNI,全称为Java Native Interface,即Java本地接口,JNI是Java调用Native 语言的一种特性。通过JNI可以使得Java与C/C++机型交互。即可以在Java代码中调用C/C++等语言的代码或者在C/C++代码中调用Java代码。由于JNI是JVM规范的一部分,因此可以将我们写的JNI的程序在任何实现了JNI规范的Java虚拟机中运行。同时,这个特性使我们可以复用以前用C/C++写的大量代码JNI是一种在Java虚拟机机制下的执行代码的标准机制。代码被编写成汇编程序或者C/C++程序,并组装为动态库。也就允许非静态绑定用法。这提供了一个在Java平台上调用C/C++的一种途径,反之亦然。

PS:
开发JNI程序会受到系统环境限制,因为用C/C++ 语言写出来的代码或模块,编译过程当中要依赖当前操作系统环境所提供的一些库函数,并和本地库链接在一起。而且编译后生成的二进制代码只能在本地操作系统环境下运行,因为不同的操作系统环境,有自己的本地库和CPU指令集,而且各个平台对标准C/C++的规范和标准库函数实现方式也有所区别。这就造成了各个平台使用JNI接口的Java程序,不再像以前那样自由的跨平台。如果要实现跨平台, 就必须将本地代码在不同的操作系统平台下编译出相应的动态库。

(二) 为什么需要JNI

因为在实际需求中,需要Java代码与C/C++代码进行交互,通过JNI可以实现Java代码与C/C++代码的交互


(三) JNI的优势

与其它类似接口Microsoft的原始本地接口等相比,JNI的主要竞争优势在于:它在设计之初就确保了二进制的兼容性,JNI编写的应用程序兼容性以及其再某些具体平台上的Java虚拟机兼容性(当谈及JNI时,这里并不特比针对Davik虚拟机,JNI适用于所有JVM虚拟机)。这就是为什么C/C++编译后的代码无论在任何平台上都能执行。不过,一些早期版本并不支持二进制兼容。二进制兼容性是一种程序兼容性类型,允许一个程序在不改变其可执行文件的条件下在不同的编译环境中工作。


(四) JNI的命名规则

JNIExport jstring JNICALL Java_com_example_hellojni_MainActivity_stringFromJNI( JNIEnv* env,jobject thiz )

jstring 是返回值类型
Java_com_example_hellojni 是包名
MainActivity 是类名
stringFromJNI 是方法名

其中JNIExport和JNICALL是不固定保留的关键字不要修改


(五) 如何实现JNI

1.在local.properties文件中配置NDK的路径
例如:ndk.dir=/work2/Studio/studio-sdk/ndk/22.0.7026061

2.在GpioTest/app/src/main/java/com/actions/gpiotest/目录下新建JniTest.java文件,声明静态方法,如下:
public class JniTest {

    static {
        System.loadLibrary("gpio-control"); //导入将要生成的库文件
    }

    public static native int owlGpioInit();
    public static native int owlIoctrl(int which, int status);
    public static native int owlGpioCleanup();
}

3.在main目录下新建jni文件夹,在jni目录下新建.c文件实现JniTest.java文件中声明的方法


4.在app目录(或其他目录)下新建CMakeLists.txt文件并按语法编写。

5.具体Module中的build.gradle中先指定这个文件的位置
在android {}中加入以下内容:
externalNativeBuild {
    cmake {
        path "src/main/cpp/CMakeLists.txt" //CMakeLists.txt文件的存放路径
    }

}
ps:如果CMakeLists.txt放在app目录下,路径只需这样写:path "CMakeLists.txt"

6.完成以上步骤后,正常编译运行即可。

CMakeLists.txt文件语法如下:
cmake_minimum_required(VERSION 3.4.1) #指定编译器版本
set(PROJECT_NAME xxx)
     
project (${PROJECT_NAME})
     
add_library( # Sets the name of the library.
        ${PROJECT_NAME}

        # Sets the library as a shared library.
        SHARED

        # Provides a relative path to your source file(s).
        xxx.c ) #路径从src/开始写
     

find_library( # Sets the name of the path variable.
        log-lib

        # Specifies the name of the NDK library that
        # you want CMake to locate.
        log)
     
target_link_libraries( # Specifies the target library.
        ${PROJECT_NAME}
        # Links the target library to the log library
        # included in the NDK.
        ${log-lib})

PS:请参考附件的Demo(App控制底层GPIO的高低电平)

猜你喜欢

转载自blog.csdn.net/Chris_1994/article/details/134335371