一:基本概念: JNI是Java Native Interface的缩写,通过使用Java本地接口书写程序,可以确保代码在不同的平台上方便移植。 NDK提供了一系列的工具,帮助开发者快速开发C(或C++)的动态库,并能自动将so和java应用一起打包成apk。
二: Java调用C++
static {
System.loadLibrary("native-lib");
}
1.静态注册Native函数
public native void changeName();
public static native void changeAge();
extern "C" //必须采用C的编译方式,无论是C还是C++ 最终是调用到 C的JNINativeInterface,所以必须采用C的方式 extern "C"
JNIEXPORT //标记该方法可以被外部调用
void JNICALL
//Java_包名_类名_方法名,
//JNIEnv *env :JNI的桥梁
// jobject jobj 谁调用,就是谁的实例 MainActivity this
Java_com_derry_as_1jni_1project_MainActivity_changeName(JNIEnv *env, jobject thiz) {
}
extern "C"
JNIEXPORT void JNICALL
// jclass clazz 谁调用,就是谁的class MainActivity.class
Java_com_derry_as_1jni_1project_MainActivity_changeAge(JNIEnv *env, jclass jcls) {
}
三:C++调用Java
// NDK工具链里面的 log 库 引入过来
#include <android/log.h>
#define TAG "Derry"
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, TAG, __VA_ARGS__)
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, TAG, __VA_ARGS__)
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, TAG, __VA_ARGS__)
extern "C"
JNIEXPORT void JNICALL
Java_com_derry_as_1jni_1project_MainActivity_changeName(JNIEnv *env, jobject thiz) {
// 获取class
jclass j_cls = env->GetObjectClass(thiz);
// 获取属性 L对象类型 都需要L
// jfieldID GetFieldID(MainActivity.class, 属性名, 属性的签名)
jfieldID j_fid = env->GetFieldID(j_cls, "name", "Ljava/lang/String;");
// 转换工作
jstring j_str = static_cast<jstring>(env->GetObjectField(thiz ,j_fid));
// 打印字符串 目标
char * c_str = const_cast<char *>(env->GetStringUTFChars(j_str, NULL));
LOGD("native : %s\n", c_str);
LOGE("native : %s\n", c_str);
LOGI("native : %s\n", c_str);
// 修改成 Beyond
jstring jName = env->NewStringUTF("Beyond");
env->SetObjectField(thiz, j_fid, jName);
// printf() C
// cout << << endl; // C++
}
extern "C"
JNIEXPORT void JNICALL
Java_com_derry_as_1jni_1project_MainActivity_callAddMethod(JNIEnv *env, jobject job) {
// 自己得到 MainActivity.class
jclass mainActivityClass = env->GetObjectClass(job);
// GetMethodID(MainActivity.class, 方法名, 方法的签名)
jmethodID j_mid = env->GetMethodID(mainActivityClass, "add", "(II)I");
// 调用 Java的方法
jint sum = env->CallIntMethod(job, j_mid, 3, 3);
LOGE("sum result:%d", sum);
}
/*
签名规则 大写
javap -s -p MainActivity 必须是.class
Java的boolean --- Z 注意点
Java的byte --- B
Java的char --- C
Java的short --- S
Java的int --- I
Java的long --- J 注意点
Java的float --- F
Java的double --- D
Java的void --- V
Java的引用类型 --- Lxxx/xxx/xx/类名;
Java的String --- Ljava/lang/String;
Java的array int[] --- [I double[][][][] --- [[[D
int add(char c1, char c2) ---- (CC)I
void a() === ()V
javap -s -p xxx.class -s 输出xxxx.class的所有属性和方法的签名, -p 忽略私有公开的所有属性方法全部输出
*/