android jni 程序框架搭建
android上 jni开发 应用构建过程基本一致,下面 结合最近 在android 上实现 jni层 绘制 surfaceview 功能 阐述 带jni的apk构建过程。
apk 目录结构:
├── AndroidManifest.xml├── Android.mk├── jni│ ├── Android.mk│ ├── logger.cpp│ ├── logger.h│ ├── OnLoad.cpp│ └── SurfaceviewJni.cpp├── libs│ └── armeabi│ └── libsurfaceviewJni.so├── res│ ├── layout│ │ └── hello_activity.xml│ └── values│ └── strings.xml└── src └── com └── example └── android └── jnisurfaceview ├── JavasurfaceView.java └── JniSurfaceViewActivity.java
1. java类中 static 块 加载动态库及java层本地方法声明 :
static {
System.loadLibrary("surfaceviewJni");
}
private native void nativeSetSurface(Surface surface);
private native void nativeDraw(String path ,int width, int height);
2 . 编写 jni makefile
jni/Android.mk
#lib for jnisurfaceviewLOCAL_PATH := $(call my-dir)include $(CLEAR_VARS)LOCAL_LDLIBS := \ -lm -lstdc++ -lgcc -llogLOCAL_SRC_FILES := \OnLoad.cpp \SurfaceviewJni.cpp \ logger.cpp#LOCAL_SHARED_LIBRARIES := libsurfaceviewJniLOCAL_SYSTEM_SHARED_LIBRARIES := libc libstdc++ libutils LOCAL_MODULE := libsurfaceviewJniinclude $(BUILD_SHARED_LIBRARY)
3. 编写 apk makefile
LOCAL_PATH:= $(call my-dir)include $(CLEAR_VARS)# Only compile source java files in this apk.LOCAL_SRC_FILES := $(call all-java-files-under, src)LOCAL_PACKAGE_NAME := JniSurfaceView#LOCAL_JNI_SHARED_LIBRARIES := libsurfaceviewJni#LOCAL_PRELINK_MODULE := falseinclude $(BUILD_PACKAGE)
4. C/C++代码中绑定java层和本地接口
这里的关键点在 JNI_OnLoad 函数,java层在 load 动态库时虚拟机会首先调用动态库中的JNI_OnLoad,所以 java层接口和本地接口的绑定在JNI_OnLoad 函数中初始化即可,这也是android framework 的做法。
放在一个文件中:
OnLoad.cpp
/* * Desc: jni code for surfaceview * Author :lidp */ #include #include #include "logger.h"#define TAG_JNISURFACEVIEW "jni surfaceview test"static JavaVM *jvm = NULL;int register_jnisurfaceview(JNIEnv* env);JNJEnv* getEnv(){JNIEnv* env = NULL;if(jvm->GetEnv(void**)&env, JNI_VERSION_1_4) != JNI_OK) {return NULL;droid_log(LOG_ERROR,"failed in get jvm\n");}return env;}//this function will be called by jvm on load shared libjint JNI_OnLoad(JavaVM *vm,void* reserved){JNIEnv* env = NULL;jint ret = JNI_ERR;droid_log(LOG_DEBUG,"Jni Onload be called\n");jvm = vm;if(jvm->GetEnv((void**)&env, JNI_VERSION_1_4) != JNI_OK) {droid_log(LOG_ERROR,"failed get jvm\n");return ret;}if(register_jnisurfaceview(env) != JNI_OK)return ret;;return JNI_VERSION_1_4;}
5. 实现接口代码:
SurfaceviewJni.cpp
#include #include #include #include #include "logger.h"#include struct JavaGule {jobject jsurface;};static struct JavaGule gule;//code pase from framework jnihelp.cppstatic int jniRegisterNativeMethods(JNIEnv* env, const char* className, const JNINativeMethod* gMethods, int numMethods){ jclass clazz;droid_log(LOG_DEBUG, "register native method for class %s\n", className); clazz = env->FindClass(className); if (clazz == NULL) return -1; if (env->RegisterNatives(clazz, gMethods, numMethods) < 0) return -1; return 0;}static void jnisurfaceview_draw(JNIEnv *env, jobject obj, jstring photopath, jint w, jint h){droid_log(LOG_DEBUG, "native draw be called \n");jclass sufaceClass = env->FindClass("android/view/Surface");if(sufaceClass == NULL) {droid_log(LOG_ERROR,"Cant not find android/view/Surface class\n");return;}jfieldID surfaceID = env->GetFieldID(sufaceClass, "mSurface", "I"); if (surfaceID == NULL) { droid_log(LOG_ERROR,"Can't find Surface.mSurface"); return; }//sp surface = (Surface *)env->GetIntField(gule.jsurface, surfaceID);/*if(surface.isValid()) {} else {droid_log(LOG_ERROR, "cant get surface\n");}*/}static void jnisurfaceview_setSurface(JNIEnv *env, jobject obj, jobject javasurface){droid_log(LOG_DEBUG, "native setSurface be called \n");gule.jsurface = javasurface;}static JNINativeMethod gmethods[] = {{"nativeDraw", "(Ljava/lang/String;II)V", (void *)jnisurfaceview_draw},{"nativeSetSurface", "(Landroid/view/Surface;)V", (void*)jnisurfaceview_setSurface},};int register_jnisurfaceview(JNIEnv* env){return jniRegisterNativeMethods(env,"com/example/android/jnisurfaceview/JavasurfaceView", gmethods, sizeof(gmethods)/sizeof(gmethods[0]));}
6. ndk_build 编译 jni目录,生成动态库到 libs目录,
apk 根目录 执行 mm 生成apk.
注意:
这里本地代码用到了 ndk提供的log 接口 android/log.h 所以在makefile中要连接log动态库 用参数
LOCAL_LDLIBS := \ -lm -lstdc++ -lgcc -llog
上面的 c++代码即包含 java->c++的调用也包含 C++ -> java的反调用。
ok.
csdn lidp 原创,转载著名出处,谢谢。
更多相关文章
- Android(安卓)ListView 去除边缘阴影、选中色、拖动背景色等
- android第二行代码总结:二、UI
- Android(安卓)5.0 Phone初始化分析
- Android(安卓)5.0 Telephony关键类初始化和相互关系
- 实现底部导航栏中间凸起
- Android(安卓)蓝牙4.0代码解析
- Android版本与Linux内核版本的关系
- 【Android】Android(安卓)代码判断当前设备是否为模拟器
- android 实现 搜索保存历史记录功能