目前接触到的终端产品基本都是:C/C++写内核 + Android/IOS包一层皮。
OC和C/C++可以混编,java和C/C++需要依赖jni桥接。
jni需要掌握两个点:
- 如何桥接
- 如何进行数据转换
1. jni桥接
- 在XXX.java中定义native方法作为接口,不需要在java中实现。
- 针对XXX.java生成C/C++头文件XXX.h,该头文件包含了XXX.java中所有的native函数定义。
- 建立C/C++的.dll或.so工程,引用jni.h、jni_md.h、XXX.h。
- 新建XXX.cpp并实现XXX.h中的方法,编译生成动态链接库XXX.dll或XXX.so
- 在XXX.java中使用语句加载XXX.dll或XXX.so后,即可调用native方法。
2. jni数据转换
XXX.h头文件中定义的函数为
JNIEXPORT void JNICALL method_name
(JNIEnv *env, jobject obj, ...){
}
env包含了大量可调用的函数。
若方法为static,则obj为类;
若方法非static,则obj为类对象
2.1 基本数据类型
基本数据类型可以直接用。
jni.h中的定义:
typedef unsigned char jboolean; // 1byte
typedef unsigned short jchar; // 2byte
typedef short jshort; // 2byte
typedef float jfloat; // 4byte
typedef double jdouble; // 8byte
typedef long jint; // 4byte
typedef __int64 jlong; // 8byte
typedef signed char jbyte; // 1byte
typedef jint jsize; // 4byte
2.2 string
获取长度
// 获取unicode编码下的string长度
jsize len = env->GetStringLength(str);
// 获取utf-8编码下的string长度
jsize len = env->GetStringUTFLength(str);
访问元素,无法修改,一定要释放
// 获取string长度
jsize len = env->GetStringLength(str); // unicode编码模式
jsize len = env->GetStringUTFLength(str); // utf-8编码模式
// 获取char
const jchar *data = env->GetStringChars(str, NULL); // unicode编码模式
const char *data = env->GetStringUTFChars(str, NULL); // utf-8编码模式
// 访问
for(int i = 0;i<len;i++){
data[i];
}
// 释放
env->ReleaseStringChars(str,data); // unicode编码模式
env->ReleaseStringUTFChars(str,data); // utf-8编码模式
创建新string
jstring str = env->NewString(unicode, len); // unicode编码模式
jstring str = env->NewStringUTF(utf); // utf-8编码模式
2.3 Class
获取class类
jclass _jclass = env->FindClass("类路径,例如java/lang/String");// 根据路径得到类
jclass _jclass = env->GetObjectClass(_jobject); // 根据类对象得到类
得到类对象中的属性
// 得到_jclass类中名字为name,描述为sig的属性
jfieldID _fieldID = env->GetFieldID(_jclass, "name", "sig");
// 基于属性的数据类型选择Get方法,得到该属性的值
jint value = env->GetIntField(_jobject, _fieldID); // int型
jbyte value = env->GetByteField(_jobject, _fieldID); // byte型
jchar value = env->GetCharField(_jobject, _fieldID); // char型
jobject value = env->GetObjectField(_jobject, _fieldID); // class型
...
调用类对象中的方法
// 得到_jclass类中名字为name,描述为sig的方法
jmethodID _methodID = env->GetMethodID(_jclass, "name", "sig");
// 基于返回值的数据类型选择call方法进行函数调用
env->CallVoidMethod(_jobject, _methodID, ...);
jboolean ret = env->CallBooleanMethod(_jobject, _methodID, ...);
jchar ret = env->CallCharMethod(_jobject, _methodID, ...);
jbyte ret = env->CallByteMethod(_jobject, _methodID, ...);
jshort ret = env->CallShortMethod(_jobject, _methodID, ...);
jint ret = env->CallIntMethod(_jobject, _methodID, ...);
jlong ret = env->CallLongMethod(_jobject, _methodID, ...);
jfloat ret = env->CallFloatMethod(_jobject, _methodID, ...);
jdouble ret = env->CallDoubleMethod(_jobject, _methodID, ...);
jobject ret = env->CallObjectMethod(_jobject, _methodID, ...);
备注:
name应与类对象中的方法/属性名一致
方法/属性的sig可通过命令javap -s -p XXX.class得到
2.4 数组
jni.h定义了9种array,且都继承了_jarray类
class _jbooleanArray : public _jarray {};
class _jbyteArray : public _jarray {};
class _jcharArray : public _jarray {};
class _jshortArray : public _jarray {};
class _jintArray : public _jarray {};
class _jlongArray : public _jarray {};
class _jfloatArray : public _jarray {};
class _jdoubleArray : public _jarray {};
class _jobjectArray : public _jarray {};
访问array,无法修改,一定要释放
// 获取array的长度
jsize len = env->GetArrayLength(_jArray);
// 依据array中元素的数据类型选择对象的函数,获取array的首地址
jboolean *data = env->GetBooleanArrayElements(_jarray ,NULL);
jbyte *data = env->GetByteArrayElements(_jarray ,NULL);
jchar *data = env->GetCharArrayElements(_jarray ,NULL);
jshort *data = env->GetShortArrayElements(_jarray ,NULL);
jint *data = env->GetIntArrayElements(_jarray ,NULL);
jlong *data = env->GetLongArrayElements(_jarray ,NULL);
jfloat *data = env->GetFloatArrayElements(_jarray ,NULL);
jdouble *data = env->GetDoubleArrayElements(_jarray ,NULL);
jobject *data = env->GetObjectArrayElement(_jarray ,NULL);
// 遍历访问array
for(int i = 0; i<len; i++){
data[i];
}
// 释放
env->ReleaseBooleanArrayElements(array,data,mode);
env->ReleaseByteArrayElements(array,data,mode);
env->ReleaseCharArrayElements(array,data,mode);
env->ReleaseShortArrayElements(array,data,mode);
env->ReleaseIntArrayElements(array,data,mode);
env->ReleaseLongArrayElements(array,data,mode);
env->ReleaseFloatArrayElements(array,data,mode);
env->ReleaseDoubleArrayElements(array,data,mode);
创建array,做了实验,不需要释放
jbooleanArray array = env->NewBooleanArray(_size);
jcharArray array = env->NewCharArray(_size);
jbyteArray array = env->NewByteArray(_size);
jshortArray array = env->NewShortArray(_size);
jintArray array = env->NewIntArray(10);
jlongArray array = env->NewLongArray(_size);
jfloatArray array = env->NewFloatArray(_size);
jdoubleArray array = env->NewDoubleArray(_size);
对array赋值
env->SetBooleanArrayRegion(array, start, len, *buf);
env->SetCharArrayRegion(array, start, len, *buf);
env->SetByteArrayRegion(array, start, len, *buf);
env->SetShortArrayRegion(array, start, len, *buf);
env->SetIntArrayRegion(array, start, len, *buf);
env->SetLongArrayRegion(array, start, len, *buf);
env->SetFloatArrayRegion(array, start, len, *buf);
env->SetDoubleArrayRegion(array, start, len, *buf);