«

Android中JNI的基本使用(只试用于NDK-r8版本以上,不支持之前版本)

时间:2024-3-2 18:19     作者:韩俊     分类: Android


Android中JNI的基本使用

android中jni是为了能够用java代码调用C/C++代码从而提升程序运行的效率的一种机制。所以当程序对运行效率要求比较高的时候需要用到jni,比如游戏、绘图和一些算法等。下面我来介绍一下JNI的基本使用。而这个使用是针对于NDK-r8版本以上的,之前版本是不支持的。

第一步,首先下载一个ndk,放到一个没有空格的目录下,比如D:android-ndk-r10e(我下载的是10版本的ndk)。然后把这个路径添加到环境变量里面(这个不会的自己百度吧,同时也鄙视一下,做android都不会配置环境变量真的不应该)。当配置好环境变量以后,在cmd中输入ndk-build出现如下情况,这说明配置好了。

第二步,用eclipse新建一个android项目,再新建一个load类(名字随便命名),类里面首先写一个静态代码库块,用来加载so库的。

<span style="font-size:18px;font-weight: normal;">static {
    // 加载库文件
    System.loadLibrary("jni_test");
    }
</span>

loadLibrary方法里面的参数就是so库的名字。要注意的是当编译完C/C++代码之后会生成一个libjni_test(libxxx.so)的文件,填写这个参数的时候一定要把lib这三个字母去掉,要不然会加载不到so库。写完这个静态代码块之后就写你要调用的C/C++方法了。方法必须加native关键字。

<span style="font-size:18px;font-weight: normal;"><span style="white-space:pre"> </span>public native int addJNI(int first, int second);

public native int subtractJNI(int first, int second);

public native int rideJNI(int first, int second);

public native int divideJNI(int first, int second);

</span>

我这里就写了加减乘除四个方法,同时这也简单(本人C/C++基本忘记了,复杂点的写不出来,只能写这个)。到这里这个类就写完了。

第三步,打开cmd,进入到刚才新建的安卓项目的bin目录里面的classes文件夹下,根据包名找到刚才新建的load类的字节文件,然后通过javah命令来生成C/C++头文件,,生成成功之后会在classes文件夹下有一个.h文件。这个.h文件的名字比较长,可以把这个名字的包名去掉,当然也可以改成其他的名字,只要编译的时候能对上名字就行了。

打开这个文件可以看到有四个函数(C++里面叫函数,java里面叫方法),方法的名字都是Java_包名_方法名,把包名的.用_替代了

<span style="font-size:18px;font-weight: normal;">/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_example_JniLoad_JniLoad */

#ifndef _Included_com_example_JniLoad_JniLoad
#define _Included_com_example_JniLoad_JniLoad
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     com_example_JniLoad_JniLoad
 * Method:    addJNI
 * Signature: (II)I
 */
JNIEXPORT jint JNICALL Java_com_example_JniLoad_JniLoad_addJNI
  (JNIEnv *, jobject, jint, jint);

/*
 * Class:     com_example_JniLoad_JniLoad
 * Method:    subtractJNI
 * Signature: (II)I
 */
JNIEXPORT jint JNICALL Java_com_example_JniLoad_JniLoad_subtractJNI
  (JNIEnv *, jobject, jint, jint);

/*
 * Class:     com_example_JniLoad_JniLoad
 * Method:    rideJNI
 * Signature: (II)I
 */
JNIEXPORT jint JNICALL Java_com_example_JniLoad_JniLoad_rideJNI
  (JNIEnv *, jobject, jint, jint);

/*
 * Class:     com_example_JniLoad_JniLoad
 * Method:    divideJNI
 * Signature: (II)I
 */
JNIEXPORT jint JNICALL Java_com_example_JniLoad_JniLoad_divideJNI
  (JNIEnv *, jobject, jint, jint);

#ifdef __cplusplus
}
#endif
#endif
</span>

而且函数的参数只有类型,没有具体的参数,这是没有错的,具体为什么是这样本人还没研究过,我记得C/C++也不是这样写头文件(错了勿怪)。再看返回类型,类型里面都会加上一个j,貌似是代表java的意思,比如jint,jstring。另外还有两个大写的JNIEXPORT和JNICALL,具体什么意思没研究过,这里只是讲基本用法而已,不深究这个。从意思上来看是jni输入和jni调用的意思。

第四步,新建一个一个.c或者.cpp文件,该文件是写C代码或者C++代码的。名字要跟那个.h的头文件一样,这是C/C++的规定。头文件只定义函数名,在.c或者.cpp文件里面写函数的实现。

<span style="font-size:18px;font-weight: normal;">#include <jni.h>
#include<stdio.h>
#include "JniLoad.h"

JNIEXPORT jint JNICALL Java_com_oyf_jnitest_jni_JniLoad_addJNI
  (JNIEnv *env, jobject obj, jint first, jint second){
    return first+second;
}

JNIEXPORT jint JNICALL Java_com_oyf_jnitest_jni_JniLoad_subtractJNI
  (JNIEnv *env, jobject obj, jint first, jint second){
    return first-second;
}

JNIEXPORT jint JNICALL Java_com_oyf_jnitest_jni_JniLoad_rideJNI
  (JNIEnv *env, jobject obj, jint first, jint second){
    return first*second;
}

JNIEXPORT jint JNICALL Java_com_oyf_jnitest_jni_JniLoad_divideJNI
  (JNIEnv *env, jobject obj, jint first, jint second){
    return first/second;
}
</span>

这里可以直接把.h头文件里面的四个方法复制到.c或者.cpp文件里,再给每个函数补全参数并添加函数体,毕竟这个函数名太长了,万一写错了就不好了。函数体里面用C/C++语法写函数的实现过程。

第五步,当写好.c或者.cpp文件后,在eclipse的项目的跟目录下新建一个jni文件,把头文件和.c或者.cpp文件放到这个文件夹下,再新建一个Android.mk文件,里面编写的内容如下:

<span style="font-size:18px;font-weight: normal;">LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE    := jni_test
LOCAL_SRC_FILES := JniLoad.c 

LOCAL_LDLIBS    := -llog

include $(BUILD_SHARED_LIBRARY)
</span>

第一、第二和最后一个基本不改的,也不建议改。第三个就生成so库放的文件夹,第四个就是C/C++的源代码,第五个就是日志文件了。这里要说一下的是源代码后面必须要带一个反斜杠,要不然编译会出错。且如果有多个源代码要编译则用空格隔开

第六步,新建一个txt文件,然后里面写ndk-build,再把该文件的后缀改成bat,并放到该项目的根目录下

双击该文件,然后就会自动编译C/C++代码了。不管编译成功还是失败都会生成一个obj的文件夹,如果成功了可以在里面找到so库,如果没成功则里面没有so库。成功的同时也会在libs里面添加so库。

ok!好了,到这里我们就得到我们要的so库了,然后就可以通过load类来调用那些native方法了。

至此,android里面的JNI的基本使用就完成了。

本来想把源代码上传的,但是不知道怎么上传文件,只有上传图片的

标签: android

热门推荐