Android之jni深入

小技巧:自动生成 java本地方法对应的c代码的方法名 javah 指令 +全类名

java1.6版本 class C:workspaceHelloWorldFromC2inclasses
java1.7以上 src C:workspaceHelloWorldFromC2src

获得方法的签名的方法

javap -s 打印方法的签名 注意要cd到 C:workspaceHelloWorldFromC2inclasses 传全类名

Android.mk文件的书写

Anroid.mk 文件 
    LOCAL_PATH := $(call my-dir)   // 返回当前c代码目录
    include $(CLEAR_VARS)        // 清楚了所有 已local 开头的配置文件 唯独不清楚LOCAL_PATH

    LOCAL_MODULE    := hello   // 库函数的名字  严格遵守makefile 格式  lib  .so  如果前面加lib 不会自动生成了
   LOCAL_SRC_FILES := Hello.c
    include $(BUILD_SHARED_LIBRARY)  // 加入库函数

java调用C方法,并且传递参数

/**
     * 计算x和y的加法  apktools  
     * 315 
     * @param x
     * @param y
     * @return
     */
    public native int add(int x ,int y);  // char   String   short   kiss  keep it simple and stupid  String[]  "123:234" 
    /**
     * 给字符串后面拼装字符  加密运算   web   url  
     * @param s
     * @return
     */
    public native String sayHelloInC(String s);
    //  
    /**
     * 给c代码传递int数组   让c代码给这个数组进行操作
     * 图形 声音的处理
     * @param iNum
     * @return
     */
    public native int[] intMethod(int[] iNum); 

C代码输出到控制台上LOG

#define LOG_TAG "clog"
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)

传递两个int实现

JNIEXPORT jint JNICALL Java_com_example_ndkpassdata_DataProvider_add
  (JNIEnv * env, jobject jobject, jint x, jint y){
    // 想在logcat控制台上 打印日志
    LOGD("x=%d",x);
    LOGI("y=%d",y);
    // log.i(TAG,"sss");
    return x+y;

}

字符串拼接实现

JNIEXPORT jstring JNICALL Java_com_example_ndkpassdata_DataProvider_sayHelloInC
  (JNIEnv * env, jobject jobject, jstring str){

    char* c="hello";
    // 在C语言中不能直接操作java中的字符串
    // 把java中的字符串转换成c语言中 char数组
    char* cstr=Jstring2CStr(env,str);

    strcat(cstr,c);
    LOGD("%s",cstr);
    return  (*env)->NewStringUTF(env,cstr);
}

传递数组实现

JNIEXPORT jintArray JNICALL Java_com_example_ndkpassdata_DataProvider_intMethod
  (JNIEnv * env, jobject jobject, jintArray jarray){
    // jArray  遍历数组   jint*       (*GetIntArrayElements)(JNIEnv*, jintArray, jboolean*);
    // 数组的长度    jsize       (*GetArrayLength)(JNIEnv*, jarray);
    // 对数组中每个元素 +5
    int length=(*env)->GetArrayLength(env,jarray);
    int* array=(*env)->GetIntArrayElements(env,jarray,0);
    int i=0;
    for(;i<length;i++){
        *(array+i)+=5;
    }
    return jarray;
}

C语言利用反射回调java方法

java的反射

Class<?> forName = Class.forName("com.example.ndkcallback.DataProvider");
        Method declaredMethod = forName.getDeclaredMethod("helloFromJava", new Class[]{});
        declaredMethod.invoke(forName.newInstance(), new Object[]{});

java中的方法的声明

public class DataProvider {
    //C调用java空方法
    public void helloFromJava(){
        System.out.println("哈哈哈  我被调用了");
    }
    //C调用java中的带两个int参数的方法
    public int Add(int x,int y){
         int result=x+y;
        System.out.println("result:"+result);
        return result;
    }
    //C调用java中参数为string的方法
    public void printString(String s){
        System.out.println(s);
    }

    public static void demo(){
        System.out.println("哈哈哈,我是静态方法");

    }

    public native void callMethod1();
    public native void callMethod2();
    public native void callMethod3();
    public native void callMethod4();
    public native void callMethod5();
}

实现

实现调用java空方法

JNIEXPORT void JNICALL Java_com_example_ndkcallback_DataProvider_callMethod1
  (JNIEnv * env, jobject jobject){

    /*
     *
        Class<?> forName = Class.forName("com.example.ndkcallback.DataProvider");
        Method declaredMethod = forName.getDeclaredMethod("helloFromJava", new Class[]{});
        declaredMethod.invoke(forName.newInstance(), new Object[]{});
     *
     *
     */
    ///jclass      (*FindClass)(JNIEnv*, const char*);
    jclass clazz=(*env)->FindClass(env,"com/example/ndkcallback/DataProvider");
    //  jmethodID   (*GetMethodID)(JNIEnv*, jclass, const char*, const char*);
    // 方法签名  参数和返回值
    jmethodID methodId=(*env)->GetMethodID(env,clazz,"helloFromJava","()V");
    // void        (*CallVoidMethod)(JNIEnv*, jobject, jmethodID, ...);
    (*env)->CallVoidMethod(env,jobject,methodId);
}

实现调用int参数的方法

JNIEXPORT void JNICALL Java_com_example_ndkcallback_DataProvider_callMethod2
  (JNIEnv *  env, jobject jobject){
    jclass clazz=(*env)->FindClass(env,"com/example/ndkcallback/DataProvider");
    jmethodID methodId=(*env)->GetMethodID(env,clazz,"Add","(II)I");
    // jint        (*CallIntMethod)(JNIEnv*, jobject, jmethodID, ...);
    (*env)->CallIntMethod(env,jobject,methodId,3,5);
}

实现调用String参数的方法

JNIEXPORT void JNICALL Java_com_example_ndkcallback_DataProvider_callMethod3
  (JNIEnv * env, jobject jobject){   // 参数 object  就是native方法所在的类
    jclass clazz=(*env)->FindClass(env,"com/example/ndkcallback/DataProvider");
        jmethodID methodId=(*env)->GetMethodID(env,clazz,"printString","(Ljava/lang/String;)V");
        // jint        (*CallIntMethod)(JNIEnv*, jobject, jmethodID, ...);
        jstring str=(*env)->NewStringUTF(env,"hello");

        (*env)->CallVoidMethod(env,jobject,methodId,str);

}

实现调用其他类中的方法,注意此时的object为该类的对象

JNIEXPORT void JNICALL Java_com_example_ndkcallback_DataProvider_callMethod4
  (JNIEnv * env, jobject j){
    jclass clazz=(*env)->FindClass(env,"com/example/ndkcallback/MainActivity");
    //  jmethodID   (*GetMethodID)(JNIEnv*, jclass, const char*, const char*);
    // 方法签名  参数和返回值
    jmethodID methodId=(*env)->GetMethodID(env,clazz,"helloFromJava","()V");
    // void        (*CallVoidMethod)(JNIEnv*, jobject, jmethodID, ...);
    // 需要创建DataProvider的 对象
    // jobject     (*AllocObject)(JNIEnv*, jclass);
    jobject obj=(*env)->AllocObject(env,clazz);  // new MainActivity();
    (*env)->CallVoidMethod(env,obj,methodId);

}

实现调用静态方法

JNIEXPORT void JNICALL Java_com_example_ndkcallback_DataProvider_callMethod5
  (JNIEnv * env, jobject j){
    jclass clazz=(*env)->FindClass(env,"com/example/ndkcallback/DataProvider");
    //     jmethodID   (*GetStaticMethodID)(JNIEnv*, jclass, const char*, const char*);
     jmethodID  methodid=(*env)->GetStaticMethodID(env,clazz,"demo","()V");
    //void        (*CallStaticVoidMethod)(JNIEnv*, jclass, jmethodID, ...);
     (*env)->CallStaticVoidMethod(env,clazz,methodid);
}

完成

原文地址:https://www.cnblogs.com/jjx2013/p/6223735.html