JNI是Java Native Interface的缩写,中文为JAVA本地调用。使用JNI可以很方便的用我们的Java程序调用C/C++程序。很多时候,某些功能用Java无法实现,比如说涉及到底层驱动的一些功能,这时候我们就可以利用JNI来调用C或者C++程序来实现,这就是JNI的强大之处。但是JNI也有它的缺点,使用java与本地已编译的代码交互,通常会丧失平台可移植性。
1、首先配置SDK环境,配置NDK环境、配置JDK环境;这些环境的搭建这里我就不做过多介绍
2、编写Android小程序,这里我简单放一个Button按钮,目的就是调用底层C语言传过来的值;这里我只粘贴关键代码。这个是在onCreate()函数里面设置点击按钮后的事件。
btnGetC = (Button) findViewById(R.id.btnGetC);
btnGetC.setOnClickListener(new OnClickListener(){
@Override
public void onClick(View v) {
Toast.makeText(MainActivity.this, "单击成功"+show(), Toast.LENGTH_SHORT).show();
}
});
定义native函数,为了调用C语言里面的值。这里只对其进行定义。
/**
* 该方法为native方法 ,获取C语言的代码
* @return
*/
public static native String show();
3、加载so文件
/**
* 载入JNI生成so库文件
*/
static{
System.loadLibrary("libJNI");
}
加载的libJNI要和lib下面的so文件名一致;如lib下面的so文件名为libHookFun.so,那么这里放的参数应该为HookFun
4、在工程文件下创建jni目录,新建c程序文件为hello.c文件。引入头文件#include<jni.h>。下面是hello.c文件中的代码;
JNIEnv* env = NULL;
extern "C" {JNIEXPORT <span style="color:#FF0000;"><strong>jstring </strong></span>JNICALL <strong><span style="color:#FF0000;">show</span></strong>(<strong><span style="color:#FF0000;">JNIEnv *env,jclass tis</span></strong>) //jstring要和native函数中的返回值照应,show为native函数名;其中默认两个参数,如果有其他参数可以继续添加
{
return NULL;//这里我返回了空,这里你可以添加自己的C程序,最后返回的时候要转化为jstring类型,具体可以参考JNI的编写规则;
}
}
static JNINativeMethod getMethods[] =
{
{"<strong><span style="color:#FF0000;">show</span></strong>", "<span style="color:#FF0000;"><strong>()Ljava/lang/String;</strong></span>", <strong><span style="color:#FF0000;">(void*)show</span></strong>}//第一个参数为函数名,第二个参数括号内为参数类型,括号外为返回类型,第三个为函数指针类型;
};
static int registerNativeMethods(JNIEnv* env, const char* className, JNINativeMethod* gMethods, int numMethods)//这个是注册函数,固定的,可以参考此;下面固定;
{
jclass clazz;
// clazz = env->FindClass(className);
jclass temp = env->FindClass(className);
clazz =(jclass)env->NewGlobalRef(temp);
if (clazz == NULL)
{
return 0;
}
if (env->RegisterNatives(clazz, gMethods, numMethods) < 0)
{
return 0;
}
return 1;
}
static int registerNatives(JNIEnv* env)
{
if (!registerNativeMethods(env, "com/example/jnihook/MainActivity", getMethods, sizeof(getMethods) / sizeof(getMethods[0])))
return JNI_FALSE;
return JNI_TRUE;
}
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void *reserved)
{
// LOGI("before antiDebug");
// antiDebug(true);
// LOGI("after antiDebug");
jint result = -1;
if(vm->GetEnv((void**)&env, JNI_VERSION_1_4) != JNI_OK)
return -1;
if(!registerNatives(env))
return -1;
return JNI_VERSION_1_4;
}
5、在jni目录下编写Android.mk文件,这个是配置文件,具体可以参考网上http://blog.csdn.net/ly131420/article/details/9619269文章有介绍
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := <strong><span style="color:#FF0000;">JNIHook</span></strong>
LOCAL_LDLIBS := -llog
LOCAL_LDLIBS += -landroid
LOCAL_CFLAGS := -fpermissive -DDEBUG -O0 -fexceptions
LOCAL_CFLAGS += -I~/android-4.4/system/core/include
LOCAL_SRC_FILES := \
hello.cpp
include $(BUILD_SHARED_LIBRARY)
这里Local_module模块为lib加载的so文件名,local_src_files下面为C程序的文件。
6、配置C程序的编译器,这个和ndk的路径有关
具体可以参考下面我的截图
配置好之后就可以自动的进行编译;
完成好之后就可以运行了,点击按钮会弹出“单机成功NULL”。表示JNI程序运行通过测试。
具体复杂的,还要了解JNI的编写规则,mk文件的编写,C和Java程序的编写等等。