NDK的用法
1.新建一个项目,并使用native方法。
public class MainActivity extends AppCompatActivity {
private TextView showTv;
static {
System.loadLibrary("jni-test");
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
showTv = findViewById(R.id.show);
showTv.setText(get());
set("Hello from Android");
}
public native String get();
public native void set(String string);
}
2.实现Android项目中声明的native方法
有三个文件,test.cpp,Android.mk,Application.mk。
test.cpp
#include <jni.h>
#include <stdio.h>
#ifdef __cplusplus
extern "C"{
#endif
jstring Java_com_xupt_will_ndktest_MainActivity_get(JNIEnv *env,jobject thiz){
printf("invoke get from C++\n");
return env->NewStringUTF("Hello from JNI in jni-test.so !");
}
void Java_com_xupt_will_ndktest_MainActivity_set(JNIEnv *env,jobject thiz,jstring string){
printf("invoke get from C++\n");
char* str = (char*)env->GetStringUTFChars(string,NULL);
printf("%s\n",str);
env->ReleaseStringUTFChars(string,str);
}
#ifdef __cplusplus
}
#endif
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := jni-test
LOCAL_SRC_FILES := test.cpp
include $(BUILD_SHARED_LIBRARY)
APP_ABI := armeabi-v7a
在Android.mk中:
LOCAL_MODULE 表示模块的名称
LOCAL_SRC_FILES 表示需要参与编译的源文件
Application.mk中
APP_ABI 表示CPU的架构平台的类型,目前常见的类型有armeabi,x86和mips,其中armeabi是最常见的,所以只编译这种,如果是all的话,则表示编译所有CPU平台的so库。
在此基础上,生成一个jni文件夹,目录结构如图所示:
然后将test.cpp,Android.mk,Application.mk这三个文件放到里面。
3.使用ndk-build命令编译产生so库
先使用ndk-build生成so库。
这时目录结构会成为这样。
4.运行
直接运行的话会报错,如下图所示。
因为我们没有指出so库所在的位置,找不到,自然会报错。
所以我们需要在build.gradle(Module:app)中添加下面这几行代码,指出so库所在的位置。
sourceSets {
main {
jniLibs.srcDirs = ['libs']
}
}
结果如图所示:
JNI调用Java
上面我们说了如何使用Java调用C或C++,接下来是C/C++如何调用Java的。
JNI调用Java方法的流程是先通过类名找到类,然后通过方法名找到方法的id,最后才可以调用。如果调用的是一个非静态方法,那么需要构造出类的对象后才能调用。
1.在MainActivity中添加一个静态方法以供JNI调用
public static void methodCalledByJni(String msgFromJni){
Log.d("haha", "methodCalledByJni,msg:" + msgFromJni);
}
2.在test.cpp中添加方法来调用 Java方法
void callJavaMethod(JNIEnv *env,jobject thiz){
jclass clazz = env->FindClass("com/xupt/will/ndktest/MainActivity");
if(clazz == NULL){
printf("find class MainActivity error");
return;
}
jmethodID id = env->GetStaticMethodID(clazz,"methodCalledByJni","(Ljava/lang/String;)V");
if(id == NULL){
printf("find method methodCalledByJni error");
}
jstring msg = env->NewStringUTF("msg send by callJavaMethod in test.cpp");
env->CallStaticVoidMethod(clazz,id,msg);
}
3.调用调用Java方法的方法
jstring Java_com_xupt_will_ndktest_MainActivity_get(JNIEnv *env,jobject thiz){
printf("invoke get from C++\n");
callJavaMethod(env,thiz);
return env->NewStringUTF("Hello from JNI in jni-test.so !");
}
4.查看结果
最后结果如下图所示。