本文不涉及android-ndk开发环境搭。

步骤一:新建一个APP,名称为HelloJNI,然后定义一个类(将会在native代码中调用和访问该类):

package com.example.hellojni;

public class JNITestBean {
    private int initField;
    public String firstStr = null;
    public static String secondStr = null;
    public JNITestBean(){
    }
    public String getFirstString(String str){
        firstStr = str;
        return firstStr;
    }
    public static String getSecondString(String str){
        secondStr = str;
        return secondStr;
    }
    public int getInitField(){
        return initField;
    }
}

步骤二:在MainActivity中定义native方法:
MainActivity的全路径名是:com.example.hellojni.MainActivity;

native方法是:

private native JNITestBean createJNITestObjFromNative();
//Java加载.so动态库的方式如下:
static{ 
 System.loadLibrary(“HelloJNI”); 
 }


步骤三:使用javah命令生成native函数的.h头文件
首先在HelloJNI目录下,新建目录jni(不能随意命名,只能是jni)

javah -classpath bin\classes -d jni com.example.hellojni.MainActivity
注:
1)如何提示:cannot access android.app.Activity(无法找到android.app.Activity类)时,需要给classpath增加android相应平台的android.jar
javah -classpath D:\software\adt-bundle-windows-x86-20140702\sdk\platforms\android-18\android.jar;bin\classes -d jni com.example.hellojni.MainActivity
记得linux平台时需要把上面的;bin\classes改成:bin/classes
2)bin\classes目录是因为你的java代码编译后在bin下classes下面,如果你的编译后的代码直接在bin下面,就不需要添加classes目录了。
步骤四:编写C/C++代码
将生成的com_example_hellojni_MainActivity.h里面的声明函数,拷贝到自定义的C++函数中,
函数中有具体的注释,需要说明几点:
第一点:C++和C函数使用JNI函数略有不同,需要注意你用的是C++,还是C
第二点:本函数中使用了一个android native层的log函数,所以在模块编译时,需要增加依赖库
第三点:在native方法中所有对类的方法、属性的操作,都是通过反射进行的,不论是静态时还是非静态是,私有属性,公有属性都可以通过反射进行操作,但是操作的时候,需要继续名称(name)和签名(signature)。可以通过下面命令查看签名信息:
javap -s -p 类名

/*
 * mynative.cpp
 *
 */


#include "com_example_hellojni_MainActivity.h"
#include "stdio.h"
#include "string.h"
#include "android/log.h"
#define LOG_TAG "========MYNATIVE=========="
//#define LOGI(...)_android_log_print(ANDROID_LOG_INFO, LOG_TAG,...)
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO  ,  LOG_TAG, __VA_ARGS__)
//#define LOGE(...)_android_log_print(ANDROID_LOG_ERROR, LOG_TAG,...)
//extern int addSum(int , int);
#ifdef __cplusplus
extern "C"
{
#endif
//如果自定义的函数在“main”函数后面,则需要提前声明该函数,否则会 提示error:  was not declared in this scope
int addSum(int , int );
/*
 *env函数指针,指向的是jni开发环境(jni开发所有的所有函数调用都靠他)
 * jobject是MainActivity调用这个方法是,传入的。本方法在Java中声明的是一个static native 这个变量就是jclass对象。一般是调用此方法的当前对象或者当前类
 */
JNIEXPORT jobject JNICALL Java_com_example_hellojni_MainActivity_createJNITestObjFromNative
  (JNIEnv*  env , jobject thizz)
{
    jclass targetClass;
    jmethodID mid;
    jobject newObj;
    jfieldID fid;
    jstring str, str1;
    jint main_acti_value;

    //此处两行代码的作用是得到MainActivity的域
    //targetClass = env->FindClass("MainActivity");
    targetClass = env->GetObjectClass(thizz);
    fid = env->GetStaticFieldID(targetClass, "filed", "I");
    //通过object和方法实体,得到该方法的值
    main_acti_value = env->GetStaticIntField(targetClass, fid);
    LOGI("在C++方法中访问java域,得到的值是: %d \n", main_acti_value);

    //下面的代码将生成JNITest对象,并返回
    targetClass = env->FindClass("com/example/hellojni/JNITestBean");
    if(targetClass == NULL){
        return NULL;
    }
    //得到JNITest类的构造方法
    mid = env->GetMethodID(targetClass, "<init>", "()V");

    LOGI("[CPP] JNITest对象 生成 \n");
    newObj = env->NewObject(targetClass, mid);
    //调用对象的方法
    mid = env->GetStaticMethodID(targetClass, "getSecondString", "(Ljava/lang/String;)Ljava/lang/String;");
    LOGI("查找JNITest对象的getsecondstring这个方法");
    int result = addSum(10 , 20);
    if(mid != NULL){
        LOGI("找到JNITest对象的getsecondstring这个方法");
        char* tempchar = "method invoke from native\n";
            str1 = env->NewStringUTF(tempchar);
            //const char* strch = env->GetStringUTFChars(str, NULL);
            //env->call
            //将jobject对象,转化成jstring对象
            str = (jstring) env->CallStaticObjectMethod(targetClass, mid, str1);
            //将java中的string转化成char字符数组,以便打印输出
            const char* strch = env->GetStringUTFChars(str, NULL);
            LOGI("在native调用java的static方法,方法返回值是: %s \n", strch);

            //释放资源
            //env->ReleaseStringUTFChars(str1, tempchar);
            //env->ReleaseStringUTFChars(str, strch);

    }else{
        LOGI("没有找到JNITest对象的getsecondstring这个方法");
    }
    LOGI("查找JNITest对象的initField这个属性");
    //设置JNITest中的私有变量的值
    fid = env->GetFieldID(targetClass, "initField", "I");
    if(fid != NULL){
        LOGI("设置jnitest的变量的值initfield的值为200");
            main_acti_value = 200;
            env->SetIntField(newObj, fid, main_acti_value);
    }else{
        LOGI("没有找到initfield这个属性");
    }

    return newObj;

}
int addSum(int a, int b)
{
    return a + b;
}
#ifdef __cplusplus
}
#endif

步骤五:编写Android.mk的makefile文件

LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := HelloJNI 
 LOCAL_SRC_FILES := mynative.cpp 
 LOCAL_LDLIBS := -lm -llog -ljnigraphics 
 include $(BUILD_SHARED_LIBRARY) 
 LOCAL_MODULE := HelloJNI 此配置表示编译生成libHelloJNI.so的动态链接库 
 LOCAL_SRC_FILES := mynative.cpp 此配置表示需要编译的C/C++函数


LOCAL_LDLIBS := -lm -llog -ljnigraphics 此配置表示android log函数需要依赖的库

步骤五:在项目根目录下(HelloJNI),通过ndk-build命令编译生成共享库

步骤六:在MainActivity中调用操作native层生成的JNITestBean对象.