zoukankan      html  css  js  c++  java
  • android windows 上JNI编程

    昨天学习windows上的JNI编程,JNI说白了就是java和c语言的一个互相沟通的桥梁。java能够调用JNI来完毕调用C语言实现的方法。

    JNI的全称是(Java native interface),事实上在编程重你仅仅须要将与java交互的函数写出来。其它的C语言内部调用的就能够直接使用C语言相关语法了。闲话少说,開始正题吧。

    要想在windroid或者是linux上使用JNI必须要下载NDK的而且指定路径,在windows我们还须要安装一个sygwin,这里我就不再说如何安装cygwin了。在你安装好的cygwin目录中找到一个etc的目录,在这个文件里找到一个profile文件,改动当中的Path后加上:(ndk的路径)。在我理解ndk就是构建出了一个重pc到android的一个交叉编译环境。当然它里面还有非常多我不知道的。还有待探索。然后我们就能够開始使用了。当然你要是用eclipse写C/C++还须要安装cdt插件。安装过后就能够使用eclipse编写c/c++的代码了。
    以下我们来看看代码如何编写吧,首先我们在androidproject中创建一个jni的目录。在jni的目录中创建c语言的源文件,在android中穿件一个类,类中能够使用native标识创建函数比如以下:
    public class DataProvider {
      //带參数的c语言调用java语言
     public int add2( int x, int y){
      return x + y;
     }
      //无參数的函数C语言调用java语言
     public void show(){
      System.out.println( "我被调用了啊" );
     }
      //无參数的静态函数C语言调用java语言
     public static void show2(){
      System.out.println( "我又被调用了啊" );
     }
     
    //将函数使用native标识,能够自己主动生成对应的函数
     public native int add(int x, int y);
     public native int sayHello( String hello );
     public native int[] array(int[] arr);
     
     public native int callbackadd2();
     public native void callbackshow();
     public native static void callbackshow2();
     public native void callbackshow3();
    }

    将这个类写好了就能够使用javah (类的全类名)。 全类名是指包名+类名,比如com.example.testjni.DataProvider。这样就能够生成一个c语言中使用的头文件比如:
    /* DO NOT EDIT THIS FILE - it is machine generated */
    #include <jni.h>
    /* Header for class com_example_testjni_DataProvider */
    #ifndef _Included_com_example_testjni_DataProvider
    #define _Included_com_example_testjni_DataProvider
    #ifdef __cplusplus
    extern "C" {
    #endif
    /*
     * Class:     com_example_testjni_DataProvider
     * Method:    add
     * Signature: (II)I
     */
    JNIEXPORT jint JNICALL Java_com_example_testjni_DataProvider_add
      (JNIEnv *, jobject, jint, jint);
    /*
     * Class:     com_example_testjni_DataProvider
     * Method:    sayHello
     * Signature: (Ljava/lang/String;)I
     */
    JNIEXPORT jint JNICALL Java_com_example_testjni_DataProvider_sayHello
      (JNIEnv *, jobject, jstring);
    /*
     * Class:     com_example_testjni_DataProvider
     * Method:    array
     * Signature: ([I)[I
     */
    JNIEXPORT jintArray JNICALL Java_com_example_testjni_DataProvider_array
      (JNIEnv *, jobject, jintArray);
    /*
     * Class:     com_example_testjni_DataProvider
     * Method:    callbackadd2
     * Signature: ()I
     */
    JNIEXPORT jint JNICALL Java_com_example_testjni_DataProvider_callbackadd2
      (JNIEnv *, jobject);
    /*
     * Class:     com_example_testjni_DataProvider
     * Method:    callbackshow
     * Signature: ()V
     */
    JNIEXPORT void JNICALL Java_com_example_testjni_DataProvider_callbackshow
      (JNIEnv *, jobject);
    /*
     * Class:     com_example_testjni_DataProvider
     * Method:    callbackshow2
     * Signature: ()V
     */
    JNIEXPORT void JNICALL Java_com_example_testjni_DataProvider_callbackshow2
      (JNIEnv *env, jclass);
    /*
     * Class:     com_example_testjni_DataProvider
     * Method:    callbackshow3
     * Signature: ()V
     */
    JNIEXPORT void JNICALL Java_com_example_testjni_DataProvider_callbackshow3
      (JNIEnv *, jobject);
    #ifdef __cplusplus
    }
    #endif
    #endif
    这些都是使用javah后自己主动生成的。下一步我将该在c语言中是实现这些函数了,在此之前还须要创建一个mk文件。这个文件就是makefile,C语言在编译成库的情况下就能够读取makefile来编译。

    mk文件:
       LOCAL_PATH := $(call my-dir)
       include $(CLEAR_VARS)
       
       #相应的c语言的函数库
       LOCAL_MODULE    := hello
       
       #相应c代码的文件
       LOCAL_SRC_FILES := hello.c functions.c
       
       LOCAL_LDLIBS := -llog//使用本地库
       include $(BUILD_SHARED_LIBRARY)


    #include <stdio.h>
    #include "com_example_testjni_DataProvider.h" //引用头文件
    #include <android/log.h> //打印的日志
    const char *TAG = "clog";
    #define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, TAG, __VA_ARGS__ );
    #define LOGI(...) __android_log_print(ANDROID_LOG_INFO, TAG, __VA_ARGS__ );
    //使用log头文件里的函数打印日志到eclipse中的logcat,在这里须要在mk文件里加入库引用,LOCAL_LDLIBS += -llog
    JNIEXPORT jint JNICALL Java_com_example_testjni_DataProvider_add
      (JNIEnv *env, jobject o, jint x, jint y)
    {
     LOGI("%d ", x );
     LOGD("%d ", y );
     return x + y; //直接返回就能够
    }
    //int print(jintArray localarray, int i);
    int print( int* localarray, int i )
    {
     LOGD( "array = %d ", *(localarray+i));
     return 0;
    }//寻常的c语言代码,能够直接调用
    /*
     * Class:     com_example_testjni_DataProvider
     * Method:    sayHello
     * Signature: (Ljava/lang/String;)I
     */
    JNIEXPORT jint JNICALL Java_com_example_testjni_DataProvider_sayHello
      (JNIEnv *env, jobject o, jstring hello)
    {
    }
    /*
     * Class:     com_example_testjni_DataProvider
     * Method:    array
     * Signature: ([I)[I
     */
    JNIEXPORT jintArray JNICALL Java_com_example_testjni_DataProvider_array
      (JNIEnv *env, jobject obj, jintArray array )//传的是一个java中int型数组,java调用c语言
    {
     //获得数组长度
     int length = (*env)->GetArrayLength(env, array);
     int i;
     jint* localarray = (*env)->GetIntArrayElements(env, array, 0);
     for( i = 0; i < length; i++ ){
      *(localarray+i) += 5;
      print( localarray, i );
     }
     return array;
    }
    /*
     * Class:     com_example_testjni_DataProvider
     * Method:    callbackadd2
     * Signature: ()I
     */
    JNIEXPORT jint JNICALL Java_com_example_testjni_DataProvider_callbackadd2
      (JNIEnv *env, jobject obj)
    {
     jclass clazz = (*env)->FindClass(env, "com/example/testjni/DataProvider");
     jmethodID mid = (*env)->GetMethodID(env, clazz, "add2", "(II)I");
     return (*env)->CallIntMethod(env, obj, mid, 3, 5);
    }
    /*
     * Class:     com_example_testjni_DataProvider
     * Method:    callbackshow
     * Signature: ()V
     */
    JNIEXPORT void JNICALL Java_com_example_testjni_DataProvider_callbackshow
      (JNIEnv *env, jobject obj)
    {
     jclass clazz = (*env)->FindClass(env, "com/example/testjni/DataProvider");
     jmethodID mid = (*env)->GetMethodID(env, clazz, "show", "()V");//
     (*env)->CallVoidMethod(env, obj, mid);
    }
    /*
     * Class:     com_example_testjni_DataProvider
     * Method:    callbackshow2
     * Signature: ()V
     */
    JNIEXPORT void JNICALL Java_com_example_testjni_DataProvider_callbackshow2
      (JNIEnv *env, jclass jc)
    {
     jmethodID mid = (*env)->GetStaticMethodID(env, jc, "show2", "()V");
     jobject obj =  (*env)->CallStaticObjectMethod(env, jc, mid);
     (*env)->CallVoidMethod(env, obj, mid);
    }
    /*
     * Class:     com_example_testjni_DataProvider
     * Method:    callbackshow3
     * Signature: ()V
     */
    JNIEXPORT void JNICALL Java_com_example_testjni_DataProvider_callbackshow3
      (JNIEnv *env, jobject obj)
    {
     jclass clazz = (*env)->FindClass(env, "com/example/testjni/DataProvider");
     jmethodID mid = (*env)->GetStaticMethodID(env, clazz, "show2", "()V");
     (*env)->CallVoidMethod(env, obj, mid);
    }
    java调用C语言将java传过来的值,使用jni的方法进行处理,然后使用,返回,c语言调用java须要在C语言代码中进行映射,比如:
    JNIEXPORT void JNICALL Java_com_example_testjni_DataProvider_callbackshow3
      (JNIEnv *env, jobject obj)
    {
     jclass clazz = (*env)->FindClass(env, "com/example/testjni/DataProvider");//得到类的字节码
     jmethodID mid = (*env)->GetStaticMethodID(env, clazz, "show2", "()V");//得到函数的id
     (*env)->CallVoidMethod(env, obj, mid);//运行函数
    }
    执行函数有不同的call函数。比如返回值是int是CallIntMethod(env, obj, mid, 3, 5);空类型是CallVoidMethod(env, obj, mid);后面的()V是函数签名。代表是返回值是void型,无參的函数。

    (II)I返回值是int型參数是两个int值得函数。c语言编写后要在project的src文件夹下执行ndk-bulid命令就能够生成一个c语言库,在eclipseproject文件夹中也有显示。

    在每次编译之前须要删除obj目录,以清除缓存。

    jni对于一些能够非常大的提高java代码的隐秘性,并且使用c语言开发jni程序能够提高效率。
  • 相关阅读:
    C#委托本质探索 四、方法变量内、外混合调用
    calibredrv 对layer做操作
    2021年11月工作笔记
    2022年1月工作资料
    2021年12月工作资料
    MySQL 5.7 MGR原理及部署
    在虚拟机上安装redis集群,redis使用版本为4.0.5,本机通过命令客户端可以连接访问,外部主机一直访问不了
    mongoDB中的的常用语法
    使用Nginx做图片服务器时候,配置之后图片访问一直是 404问题解决
    jquery.cookie() 方法的使用(读取、写入、删除)
  • 原文地址:https://www.cnblogs.com/bhlsheji/p/5111991.html
Copyright © 2011-2022 走看看