打印log
一般调试ndk都需要log。那怎么打印log呢?
下面是打印log的方法。
#include <jni.h>
#include<android/log.h>
#define LOG_TAG "System.out.c"
#define LOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__)
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
#define LOGW(...) __android_log_print(ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__)
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)
#define LOGF(...) __android_log_print(ANDROID_LOG_FATAL, LOG_TAG, __VA_ARGS__)
这里用宏定义定义了android系统下几个log打印。__VA_ARGS__
代表宏参数...
,括号内 … 的内容原样抄写在__VA_ARGS__
的位置。
使用方法如下,在适合的地方调用该方法。
LOGD("这里打印log");
LOGI("这是来自info信息");
java调用c的函数
这里介绍的是静态注册的方法。
extern "C" {
// Data callback stuff
JavaVM* theJvm;
jobject dataCallbackObj;
jmethodID midDataCallback;
/**
* Initializes JNI interface stuff, specifically the info needed to call back into the Java
* layer when MIDI data is received.
*/
JNICALL void Java_com_slzr_ndk_NDKManager_initNative(JNIEnv * env, jobject instance) {
env->GetJavaVM(&theJvm);
// Setup the receive data callback (into Java)
jclass clsNDKManager = env->FindClass("com/slzr/ndk/NDKManager");
dataCallbackObj = env->NewGlobalRef(instance);
midDataCallback = env->GetMethodID(clsNDKManager, "onNativeMessageReceive", "([B)V");//[B
}
} // extern "C"
当JVM调用这些函数,就传递一个JNIEnv指针,一个jobject的指针,你说看到是输入参数里面有(JNIEnv * env, jobject instance)
就是这个东西了。
Java_com_slzr_ndk_NDKManager_initNative包含有了包名,类名和方法名,中间用下划线分开。由于该方法是没有返回值,所以直接用了JNICALL
,如果有返回值比如说是String返回,用JNIEXPORT jstring JNICALL
这样的形式。JNIEXPORT和JNICALL中间夹着返回值。
对应到java里面的方法是。
public native void initNative();
native 是java里面的关键字,表示地调用c语言里面的函数。
c调用java的方法
在NDK里面c调用java的方法类似于反射。
需要先获取到对应的方法名称,虚拟机等。
这个回去相关的信息的c代码。
#include <jni.h>
extern "C" {
// Data callback stuff
JavaVM* theJvm;
jobject dataCallbackObj;
jmethodID midDataCallback;
/**
* Initializes JNI interface stuff, specifically the info needed to call back into the Java
* layer when MIDI data is received.
*/
JNICALL void Java_com_slzr_ndk_NDKManager_initNative(JNIEnv * env, jobject instance) {
env->GetJavaVM(&theJvm);
// Setup the receive data callback (into Java)
jclass clsNDKManager = env->FindClass("com/slzr/ndk/NDKManager");
dataCallbackObj = env->NewGlobalRef(instance);
midDataCallback = env->GetMethodID(clsNDKManager, "onNativeMessageReceive", "([B)V");//[B
}
} // extern "C"
initNative是初始化函数,对应java里面的public native void initNative();
调用。env是java虚拟机对象,instance是Object。在这里,先获取到对应的class对象、Object对象和对应的方法。
下面的c调用java里面的方法。
// The Data Callback
extern JavaVM *theJvm; // Need this for allocating data buffer for...
extern jobject dataCallbackObj; // This is the (Java) object that implements...
extern jmethodID midDataCallback; // ...this callback routine
int soso(char *data) {
......
JNIEnv *env;
theJvm->AttachCurrentThread(&env, NULL);
if (env == NULL) {
LOGI("Error retrieving JNI Env");
}
// Allocate the Java array and fill with received data
jbyteArray ret = env->NewByteArray(strlen(data));
env->SetByteArrayRegion(ret, 0, strlen(data), (jbyte *) data);
// send it to the (Java) callback
env->CallVoidMethod(dataCallbackObj, midDataCallback, ret);
return 1;
}
这里是上面保存下来的相关参数再调用一次。jbyteArray 是转换成java里面的数组。可以在java里面写相对应的实现。
这是调用java里面的onNativeMessageReceive方法。
public void onNativeMessageReceive(final byte[] message) {
String str=null;
try {
str = new String(message, "utf-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
Log.i("NDKManager","这是来自ndkmanger的信息" + str);
}
附件:
demo源码地址