C++ Android 通过JNI 双向调用注意事项

在一般的APP项目中,都不用用到C++  所以当我们需要使用C++(也就是JNI)的时候 需要在 Android studio 中进行如下设置

(这里需要特别注意下  如果你的 Android studio版本是3.0及以上时,那么原来3.0以下的版本 在运行项目时会提示 “No toolchains found in the NDK toolchains folder for ABI with prefix: arm-linux-androideabi” 

我的解决方法是  在3.0以下的版本点击安装 CMAKE,NDK,3.0以上的项目也没有报错)

补充:https://developer.android.google.cn/ndk/downloads/  下载替换 自己sdk 中 toolchains 文件夹,及android-ndk-r16b-windows-x86_64android-ndk-r16b oolchains 中的文件就可以解决上面的问题

方法有两种:

(1)File --> Settings --> Appearance & Behavior --> System Settings --> Android SDK -->勾选CMAKE,NDK

(2)ctrl+alt+S -->搜索框中 输入 SDK -->勾选CMAKE,NDK

 如下图:

配置做完后 在撸代码之前 我们来对 java类型与C++类型的比较

/*
    *
    *
       Java类型      别名             C++本地类型          字节(bit)


       boolean      jboolean            unsigned char         8, unsigned

       byte         jbyte               signed char       8

       char         jchar               unsigned short        16, unsigned

       short        jshort              short                 16

       int          jint                long               32

       long         jlong               __int64            64

       float        jfloat              float               32

       double       jdouble             double              64

       void         void                                   n/a

*
    * */

开始正式撸代码  (如果大家想快速生成JNI范例   在新建项目时勾选 include C++ 就可以

MainActivity.java

public class MainActivity extends AppCompatActivity { // Used to load the 'native-lib' library on application startup. static { System.loadLibrary("native-lib");//此.so名称名称可以在 CMakeLists.txt 中修改 } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // Example of a call to a native method TextView tv = (TextView) findViewById(R.id.sample_text); tv.setText(stringFromJNI()); tv.setText(testNativeFunction()); } /** * A native method that is implemented by the 'native-lib' native library, * which is packaged with this application. */ public native String stringFromJNI(); public native String testNativeFunction();
    public native String cCallJava();

public native String cCallJavaParm();
    /*
    * java调用有参方法
    */
    public static  Object cByJava(int b){
        Log.i("cByJava", "cByJava: 我被调用了  b:"+b);
        return "ssssss";
    }


    public static void cByJavaf(){
        Log.i("cByJava1", "cByJava: 我被调用了 ");
    }
  public  void     addffffff(int b,int c,int d){
  Log.i("bbbbb","fffffff");
  }
}

  native-lib.cpp

#include <jni.h>
#include <string>


#define  NativeStr(name)Java_com_example_android_testc_##name

/*
    *
    *
       类型           相应的签名:(就是后面的 GetStaticMethodID(mMain,"cByJava","(I)Ljava/lang/Object;") 的 (I)Ljava/lang/Object;)

       boolean        Z

       byte           B

       char           C

       short          S

       int            I

       long           J

       float          F

       double         D

       void           V

       object         L用/分隔包的完整类名:   Ljava/lang/String;

       Array          [签名          [I      [Ljava/lang/Object;

       Method         (参数1类型签名 参数2类型签名···)返回值类型签名





    *
    * */



extern "C" JNIEXPORT
jstring JNICALL
        NativeStr(MainActivity_stringFromJNI)(
        JNIEnv *env,
        jobject /* this */) {

    //C++调用java  带参数 有返回值(当返回值为String时用Object代替)
    //----------------beigin----------------
//    static const char* const DL_CLASS_NAME = "com/example/android/testc/MainActivity";
//    jclass  mMain = (env)->FindClass(DL_CLASS_NAME);
//    jmethodID   cByJava =(env)->GetStaticMethodID(mMain,"cByJava","(I)Ljava/lang/Object;");//java中有参数返回的方法的时候;一定要加上 ";" 不然会调用失败
//    jstring result =(jstring)(env)->CallStaticObjectMethod(mMain, cByJava,1111);
    //----------------end----------------
//    return result;
//    std::string hello = "";
//    return env->NewStringUTF(hello.c_str());


//C++调用java  带参数 无返回值
    static const char* const DL_CLASS_NAME = "com/example/android/testc/MainActivity";
    jclass  mMain = (env)->FindClass(DL_CLASS_NAME);
    jmethodID   cByJavaf =(env)->GetStaticMethodID(mMain,"cByJavaf","()V");//在方法名为void的情况下  V后面不能加上 ';' 不然会运行异常 报找不到方法 ()后面一定要大写
    (env)->CallStaticVoidMethod(mMain, cByJavaf);
    jstring  js =env->NewStringUTF("ssssssss");
    return js;

}

extern "C" JNIEXPORT
jstring JNICALL NativeStr(MainActivity_testNativeFunction)(
        JNIEnv *env,
        jobject /* this */) {

    static const char* const DL_CLASS_NAME = "com/example/android/testc/MainActivity";
    jclass  mMain = (env)->FindClass(DL_CLASS_NAME);
    jmethodID   cByJavaf =(env)->GetStaticMethodID(mMain,"cByJavaf","()V");//在方法名为void的情况下  V后面不能加上 ';' 不然会运行异常 报找不到方法 ()后面一定要大写
    (env)->CallStaticVoidMethod(mMain, cByJavaf);
    jstring  js =env->NewStringUTF("sssffffsssss");
    return js;

}
//C 调用Java普通方法
extern "C"
JNIEXPORT jstring JNICALL
Java_com_example_myapplication_MainActivity_cCallJava(JNIEnv *env, jobject instance) {

// TODO C调用java

static const char* const DL_CLASS_NAME ="com/example/myapplication/MainActivity";

jclass mMain = env->FindClass(DL_CLASS_NAME);

jmethodID addMethod = env->GetMethodID(mMain,"add","()V");

env->CallVoidMethod(instance,addMethod);

return env->NewStringUTF("ffff");

}

extern "C"
JNIEXPORT jstring JNICALL
Java_com_example_myapplication_MainActivity_cCallJavaParm(JNIEnv *env, jobject instance) {

static const char* const DL_CLASS_NAME ="com/example/myapplication/MainActivity";

jclass mMain = env->FindClass(DL_CLASS_NAME);

jmethodID addMethod = env->GetMethodID(mMain,"addffffff","(III)V");

env->CallVoidMethod(instance,addMethod,22,33,44);


return env->NewStringUTF("调用有参的函数");
}

  此处有个坑:  在studio3.2 中 每个C++方法都需要加上   extern "C" JNIEXPORT 前缀  不然会提示找不到 第二个方法   NativeStr(MainActivity_testNativeFunction)

       打完收工

}
原文地址:https://www.cnblogs.com/LKit/p/9797170.html