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程序能够提高效率。
  • 相关阅读:
    docker 部署aps.net MVC到windows容器
    docker 搭建私有仓库 harbor
    解决关于:Oracle数据库 插入数据中文乱码 显示问号???
    ionic cordova build android error: commamd failed with exit code eacces
    cordova build android Command failed with exit code EACCES
    Xcode 10 iOS12 "A valid provisioning profile for this executable was not found
    使用remix发布部署 发币 智能合约
    区块链: 编译发布智能合约
    mac 下常用命令备忘录
    JQuery fullCalendar 时间差 排序获取距当前最近的时间。
  • 原文地址:https://www.cnblogs.com/bhlsheji/p/5111991.html
Copyright © 2011-2022 走看看