JNI浅尝

作者: 爱吃豆腐面 | 来源:发表于2019-09-27 18:09 被阅读0次

    什么是JNI

    百度百科:https://baike.baidu.com/item/JNI/9412164
    当然,里面也有关于JNI的实现,懂的看官就不必往下看啦,大致上差不多。

    开发环境

    • Mac电脑
    • IntelliJ IDEA(写java代码)
    • Clion(写C/C++代码)
    • 配置好java运行环境

    开始写代码

    第一步,在IDEA里创建一个java工程,创建一个java类

    Register.java

    public class Register {
        public native void staticReg();
    
        public static void main(String[] args) {
            Register register = new Register();
            register.staticReg();
        }
    }
    

    说明:public native void staticReg();native修饰的方法就是C方法,相当于这里定义一个接口,让C代码去实现。
    为了让C代码可以知道这个接口,我们需要进行以下两步操作:

    1. 使用javac Register.java命令,把java类编译成.class文件

    注意:需要在Register.java文件的目录下执行该命令。
    生成的.class文件内容如下:
    Register.class

    //
    // Source code recreated from a .class file by IntelliJ IDEA
    // (powered by Fernflower decompiler)
    //
    
    public class Register {
        public Register() {
        }
    
        public native void staticReg();
    
        public static void main(String[] var0) {
            Register var1 = new Register();
            var1.staticReg();
        }
    
    

    看起来跟java代码差不多

    2. 使用javah Register命令,根据刚才生成的.class文件,生成一个.h头文件

    注意:javah 命令后面的Register是不带后缀的
    Register.h

    /* DO NOT EDIT THIS FILE - it is machine generated */
    #include <jni.h>
    /* Header for class Register */
    
    #ifndef _Included_Register
    #define _Included_Register
    #ifdef __cplusplus
    extern "C" {
    #endif
    /*
     * Class:     Register
     * Method:    staticReg
     * Signature: ()Ljava/lang/String;
     */
    JNIEXPORT void JNICALL Java_Register_staticReg
      (JNIEnv *, jobject);
    
    #ifdef __cplusplus
    }
    #endif
    #endif
    

    可以看到,我们从最开始的java文件,生成了最终的.h头文件。了解C语言的同学大概已经猜到了,这个头文件里定义了一个java文件里public native void staticReg()对应的方法Java_Register_staticReg (JNIEnv *, jobject)

    既然已经有了C的头文件,我们是不是在我们的C的library项目里引用这个头文件,并实现其中的方法,就可以生成一个动态库了呢?
    说干就干 ~

    第二步,在Clion里创建一个C++ Library工程register

    创建library工程.png

    创建完成之后的目录结构是这样子的

    C++Library目录结构.png
    可以看到,创建的时候会默认生成一个library.h和一个library.cpp文件。这里我们是要自己引入.h头文件、再实现这个头文件的方法,所以可以删掉这个这两个文件。

    现在我们找到上面生成的.h头文件,复制粘贴到libaray目录下,
    然后修改CMakeLists.txt文件

    配置.h文件.png

    切换到Register.h文件,发现有报错


    找不到依赖的头文件.png

    那么这个依赖在哪里呢?我们需要找到依赖的.h文件,复制到libaray项目下面。
    这个jni.h在jdk里面/Library/Java/JavaVirtualMachines/jdk1.8.0_162.jdk/Contents/Home/include/jni.h
    复制完之后,看到还报错,需要把尖括号改成双引号

    .h引用方式不对,需要改成双引号引用.png 未识别JNIEXPORT.png

    这里需要再引入一个头文件jni_md.hjni.h里引用了这个),目录/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/System/Library/Frameworks/JavaVM.framework/Versions/A/Headers/jni_md.h(看官可自行搜索)

    jni_md.h,jni.h都复制粘贴之后,可以看到Register.h文件就已经不报错了。

    然后创建一个Register.cpp文件,并引用Register.h头文件,实现里面的方法
    Register.cpp

    //
    // Created by wh on 2019/9/27.
    //
    #include "Register.h" //引用头文件
    
    /*
     * Class:     Register
     * Method:    staticReg
     * Signature: ()Ljava/lang/String;
     */
    JNIEXPORT void JNICALL Java_Register_staticReg
            (JNIEnv *env, jobject obj) {
        printf("this is my first jni program"); //实现头文件中定义的方法,打印一个字符串
    }
    

    到这里,代码基本上写完了。

    现在我们把Libaray工程build一下,可以看到,生成了一个libregister.dylib文件:

    动态库文件.png

    这个文件就是生成的动态库了。

    引用动态库

    我们复制libregister.dylib的绝对路径,切回到java工程,修改Register.java

    public class Register {
        //静态加载库文件
        static {
            System.load("/Users/wh/CLionProjects/register/cmake-build-debug/libregister.dylib");
        }
    
        public native void staticReg();
    
        public static void main(String[] args) {
            Register register = new Register();
            register.staticReg();
        }
    }
    

    运行一下main函数:


    大功告成.png

    问题

    1. Android开发平时用到的动态库不是.so结尾的吗,.dylib是什么鬼?

    2. 什么是静态注册?什么是动态注册?

    3. C/C++中如何调用java代码?

    4. jni在编写和使用的过程中,有什么需要特别注意的地方吗?

    待续...

    1. 本人是个初学者,本篇文章记录了自已编写代码的过程以及思路,可能有些模棱两可的情况,欢迎批评指正。
    2. 上面只说的都只是JNI的静态注册,计划后续更新动态注册代码编写过程。

    相关文章

      网友评论

          本文标题:JNI浅尝

          本文链接:https://www.haomeiwen.com/subject/mqhauctx.html