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 <android/log.h>#include <jni.h>#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 <unistd.h>#include <stdio.h>#include <stdlib.h>#include <android/log.h>#include "logger.h"#include <jni.h>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 = (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 原創,轉載著名出處,謝謝。