關於如何移植SDL2.0到安卓上面來參考我的上一篇文章:[原]零基礎學習SDL開發之移植SDL2.0到Android
在一篇文章我們主要使用SDL2.0來加載一張BMP圖來渲染顯示。
博主的開發環境:Ubuntu 14.04 64位,Eclipse + CDT + ADT+NDK
博主曾經自己使用NDK編譯出了libSDL2.so,然后使用共享庫的方式來調用libSDL2中的函數,結果發現SDL\src\core\android\SDL_android.c 這個jni函數寫的實在是不夠自己另外做移植用,與org.libsdl.app.SDLActivity耦合太緊密了。如果想使用共享庫的方式去調用SDL中的函數,最好自己去寫JNI注冊與調用函數實現。
一、導入SDL源碼
還是把SDL源碼中的android-project工程導入到Eclipse中來,進入jni文件夾,新建一個SDL文件,將SDL2-2.0.3\src 、SDL2-2.0.3\include、SDL2-2.0.3\Android.mk文件拷貝到android-project\jni\SDL\中。
在android-project中新建Android.mk,內容如下:
include $(call all-subdir-makefiles)
在android-project中新建Application.mk,內容如下:
APP_ABI := armeabi APP_PLATFORM := android-9
二、新建功能模塊
在jni下新建一文件夾src,新建SDL_logger.h,用來使用android中的log來打印日志,內容如下:
/* * log.h * * Created on: Aug 8, 2014 * Author: clarck */ #ifndef LOG_H_ #define LOG_H_ #include <android/log.h> #define APPNAME "SDL_Lesson" #define LOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, APPNAME, __VA_ARGS__) #define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG , APPNAME, __VA_ARGS__) #define LOGI(...) __android_log_print(ANDROID_LOG_INFO , APPNAME, __VA_ARGS__) #define LOGW(...) __android_log_print(ANDROID_LOG_WARN , APPNAME, __VA_ARGS__) #define LOGE(...) __android_log_print(ANDROID_LOG_ERROR , APPNAME, __VA_ARGS__) #endif /* LOG_H_ */
新建SDL_lesson.c,用來使用SDL window的創建,加載bmp,渲染圖片的功能,具體內容:
/* * SDL_lesson.c * * Created on: Aug 8, 2014 * Author: clarck */ #ifdef __ANDROID__ #include <jni.h> #include "SDL.h" #include "SDL_log.h" #include "SDL_main.h" //The attributes of the screen const int SCREEN_WIDTH = 640; const int SCREEN_HEIGHT = 480; const int SCREEN_BPP = 32; struct SDL_Window *window = NULL; struct SDL_Renderer *render = NULL; struct SDL_Surface *bmp = NULL; struct SDL_Texture *texture = NULL; int main(int argc, char *argv[]) { char *filepath = argv[1]; LOGI("natvie_SDL %s", filepath); if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER) == -1) { LOGE("SDL_Init failed %s", SDL_GetError()); } LOGI("SDL_CreateWindow"); window = SDL_CreateWindow("Hello World!", 100, 100, 640, 480, SDL_WINDOW_SHOWN); if (window == NULL) { LOGE("SDL_CreateWindow failed %s", SDL_GetError()); } LOGI("SDL_CreateRenderer"); render = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC); if (render == NULL) { LOGE("SDL_CreateRenderer failed %s", SDL_GetError()); } bmp = SDL_LoadBMP(filepath); if (bmp == NULL) { LOGE("SDL_LoadBMP failed: %s", SDL_GetError()); } texture = SDL_CreateTextureFromSurface(render, bmp); SDL_FreeSurface(bmp); SDL_RenderClear(render); SDL_RenderCopy(render, texture, NULL, NULL); SDL_RenderPresent(render); SDL_Delay(2000); SDL_DestroyTexture(texture); SDL_DestroyRenderer(render); SDL_DestroyWindow(window); //Quit SDL SDL_Quit(); return 0; } #endif /* __ANDROID__ */
在src下編寫Android.mk,用來編譯SDL_lesson.c,內容如下:
LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := main SDL_PATH := ../SDL LOCAL_C_INCLUDES := $(LOCAL_PATH)/$(SDL_PATH)/include # Add your application source files here... LOCAL_SRC_FILES := $(SDL_PATH)/src/main/android/SDL_android_main.c \ SDL_Lesson.c LOCAL_SHARED_LIBRARIES := SDL2 LOCAL_LDLIBS := -lGLESv1_CM -lGLESv2 -llog include $(BUILD_SHARED_LIBRARY)
三、修改SDLActivity、SDL\src\main\SDL_android_main.c以便接受傳入的參數:
修改SDLActivity中的 SDLMain類,修改內容如下:
/** Simple nativeInit() runnable */ class SDLMain implements Runnable { @Override public void run() { // Runs SDL_main() String sdcard = Environment.getExternalStorageDirectory().getAbsolutePath(); SDLActivity.nativeInit(sdcard + File.separator + "hello.bmp"); //Log.v("SDL", "SDL thread terminated"); } }
修改SDL\src\main\SDL_android_main.c,修改如下:
/* SDL_android_main.c, placed in the public domain by Sam Lantinga 3/13/14 */ #include "../../SDL_internal.h" #ifdef __ANDROID__ /* Include the SDL main definition header */ #include "SDL_main.h" /******************************************************************************* Functions called by JNI *******************************************************************************/ #include <jni.h> /* Called before SDL_main() to initialize JNI bindings in SDL library */ extern void SDL_Android_Init(JNIEnv* env, jclass cls); char* jstringTostr(JNIEnv* env, jstring jstr) { char* pStr = NULL; jclass jstrObj = (*env)->FindClass(env, "java/lang/String"); jstring encode = (*env)->NewStringUTF(env, "utf-8"); jmethodID methodId = (*env)->GetMethodID(env, jstrObj, "getBytes", "(Ljava/lang/String;)[B"); jbyteArray byteArray = (jbyteArray) (*env)->CallObjectMethod(env, jstr, methodId, encode); jsize strLen = (*env)->GetArrayLength(env, byteArray); jbyte *jBuf = (*env)->GetByteArrayElements(env, byteArray, JNI_FALSE); if (jBuf > 0) { pStr = (char*) malloc(strLen + 1); if (!pStr) { return NULL ; } memcpy(pStr, jBuf, strLen); pStr[strLen] = 0; } (*env)->ReleaseByteArrayElements(env, byteArray, jBuf, 0); return pStr; } /* Start up the SDL app */ void Java_org_libsdl_app_SDLActivity_nativeInit(JNIEnv* env, jclass cls, jobject obj) { /* This interface could expand with ABI negotiation, calbacks, etc. */ SDL_Android_Init(env, cls); SDL_SetMainReady(); char *filePath = jstringTostr(env, obj); /* Run the application code! */ int status; char *argv[2]; argv[0] = SDL_strdup("SDL_app"); argv[1] = filePath; status = SDL_main(1, argv); /* Do not issue an exit or the whole application will terminate instead of just the SDL thread */ /* exit(status); */ } #endif /* __ANDROID__ */ /* vi: set ts=4 sw=4 expandtab: */
最后,上一張運行的截圖:

