eclipse下Jni开发步骤详细总结

    xiaoxiao2025-03-17  13

    前提:已经搭好ndk环境。

    步骤:

    1.在java中定义本地(native)方法

    2.在工程目录下新建一个jni文件夹(用来存放c/c++,android.mk,Application.mk等文件)

    3.在jni文件夹中新建一个c文件,并在c中实现步骤1中定义的方法

    4.在jni文件夹中新建一个Android.mk和Application.mk文件,并配置该文件的内容

    5.把C文件编译成库文件

    6.在java中加载库文件,调用步骤1中定义的本地(native)方法

    具体实现过程:

    1.在java中定义本地(native)方法

    public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } //定义本地方法,在c/c++下实现 public native String stringFromC(); } 2.在工程目录下新建一个jni文件夹(用来存放c/c++,android.mk,Application.mk等文件)

    右击项目-->New-->Folder,输入要新建的文件夹名称(Folder name):jni  --->. Finish 后的目录结构如下:

    3.在jni文件夹中新建一个c文件,并在c中实现步骤1中定义的方法

    击上一步中新建的文件夹:jni -->New-->File,输入要新建的文件名(File name)hello.c --->.Finish ,如图(Android.mk和Application.mk文件在步骤4中建立):

    (1)在hello.c文件中编写方法:

    #include <jni.h> #include <string.h> jstring Java_com_example_testjni2_MainActivity_stringFromC(JNIEnv* env, jobject thiz) { char* cstr = "Hello From CCCC!"; //把字符数组转为java的字符串,该方法在jni.h中定义

    //jstring     (*NewStringUTF)(JNIEnv*, const char*); return (*env)->NewStringUTF(env, cstr); } 该方法主要做了一件事:定义一个字符数组指针,把字符数组转化为java的字符串返回。其中, jstring Java_com_example_testjni2_MainActivity_stringFromC(JNIEnv* env,  jobject thiz) ,jstring是返回类型,表示java的string类型,Java_com_example_testjni2_MainActivity_stringFromC是实现步骤1中定义的stringFromC()方法,在这里的命名规则是:Java_包名_类名_方法名(JNIEnv* env,jobject thiz),JNIEnv是一个以线程相关的代表JNI环境的结构体,通过JNIEnv提供的JNI系统函数可以完成对java调用和操作object对象。JNIEnv在jni.h中是这样定义的

    从中可以看出jni.h头文件中对于***.c  &  ***.cpp采用不同的定义

    Java调用C和C++函数时的JNI使用区别: 在C的定义中,env是一个两级指针,而在C++的定义中,env是个一级指针,而且须将env作为第一个参数传给jni函数 对于***.c: 1.jclass test_class = (*env)->GetObjectClass(env, obj); 2.jfieldID id_num = (*env)->GetFieldID(env, test_class, "num", "I"); 对于 ***.cpp: 1.jclass test_class = env->GetObjectClass(obj);  2.jfieldID id_num = env->GetFieldID(test_class, "num", "I");

    4.在jni文件夹中新建一个Android.mk和Application.mk文件,并配置该文件的内容

    (1)重复步骤3中的新建文件方法,分别新建文件Android.mk、Application.mk(这两个Makefile文件是编译的时候使用)

    (2)在Android.mk文件中编写内容:

    ## 指定本路径 LOCAL_PATH := $(call my-dir) ## 清除之前定义的变量 include $(CLEAR_VARS) ## 指定编译的模块和源文件 ## 要生成的动态库名 LOCAL_MODULE := hello ## LOCAL_SRC_FILES := hello.c ## 打印logcat要指定的参数 LOCAL_LDLIBS :=-llog ## 生成链接库 include $(BUILD_SHARED_LIBRARY)

    (3)在Application.mk中编写如下内容:

    ##根据需要生成的目标设备来定

    APP_ABI :=all

    For example, to support hardware FPU instructions on ARMv7 based devices, use: APP_ABI := armeabi-v7a Or to support ARMv8 AArch64 instruction set, use: APP_ABI := arm64-v8a Or to support the IA-32 instruction set, use: APP_ABI := x86 Or to support the Intel64 instruction set (r1), use: APP_ABI := x86_64 Or to support the MIPS32 instruction set, use: APP_ABI := mips Or to support the MIPS64 instruction set (r6), use: APP_ABI := mips64 Or to support all at the same time, use: APP_ABI := armeabi armeabi-v7a x86 mips arm64-v8a x86_64 mips64 Or even better, since NDK r7, you can also use the special value 'all' which means "all ABIs supported by this NDK release": APP_ABI := all

    关于更多的Android.mk和Application.mk如何编写可参考NDK帮助文档,在android-ndk-r10e\docs目录下。

    5.把c/c++编译成库文件

    这里介绍两个方法:

    方法(1):

    右击项目--> Properties-->Builders-->New... -->Program

    Finish确定。这样就配置好了编译动态库的环境,当jni目录的内容有变并保存时系统就会自动编译生成相应的库文件:

    这里生成的动态库文件和Android.mk指定生成的库文件名不同,Android.mk指定生成的库文件名要“去头插尾”,即前面去掉lib,后面去掉.so

    方法(2):

    在项目路径下,按住Shift+在空白处右击-->在此处打开命令窗口

    输入:ndk-build(前提是配置了NDK的环境变量,把ndk-build.cmd的路径加入到了系统变量path中)

    eclipse中刷新就可以看到生成在lib下的库文件:

    6.在java中加载库文件,调用步骤1中定义的本地(native)方法

    最后一步是调用库文件:

    public class MainActivity extends Activity { //加载动态库 static{ System.loadLibrary("hello"); } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } public void onClickBtn(View view) { <span style="white-space:pre"> </span>//弹出吐司,弹出<span style="font-family: Arial, Helvetica, sans-serif;">stringFromC()方法返回的字符串</span> Toast.makeText(this, stringFromC(), Toast.LENGTH_LONG).show(); } //定义本地方法,在c/c++下实现 public native String stringFromC(); }

    效果图:

    如果要在C中打印日志则以上的基础上:

    1.在Android.mk文件中加:LOCAL_LDLIBS :=-llog

    2.在C文件中引入头文件android/log.h,再调用打印日志的方法(在android/log.h头文件中定义有)

    #include <android/log.h> #define TAG "hello" #define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG,TAG,__VA_ARGS__) jstring Java_com_example_testjni2_MainActivity_stringFromC(JNIEnv* env, jobject thiz) { LOGD("heloooooooooooooo!"); char* cstr = "Hello From CCCC!!!"; //把字符数组转为java的字符串,该方法在jni.h中定义 //jstring (*NewStringUTF)(JNIEnv*, const char*); return (*env)->NewStringUTF(env, cstr); }

    log.h:

    转载请注明原文地址: https://ju.6miu.com/read-1297116.html
    最新回复(0)