美文网首页Android JNIAndroid开发经验谈Android开发
ndk06_jni开发流程,JNIEnv,jni访问java变量

ndk06_jni开发流程,JNIEnv,jni访问java变量

作者: IT魔幻师 | 来源:发表于2017-09-14 11:08 被阅读73次

    一、JNI与NDK简介

    JNI(java native interface)
        jni是java虚拟机的一部分,他是伴随java虚拟机的存在而存在的,是java和C相互通信的接口。
    使用环境:
        java api 不能满足我们程序的需要的时候。
        算法计算,图像渲染 效率要求非常高的时候。
        当需要访问一些已有的本地库。
    
    NDK :
        工具的集合。帮助开发者快速开发C/C++动态库的工具
    
    静态库和动态库:
        都是函数库。
        静态库:.a  编译的时候就链接到代码中 
        动态库:.dll/.so  在程序运行的时候动态加载
    

    二、Visual Studio下JNI开发流程

    • 1.java中编写native方法

    • 2.javah 命令,生成.h文件(JniMain.h)

    • 3.复制.h头文件到cpp工程

    • 4.找到jdk中 jni.h 和jni_md.h 两个头文件引入到cpp工程下

    引入后记得将.h头文件里面的 #include <jni.h> 改成 #include "jni.h"

        /* DO NOT EDIT THIS FILE - it is machine generated */
        #include "jni.h"
        /* Header for class com_hubin_jnitext_JniMain */
        
        #ifndef _Included_com_hubin_jnitext_JniMain
        #define _Included_com_hubin_jnitext_JniMain
        #ifdef __cplusplus
        extern "C" {
        #endif
        
        JNIEXPORT jstring JNICALL java_JniMain_getStringFromC
        (JNIEnv *, jclass);
        
        #ifdef __cplusplus
        }
        #endif
        #endif
    
    • 5.实现.h头文件中的申明函数

        #include "stdafx.h"
        #include "JniMain.h"
        
        JNIEXPORT jstring JNICALL java_JniMain_getStringFromC
        (JNIEnv * env, jclass jclz){
            return (*env)->NewStringUTF(env, "C string");
        }
      
    • 6.生成一个dll动态库(window下是.dll,linux下是.so 都是动态链接库)

    1> 平台配置生成的x64

    2> 不使用预编译头

    3> 生成

    • 7.在java中加载动态库

        static{
            System.loadLibrary("JniDemo");
        }
      

    三、JNIEnv 是什么

    在C里面:
    JNIEnv是一个结构体指针的别名,就是一个java运行环境,可以通过JNIEnv调用java 中的代码;env 是一个二级指针。

    在C++里面:
    JNIEnv 是结构体的别名 ;env 是一级指针

    原理如下:

        typedef struct JNINativeInterface_ * JNIEnv;
        
        struct JNINativeInterface_ {
            char * (* getString)(JNIEnv *, char);
        };
        
        
        char * getchar(JNIEnv * env, char c) {
            return "";
        }
        
        int main() {
            struct JNINativeInterface_ struct_JNI;
            struct_JNI.getString = getchar;
        
            JNIEnv en;
            en = &struct_JNI;
        
            JNIEnv * env = &en;
            (*env)->getString();
        }
    

    静态native方法和非静态native方法的区别

    // 静态方法 jclass
    JNIEXPORT jstring JNICALL Java_JniMain_getStringFromC
    (JNIEnv * env, jclass jclz) {
        return (*env)->NewStringUTF(env, "C string");
    }
    
    // 非静态方法 jobject
    JNIEXPORT jstring JNICALL Java_JniMain_getStringFromC2
    (JNIEnv * env, jobject jobj) {
        return (*env)->NewStringUTF(env, "C string2");
    }
    

    JNI基本数据类型对应关系:

    java —---—  JNI 
    boolean    jboolean 
    byte       jbyte;    
    char       jchar;    
    short      jshort;   
    int        jint;     
    long       jlong;    
    float      jfloat;   
    double     jdouble; 
    
    引用类型:
    String      jstring
    Object      jobject
    
    基本数据类型数组:
    //type[]  jTypeArray;
    byte[]    jByteArray;
    
    引用类型数组
    Object[](String[])  jobjectArray;
    Object[]()  jobjectArray;
    

    四、访问java中的变量

    • 1.java中不同数据类型在jni中对应的签名
    • 2.访问非静态域(C修改java中的非静态变量)

    1>java中定义string 和非静态的native方法准备修改string的值

    public String key = "key";
    public native String accessField();
    

    2>JNI方法如下

    JNIEXPORT jstring JNICALL Java_JniMain_accessField(JNIEnv * env, jobject jobj) {
        
        //1.获取jclasss
        jclass jclz = (*env)->GetObjectClass(env,jobj);
            
        //2.fieldId  key:属性名称, Ljava/lang/String:属性签名
        jfieldID fid = (*env)->GetFieldID(env,jclz,"key","Ljava/lang/String;");
                
        //3.得到key 对应的值
        //GetXXXField 因为String 是引用类型 所以使用GetObjectField
        jstring jstr = (*env)->GetObjectField(env,jobj,fid);
        
        //4.将jni的string 转换成C的char
        char * c_str = (*env)->GetStringUTFChars(env,jstr,NULL);
        
        //5.生成新的字符串 hubin key
        char text[30] = "hubin";
        stract(text,c_str);
        
        
        //6.C->jni
        jstring new_str = (*env)->NewStringUTF(env,text);
        
        //7.使用set方法
        (env)-SetObjectField(env,jobj,fid,new_str);
        
        //释放
        (*env)->ReleaseStringChars(env,new_str,c_str);
    
        return new_str;
    
    }
    
    • 3.访问非静态域(C修改java中的静态变量)

    1> java中定义int类型的静态变量 count,定义native方法准备修改int 的值

        public static int count = 9;
        public native void accessStaticField();
    

    2>JNI方法如下

        //访问静态域还是使用jobject的参数 范围静态函数才是使用jclass的参数
        JNIEXPORT void JNICALL Java_JniMain_accessStaticField(JNIEnv * env, jobject jobj) {
        
            //1.获取jclasss
            jclass jclz = (*env)->GetObjectClass(env,jobj);
                        
            //2.得到fieldId  count:属性名称, I:属性签名
            jfieldID fid = (*env)->GetFieldID(env,jclz,"count","I");
            
            jint count = (*env)->GetStaticIntField(env,jclz,fid);
            
            //int 不需要转换可以直接使用
            count++;
            
            (env)-SetStaticIntField(env,jclass,fid,count);
            
        }
    

    五、更多资料查询

    • 1.JNI Specification.CHM
    • 2.JNI 简介与实现.pdf
    • 3.JNI编程指南.pdf
    • 4.JNI程序员指南与规范.pdf

    相关文章

      网友评论

        本文标题:ndk06_jni开发流程,JNIEnv,jni访问java变量

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