Android JNI编程和NDK学习 --静态、动态两种方式实现JNI

Android JNI 的实现包括两种实现方法:静态和动态。两种方法的区别如下:

静态:先由Java得到本地方法的声明“System.loadLibrary("hello_jni");”,然后再通过JNI实现该声明方法。

动态:先通过JNI重载JNI_OnLoad()实现本地方法,然后直接在Java中调用本地方法。JNI在加载时,会调用JNI_OnLoad,而卸载时会调用JNI_UnLoad,所以我们可以通过在JNI_OnLoad里面注册我们的native函数来实现JNI。需要先声明“public native String HelloLoad();”,再指明需要的库“System.loadLibrary("hello_jni");”。


静态方法实现步骤:

1.Java代码中添加库:

static
{
try {
System.loadLibrary("Hello_Jni");

} catch (Exception e) {
// TODO: handle exception
Log.e(TAG, "Load Failed!");
}
}

/* 
* 在Java中注册需要调用的C/C++本地方法(native method),也就是需要C/C++来实现的方法 
*/

public native String sayHello();

2.运行工程,生成.class文件

3.通过javah生成JNI层头文件:

javah -classpath F:\workspace1\HelloJni\src -d C: com.example.hellojni.MainActivity

-classpath 工程的源文件路径

-d <dir> 输出目录

<classes>  .java文件所在的完整路径

//每个class都会产生一个对应的*.h文件(所以一个Activity可能产生多个*.h文件),每个*.h文件命名格式固定:包名_类名.h


4 实现头文件中声明的函数

新建文件jni/hello_jni.c。hello_jni.c的代码如下:

#include <string.h>

#include<jni.h> 

JNIEXPORT jstring JNICALL Java_com_example_hellojni_MainActivity_sayHello

  (JNIEnv* env, jobject obj)

{

    return env->NewStringUTF("Hello word");

hello_jni.c的作用就是实现com_example_hellojni_MainActivity.h中声明的函数。

 

5 编写实现函数对应的Android.mk

添加文件jni/Android.mk,内容如下:

LOCAL_PATH := $(call my-dir) 

include$(CLEAR_VARS) 

LOCAL_MODULE    := hello_jni

LOCAL_SRC_FILES:= hello_jni.c    

include$(BUILD_SHARED_LIBRARY)


6 编译生成库文件

进入到工程所在目录,执行ndk-build,编译生成.so库文件。

7 运行工程

在eclipse下运行工程,ok。


动态方法步骤:

1. 在java中添加

//jni中注册的方法

static final String TAG = "HelloJni2";

static
{
try {
System.loadLibrary("HelloJni2");

} catch (Exception e) {
// TODO: handle exception
Log.e(TAG, "Load Failed!");
}

}

    public native String sayHello();


2. 在jni目录下新建HelloJni2.cpp:

[java]  view plain copy
  1. #include <jni.h>
    #include <stddef.h>
    #include <assert.h>

  2. //添加打印log 在.mk文件中添加LOCAL_LDLIBS :=-llog
    #include <android/log.h>
    #define TAG "HelloJni2" // 这个是自定义的LOG的标识
    #define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG,TAG ,__VA_ARGS__) // 定义LOGD类型
    #define LOGI(...) __android_log_print(ANDROID_LOG_INFO,TAG ,__VA_ARGS__) // 定义LOGI类型
    #define LOGW(...) __android_log_print(ANDROID_LOG_WARN,TAG ,__VA_ARGS__) // 定义LOGW类型
    #define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,TAG ,__VA_ARGS__) // 定义LOGE类型
    #define LOGF(...) __android_log_print(ANDROID_LOG_FATAL,TAG ,__VA_ARGS__) // 定义LOGF类型

    //C++ 文件需要以C函数名导出
    extern "C"
    {
    JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved);
    JNIEXPORT jstring JNICALL native_hello(JNIEnv* env, jobject object);
    JNIEXPORT void JNICALL JNI_OnUnload(JavaVM* vm, void* reserved);
    }

    //findclass .要转成/
    #define JNIREG_CLASS "com/example/hellojni2/MainActivity"

    //Java和JNI函数的绑定表
    JNINativeMethod method_table[] = {
    { "sayHello", "()Ljava/lang/String;", (void*)native_hello},//绑定
    };


    JNIEXPORT jstring JNICALL native_hello(JNIEnv* env, jobject object)
    {
    LOGI("native_hello");
    jstring strTemp;
    strTemp = env->NewStringUTF("hello dylib");
    return strTemp;
    }


    int registerNativeMethods(JNIEnv* env, const char* className,
            JNINativeMethod* gMethods, int numMethods)
    {
    LOGI("registerNativeMethods");
    jclass clazz;
    clazz = env->FindClass(className);
    if (clazz == NULL) {
    return JNI_FALSE;
    }

    if (env->RegisterNatives(clazz, method_table, numMethods) < 0) {
    return JNI_FALSE;
    }
    return JNI_TRUE;
    }

    jboolean registerNatives(JNIEnv* env)
    {
    LOGI("registerNatives");
    return registerNativeMethods(env,JNIREG_CLASS,method_table, sizeof(method_table)/sizeof(method_table[0]));
    }


    JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved)
    {
    LOGI("JNI_OnLoad");
    JNIEnv* env = NULL;
    jint result = -1;

    if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {
    return -1;
    }

    assert(env != NULL);

  3. if (!registerNatives(env)) {//注册
    return -1;
    }
    /* success -- return valid version number */
    result = JNI_VERSION_1_4;
    return result;
    }

    JNIEXPORT void JNICALL JNI_OnUnload(JavaVM* vm, void* reserved)
    {
    }

说明:JNI_OnLoad()会在JNI注册时被调用。在JNI_OnLoad()中,调用registerNatives()。registerNatives()调用registerNativeMethods()。registerNativeMethods()中通过FindClass()找到class;然后通过RegisterNatives()将method_table注册到class中。method_table是JNINativeMethod类型。


JNINativeMethod的定义如下:

typedef struct {

    constchar*name;      // Java中申明的Native函数名称

    constchar* signature; // 描述了函数的参数和返回值

    void* fnPtr;           // 函数指针,指向C函数

} JNINativeMethod;

通过method_table,就将本地的native_hello()函数和注册到Java中的sayHello()绑定起来了。当我们在Java中调用sayHello()时,实际调用的是native_hello()。


3. 在jni目录下新建Android.mk,Android.mk的代码如下:

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE    := HelloJni2
LOCAL_SRC_FILES := HelloJni2.cpp
LOCAL_LDLIBS :=-llog

include $(BUILD_SHARED_LIBRARY)


4. 生成.so库文件:

5. 在eclipse下执行工程,OK。

通过Javap 生成函数签名

javap -s -p F:\workspace1\HelloJni2\bin\classes\com\example\hellojni2\MainActivity.class(编译后的class文件)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值