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_64\android-ndk-r16b\toolchains 中的文件就可以解决上面的问题
方法有两种:
(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)
打完收工
}