JNI编程入门(一)

最近项目需要,先后进行了framework层和application的JNI,系统学习了JNI,在开发过程中踩了很多坑,那就赶紧把JNI系统总结一下,沉淀成自己的知识储备,那我们就开始吧。

我主要是参考《JNI编程指南》,非常有帮助,PDF放到这个链接中,有需要的可以参考。

另外也参考了关注的大神的JNI/NDK入门指南,他写的很系统,大家也可以去参考。

好了,先介绍下JNI学习大纲。

一、JNI编程入门

二、Android Studio中使用cmake开发JNI实战


下边就正式进入JNI世界了。

1.JNI概述

1.1 JNI是什么

JNI(Java Native Interface),主要是为了实现Java和C/C++代码之间相互调用,它相当于Java层和C/C++层的桥梁。如下图所示。

JNI编程入门(一)_第1张图片

通常我们都是在Java中调用C/C++的方法,这样可以实现Java层访问底层硬件或者直接调用现有的C++ 库。但在使用JNI的时候要非常细心,它的错误很难追踪和调试,它的局部引用和全局引用,稍微使用不当就会crash。

 1.2 JNI开发步骤

  • 在Java类中声明native方法;
  • 使用C /C++实现JNI方法(注:本JNI分类下,代码均使用C++);
  • 把实现的方法编译成动态库so,在Java类中使用静态代码块加载该so。

1.2.1 Java端代码

public class JniManager {
    private static final String TAG = "JniManager";
    //加载libjnimanager.so
    static {
        System.load("jnimanager");
    }
    //声明native方法
    private native String getStringNative();

    public static void main(String[] args) {
        JniManager jniManager = new JniManager();
        String strFromJni = jniManager.getStringNative();
        Log.i(TAG, strFromJni);
    }
}

1.2.2 C++端对应的代码

extern "C" JNIEXPORT jstring JNICALL
Java_com_jni_learn_JniManager_getStringNative(JNIEnv *env, jobject /*this*/) {
    std::string hello = "Hello From JNI, 2023";
    return env->NewStringUTF(hello.c_str());
}

本章节没有介绍使用javac把JniManager.java编译成class文件,再使用javah生成JNI的头文件,这是因为Android Studio已经可以全部做了。

1.3 c++端本地方法详解

1.3.1 c++端native方法名称介绍

  • 使用C++来写动态库时,方法前需要extern "C"来声明,这样就显式告诉C++编译器我们的接口/函数使用C语言的方式去编译和生成函数符号。
  • 如果使用C编写动态库,则不需要添加extern "C"。
  • JNIEXPORT和JNICALL是JNI中定义的两个宏,定义在

JNIEXPORT作用:动态库中定义的由JNIEXPORT修饰的函数才可以让其他程序调用。动态链接库在Window和Linux中分别是.dll文件和.so文件。该宏在预编译时会进行相应的替换。

JNICALL作用:

  • Windows JNICALL : JNICALL 被定义为 __stdcall , __stdcall 是一种函数调用参数的约定,在 Windows 中调用函数时 , 该函数的参数是以 栈 的形式保存的 , 栈中元素是后进先出的 , __stdcall 表示参数是从右到左保存的。
  • Linux JNICALL:Linux系统中JNICALL没有定义,直接置空,因此Linux中是可以不用写JNICALL宏的。
  • native方法的名称必须是Java_全类名_方法名(JNIEnv *env, jobject /*thiz*/)

1.3.2 c++端native方法参数介绍

  • JNI方法的第一个参数是JNIEnv指针,它指向本地方法的一个函数表,函数表中的每一个成员都指向一个JNI函数,如下图所示:JNI编程入门(一)_第2张图片
  •  JNIEnv是提供JNI native()的基础环境,它是线程相关的,即只在当前线程中有效,不能讲JNIEnv从一个线程传递到另一个线程中。不同线程的JNIEnv是相互独立的。
  • JNI方法的第二个参数通常是jobject或者jclass。

jobject:表示实例引用,与java.lang.Object类和其子类对应。如果Java中声明的native方法是非静态方法时,则对应的参数是jobject,表示该方法是依赖对象实例的。

jclass:表示类引用,与java.lang.Class对应。如果Java中声明的native方法是金泰方法,则对应的参数是jclass,表示该方法是依赖类。

下一节介绍Android Studio中使用cmake开发JNI。

你可能感兴趣的:(JNI开发,Android,java,c++,android)