实现功能
l 实现 java/C互相调用 android端java调用LibMain 进而执行C语言 并且传入字符数组
l C语言回调java Natives类的OnMessage方法打印消息,实现一个日志打印功能
l 通过本次NDK学习,掌握NDK开发环境的配置、C语言的编译成.so库
Android java层代码
Natives类:
public class Natives { /*** * 原生库主入口 * @param argv * @return */ public static native int LibMain(String []argv); /** * C语言调用实现日志打印 * @param text * @param level */ private static void OnMessage(String text,int level) { System.out.println("OnMessage text :"+text+" level="+level); } |
该类只是声明一个原生方法nt LibMain(String[]argv)供远程层调用。并且一个打印消息的方法,用于远程层调用,可以打印日志,用于原生层的调试。该类通过javah –jni com.flying.NDKTest1.Natives.java 能够生成头文件。
MainActiity类
public class MainActivity extends Activity {
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); String argv[]={"MyLib","arg1","arg2"}; try { Natives.LibMain(argv); } catch(Exception e) { e.printStackTrace(); } }
static{ System.loadLibrary("NDKTest1"); //加载.so库 }
} |
原生层代码
Natives生成的头文件
#include <jni.h> /* Header for class com_flying_ndktest1_Natives */
#ifndef _Included_com_flying_ndktest1_Natives #define _Included_com_flying_ndktest1_Natives #ifdef __cplusplus extern "C" { #endif /* * Class: com_flying_ndktest1_Natives * Method: LibMain * Signature: ([Ljava/lang/String;)I */ JNIEXPORT jint JNICALL Java_com_flying_ndktest1_Natives_LibMain (JNIEnv *, jclass, jobjectArray);
#ifdef __cplusplus } #endif #endif |
Lib.c
#include "com_flying_ndktest1_Natives.h" #include <stdio.h> #include <stdlib.h> #define CB_CLASS "com_flying_ndktest1_Natives"
/** * OnMessage 回调方法 */ #define CB_CLASS_CB "OnMessage" #define CB_CLASS_MSG_SIG "(Ljava/lang/String;I)v"
int lib_main(int argc ,char **argv);
const int getArrayLen(JNIEnv *env,jobjectArray jarray);
void jni_printf(char *format,...);
static JavaVM *g_VM;
static jclass jNativesCls;
/* * Class: com_flying_ndktest1_Natives * Method: LibMain * Signature: ([Ljava/lang/String;)I */ JNIEXPORT jint JNICALL Java_com_flying_ndktest1_Natives_LibMain (JNIEnv * env, jclass class, jobjectArray jargv) { (*env)->GetJavaVM(env,&g_VM);
jsize clen=getArrayLen(env,jargv);
char *args[(int)clen];
int i; jstring jrow;
for(i=0;i<clen;i++) { jrow=(jstring)(*env)->GetObjectArrayElement(env,jargv,i); const char *row=(*env)->GetStringUTFChars(env,jrow,0);
args[i]=malloc(strlen(row)+1); strcpy(args[i],row);
jni_printf("Main argv[%d]=%s",i,args[i]); //打印args参数对应的字符串
(*env)->ReleaseStringUTFChars(env,jrow,row); //释放java字符串jrow
}
//加载com_flying_ndktest1_Natives类
jNativesCls=(*env)->FindClass(env,CB_CLASS); if(jNativesCls==0) { jni_printf("Unable to find class %s",CB_CLASS); return -1; } lib_main(clen,args); return 0;
} /** * 向java层返回一个字符串 */ jmethodID mSendStr; static void jni_send_str(const char *text,int level) { JNIEnv *env; if(!g_VM) { printf("I_JNI_NOVM:%s\n",text); return ; } (*g_VM)->AttachCurrentThread(g_VM,(void **)&env,NULL); if(!jNativesCls) { jNativesCls=(*env)->FindClass(env,CB_CLASS); if(jNativesCls==0) { printf("Unable to find class %s\n",CB_CLASS); return ; } } if(!mSendStr) { mSendStr=(*env)->GetStaticMethodID(env,jNativesCls,CB_CLASS_CB,CB_CLASS_MSG_SIG);
} if(mSendStr) { (*env)->CallStaticVoidMethod(env,jNativesCls,mSendStr,(*env)->NewStringUTF(env,text),(jint) level);
}else { printf("Unable to find method :%s,signature :%s \n",CB_CLASS_CB,CB_CLASS_MSG_SIG);
} }
void jni_printf(char *format,...) { va_list argptr; static char string[1024]; va_start(argptr,format); vsprintf(string,format,argptr); va_end(argptr); jni_send_str(string,0); }
const int getArrayLen(JNIEnv *env,jobjectArray jarray) { return (*env)->GetArrayLength(env,jarray); }
int lib_main(int argc,char **argv) { int i; jni_printf("Enteing LIB MAIN"); for(i=0;i<argc;i++) { jni_printf("LIB MAIN argv[%d]=%s",i,argv[i]); } return 0; } 至此,完成了java c语言的互掉,最主要的是实现了原生层日志打印的功能,这个功能可以为今后开发提供轻量级的日志调试功能!! |