是否需单独Native函数库加载含main函数的库?技术咨询
解答你的SDL Android库加载与main函数执行问题
首先明确说:不需要单独的native函数库来加载包含main函数的库,你当前把业务逻辑(含SDL_main)编译到main.so的思路是符合SDL for Android的标准实践的,但代码实现里的细节错误导致了应用无反应、日志看不到的问题。下面一步步拆解问题和解决方案:
1. 核心问题:你的nativeRunMain函数陷入了无限递归
你写的JNI函数代码里,直接硬编码调用了自身:
JNIEXPORT int JNICALL Java_org_libsdl_app_SDLActivity_nativeRunMain(jstring library, jstring function, jobject array) { return Java_org_libsdl_app_SDLActivity_nativeRunMain("libmain.so", "SDL_main", NULL); }
这会导致函数无限调用自己,程序直接卡死,根本没机会执行真正的SDL_main入口。正确的做法应该是通过动态符号查找,加载main.so并调用其中的SDL_main:
#include <jni.h> #include <dlfcn.h> #include <android/log.h> #define LOG_TAG "SDL" #define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__) #define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__) JNIEXPORT int JNICALL Java_org_libsdl_app_SDLActivity_nativeRunMain(JNIEnv* env, jobject thiz, jstring library, jstring function, jobject array) { // 1. 获取库路径的UTF-8字符串 const char* libPath = (*env)->GetStringUTFChars(env, library, NULL); if (!libPath) { LOGE("Failed to get library path string"); return -1; } // 2. 动态加载main.so void* libHandle = dlopen(libPath, RTLD_NOW); if (!libHandle) { LOGE("dlopen %s failed: %s", libPath, dlerror()); (*env)->ReleaseStringUTFChars(env, library, libPath); return -1; } // 3. 获取SDL_main函数指针 const char* funcName = (*env)->GetStringUTFChars(env, function, NULL); if (!funcName) { LOGE("Failed to get function name string"); dlclose(libHandle); (*env)->ReleaseStringUTFChars(env, library, libPath); return -1; } typedef int (*SDLMainFunc)(int, char**); SDLMainFunc sdlMain = (SDLMainFunc)dlsym(libHandle, funcName); if (!sdlMain) { LOGE("dlsym %s failed: %s", funcName, dlerror()); dlclose(libHandle); (*env)->ReleaseStringUTFChars(env, library, libPath); (*env)->ReleaseStringUTFChars(env, function, funcName); return -1; } // 4. 执行SDL_main(Android环境下通常不需要传参数,传0和NULL即可) int result = sdlMain(0, NULL); // 5. 释放资源 dlclose(libHandle); (*env)->ReleaseStringUTFChars(env, library, libPath); (*env)->ReleaseStringUTFChars(env, function, funcName); return result; }
2. 库加载顺序的正确性
你当前的getLibraries返回顺序:
protected String[] getLibraries() { return new String[] { "SDL2", "hidapi", "native", "main" }; }
这个顺序是合理的——先加载main.so依赖的基础库(SDL2、hidapi等),再加载业务库main.so,只要编译时main.so正确链接了这些依赖库,就不会有问题。
3. 为什么看不到log_android的输出?
先解决上面的递归问题后,再按以下步骤排查日志:
- SDL默认的Android日志标签是
SDL,可以用adb命令过滤查看:adb logcat SDL:V *:S - 确保编译SDL时开启了日志功能:编译SDL时要定义
SDL_LOGGING相关宏(官方SDL Android模板默认已开启)。 - 检查
main.so是否正确包含了SDL_main的实现,可以用nm工具查看符号:
如果能输出对应的符号,说明arm-linux-androideabi-nm -D libmain.so | grep SDL_mainSDL_main存在。
4. 包含main函数库的最佳实践
在SDL for Android的生态里,把业务逻辑(含SDL_main)编译到main.so,通过SDLActivity的JNI接口启动是标准做法,不需要额外的加载库。你可以参考官方的SDL Android模板,复用其已经验证过的nativeRunMain实现,避免自己踩坑。
内容的提问来源于stack exchange,提问作者rafal1137
相关产品推荐
相关产品推荐

