Не удается загрузить собственную общую библиотеку с зависимостями в приложении native activity
В моем приложении для Android у меня есть 4 библиотеки:
libTemplate.so
depends on libPorkholt.so
libPorkholt.so
depends on libpng15.so
depends on liblua.so
depends on libopenal.so
libpng15.so
liblua.so
libopenal.so
Если я пишу небольшой исполняемый файл командной строки, который связывается с libTemplate и вручную вызывает ANativeActivity_onCreate, он связывается и работает нормально (если я указываю LD_LIBRARY_PATH на /data/data/com.mycompany.Template / lib)
Если я запускаю мое приложение, я получаю это очень полезное сообщение об ошибке:
E/AndroidRuntime(13214): java.lang.RuntimeException: Unable to start activity ComponentInfo{com.mycompany.Template/android.app.NativeActivity}: java.lang.IllegalArgumentException: Unable to load native library: /data/data/com.mycompany.Template/lib/libTemplate.so
Он даже не входит в ANativeActivity_onCreate, поэтому я только предполагаю, что это имеет какое-то отношение к связывание
Я должен, вероятно, упомянуть, что я использую CMake с этим скриптом:http://code.google.com/p/android-cmake/ построить библиотеки самостоятельно (без ndk-build). Мне удалось скомпилировать образец native-activity с ним, поэтому я знаю, что он работает.
кроме того, я убедился, что никакая библиотека не содержит номер версии в своем soname
мой манифест:
<?xml version="1.0" encoding="utf-8"?>
<!-- BEGIN_INCLUDE(manifest) -->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.mycompany.Template"
android:versionCode="1"
android:versionName="1.0">
<!-- This is the platform API where NativeActivity was introduced. -->
<uses-sdk android:minSdkVersion="9" />
<!-- This .apk has no Java code itself, so set hasCode to false. -->
<application android:label="Template Porkholt project" android:hasCode="false">
<!-- Our activity is the built-in NativeActivity framework class.
This will take care of integrating with our NDK code. -->
<activity android:name="android.app.NativeActivity"
android:label="Template Porkholt project"
android:configChanges="orientation|keyboardHidden">
<!-- Tell NativeActivity the name of or .so -->
<meta-data android:name="android.app.lib_name"
android:value="Template" />
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
<!-- END_INCLUDE(manifest) -->
4 ответов
поскольку, по-видимому, Android недостаточно умен, чтобы правильно установить LD_LIBRARY_PATH, мне удалось решить мою проблему, создав небольшую библиотеку загрузчика, которая вручную загружает фактическую активность. Вот код:
#include <android/native_activity.h>
#include <android/log.h>
#include <dlfcn.h>
#include <errno.h>
#include <stdlib.h>
#define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, "Porkholt", __VA_ARGS__))
#define LOGE(...) ((void)__android_log_print(ANDROID_LOG_ERROR, "Porkholt", __VA_ARGS__))
#define LIB_PATH "/data/data/@PH_BUNDLE_ID@/lib/"
void * load_lib(const char * l)
{
void * handle = dlopen(l, RTLD_NOW | RTLD_GLOBAL);
if (!handle)
{
LOGE("dlopen(\"%s\"): %s", l, strerror(errno));
exit(1);
}
return handle;
}
void ANativeActivity_onCreate(ANativeActivity * app, void * ud, size_t udsize)
{
LOGI("Loaded boostrap");
load_lib(LIB_PATH "libpng15.so");
load_lib(LIB_PATH "liblua.so");
load_lib(LIB_PATH "libopenal.so");
load_lib(LIB_PATH "libPorkholt.so");
void (*main)(ANativeActivity*, void*, size_t) = dlsym(load_lib(LIB_PATH "lib@PH_APP_TARGET@.so"), "ANativeActivity_onCreate");
if (!main)
{
LOGE("undefined symbol ANativeActivity_onCreate");
exit(1);
}
main(app, ud, udsize);
}
Я не думаю, что Android будет автоматически загружать библиотеки, отличные от указанных в манифесте, поэтому вы должны создать "фиктивный" класс Java для загрузки внешних зависимостей, он должен содержать:
static {
System.loadLibrary("openal");
System.loadLibrary("lua");
System.loadLibrary("png15");
System.loadLibrary("Porkholt");
System.loadLibrary("Template");
}
поскольку этот раздел является статическим, он будет выполняться при загрузке класса, даже если его методы не вызываются.
это больше не влияет на API 24+ (см. исправление фреймворка здесь). Однако, если вам нужно поддерживать более старые версии, расширьте NativeActivity
, вместо этого обратитесь к своему расширению в файле манифеста и добавьте static
блок упомянул в ответ Sdra как временное решение.
Ваша активность, вероятно, имеет статический конструктор, который вызывает System.Загрузить ("libTemplate.Итак"). Он должен загружать другие библиотеки в соответствии с порядком зависимостей.