本篇博文基于前一篇Ndk基础知识(一)环境搭建编写,有需要的读者请先阅读前一篇博文。
预备知识
在AndroidStudio自动生成的项目中,我们猜想stringFromJNI()和cpp文件中的Java_com_breeze_ndkdemo2_MainActivity_stringFromJNI是对应的,事实上确实如此。根据JNI的命名规则,java层的native方法命名规则为在返回类型前加native,如
public native String stringFromJNI();
对应的c++方法命名为对应的返回类型+类的全名(包名+类名,其中将”.”换成”_”)+方法名+(JNIEnv *env, jobject thiz + 参数)如:
jstring
Java_com_breeze_ndkdemo2_MainActivity_stringFromJNI(
JNIEnv *env, jobject /* this */)
生成java方法对应的c层的方法名看起来比较复杂,其实也有对应的工具可以使用,java提供了javah可以自动生成java native方法对应的c头文件。
在Android Studio中可以设置该命令。操作如下:File->Settings->Tools->External Tools中选择加号添加一个工具,在该窗口中进行如下设置
设置完成后,我们看如何使用:
首先写好java类,Build->Make Project生成相关类文件,这一步很重要,javah是根据class 文件去生成头文件的,所以必须先生成相应的class文件。然后对该类右键选择External Tools->javah生成相应的头文件,按照当前配置,生成的头文件会放在jni目录中。事实上得到头文件后放在哪个位置可根据需要自己重新剪切调整,甚至不使用头文件直接把该方法声明拿去使用也是可以的,javah命令只是方便我们不用去写容易出错的方法名罢了。
举例
新建一个NativeUtils类内容如下:
public class NativeUtils {
public static native int addNum(int num);
public static native String addChar(String str);
public static native int[] addArray(int[] arr, int length);
}
Build->Make Project,生成class文件,右键External Tools->javah生成对应的头文件,在native-lib.cpp文件中实现上述方法。
#include <jni.h>
#include <string>
#include <android/log.h>
#include <string.h>
#include "com_breeze_ndkdemo2_NativeUtils.h"
extern "C"
jstring
Java_com_breeze_ndkdemo2_MainActivity_stringFromJNI(
JNIEnv *env,
jobject /* this */) {
std::string hello = "Hello from C++";
return env->NewStringUTF(hello.c_str());
}
JNIEXPORT jint JNICALL Java_com_breeze_ndkdemo2_NativeUtils_addNum
(JNIEnv *, jclass, jint num){
return num + 1;
}
/*
* Class: com_breeze_ndkdemo2_NativeUtils
* Method: addChar
* Signature: (Ljava/lang/String;)Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_com_breeze_ndkdemo2_NativeUtils_addChar
(JNIEnv *env , jclass, jstring str){
jsize alen = env->GetStringLength(str);
char * strs = new char[alen + 1];
jboolean isCopy = true;
const jchar* chars = env->GetStringChars(str, &isCopy);
for (int i = 0; i < alen; i++){
strs[i] = chars[i];
}
__android_log_write(ANDROID_LOG_INFO, "str from java", strs);
std::string s = "hello";
return env->NewStringUTF(s.c_str());
}
/*
* Class: com_breeze_ndkdemo2_NativeUtils
* Method: addArray
* Signature: ([I)[I
*/
JNIEXPORT jintArray JNICALL Java_com_breeze_ndkdemo2_NativeUtils_addArray
(JNIEnv *env, jclass, jintArray array, jint length){
jboolean isCopy = true;
jint* arr = env->GetIntArrayElements(array, &isCopy);
for (int i = 0; i < length; i++){
arr[i] = arr[i] + 1;
}
jintArray javaArray;
javaArray = env->NewIntArray(length);
env->SetIntArrayRegion(javaArray, 0, length, arr);
return javaArray;
}
在MainActivity中调用:
public class MainActivity extends AppCompatActivity {
// Used to load the 'native-lib' library on application startup.
static {
System.loadLibrary("native-lib");
}
@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());
int num = NativeUtils.addNum(3);
Log.d("ZXX", num + "");
String str = NativeUtils.addChar("hello");
Log.d("ZXX", str);
int [] arr = NativeUtils.addArray(new int[]{1, 2, 3}, 3);
for (int i = 0; i < arr.length; i++){
Log.d("ZXX", "num" + i + ":" + arr[i]);
}
}
/**
* A native method that is implemented by the 'native-lib' native library,
* which is packaged with this application.
*/
public native String stringFromJNI();
}
上述内容介绍了简单数据类型和字符串在c和java之间的传递。其中jint,jstring,jintArray是java中的int,String,int[]在c中对应类型,这些内容定义在jni.h中。下面列出c和java中部分类型的对应关系:
Java类型 | 本地类型 | 描述 |
---|---|---|
boolean | jboolean | C/C++8位整型 |
byte | jbyte | C/C++带符号的8位整型 |
char | jchar | C/C++无符号的16位整型 |
short | jshort | C/C++带符号的16位整型 |
int | jint | C/C++带符号的32位整型 |
long | jlong | C/C++带符号的64位整型e |
float | jfloat | C/C++32位浮点型 |
double | jdouble | C/C++64位浮点型 |
Object | jobject | 任何Java对象,或者没有对应java类型的对象 |
Class | jclass | Class对象 |
String | jstring | 字符串对象 |
Object[] | jobjectArray | 任何对象的数组 |
boolean[] | jbooleanArray | 布尔型数组 |
byte[] | jbyteArray | 比特型数组 |
char[] | jcharArray | 字符型数组 |
short[] | jshortArray | 短整型数组 |
int[] | jintArray | 整型数组 |
long[] | jlongArray | 长整型数组 |
float[] | jfloatArray | 浮点型数组 |
double[] | jdoubleArray | 双浮点型数组 |