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 jnisurfaceview
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_LDLIBS := \
-lm -lstdc++ -lgcc -llog
LOCAL_SRC_FILES := \
OnLoad.cpp \
SurfaceviewJni.cpp \
logger.cpp
#LOCAL_SHARED_LIBRARIES := libsurfaceviewJni
LOCAL_SYSTEM_SHARED_LIBRARIES := libc libstdc++ libutils
LOCAL_MODULE := libsurfaceviewJni
include $(BUILD_SHARED_LIBRARY)
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 := false
include $(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 lib
jint 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;
}
SurfaceviewJni.cpp
#include
#include
#include
#include
#include "logger.h"
#include
struct JavaGule {
jobject jsurface;
};
static struct JavaGule gule;
//code pase from framework jnihelp.cpp
static 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 原创,转载著名出处,谢谢。