Загрузка нескольких общих библиотек во время выполнения не работает в Android
Я использую cmake для создания моих общих библиотек в Android Studio. Библиотеки создаются и связываются правильно, и я могу видеть все свои библиотеки в Apk в lib/armeabi-v7a.
Библиотеки связаны следующим образом:
- Lib1
- Lib2
- Lib3
- Lib4
- Lib5
- Lib3
- Lib2
Я загрузил свой Lib1, позвонив System.loadLibrary("lib1");
Я могу звонить в Lib1, но как только Lib1 пытается получить доступ к Lib2, я получаю сообщение о том, что Lib2 не был загружен.
Затем я решил, что мне нужно загрузить другие библиотеки, поэтому я сделал следующие вызовы, но в итоге получил то же самое распространенное сообщение "Lib2 не загружен".
System.loadLibrary("lib5");
System.loadLibrary("lib4");
System.loadLibrary("lib3");
System.loadLibrary("lib2");
System.loadLibrary("lib1");
Почему Lib1 не сможет вызвать Lib2? Распакованы ли дополнительные общие библиотеки в месте, которое вызывает сбой загрузки библиотеки?
Я хотел бы отметить, что мои библиотеки правильно загружались до перехода на использование cmake. Я полагаю, что ранее я вручную компилировал свои библиотеки и сохранял их в каталогах /jniLibs и /assets в своем проекте Android Studio, но это было некоторое время назад, поэтому моя память не совсем ясна в деталях.
1 ответ
Поскольку ваши изменения вступают в силу, я думаю, что это не случайность, а установка двоичных файлов в неправильное место. (Я сам иногда загружал в jniLibs/armeabi-v7a
потом понял, что я тестирую 64-битный APK, который опирается на jniLibs/arm64-v8a
, Или наоборот при установке apk с двойной архитектурой на 32-разрядное устройство Android.)
Я думаю, что мы можем исключить неразрешенный символ также во время загрузки, потому что он обычно говорит вам об этом в adb logcat
Я вспоминаю, что когда я видел эту проблему в прошлом, обычно это была проблема с сонам lib2. Хотя ПК Linux может работать с чем-то вроде liblib2.so.1
Android, кажется, требует, чтобы все сонамы заканчивались .so
Чтобы проверить soname на lib2, запустите readelf -a liblib2.so
, Если он кажется неправильным, как я описал, переделайте свою сборку NDK и убедитесь, что -Wl,-soname,liblib2.so
добавляется во время ссылки.
Кроме того, запустить readelf -a liblib1.so
и убедитесь, что его ссылка на liblib2.so использует новое имя сына, например (NEEDED) Shared Library: [liblib2.so]
, Вам также может понадобиться повторно связать liblib1.so.
Я хотел бы отметить, что мои библиотеки правильно загружались до перехода на использование cmake.
Я предполагаю, что CMake использовался для этапа сборки NDK, а не Java, что могло бы объяснить изменение сонама.
Примечание: немного сбивает с толку, что вы добавляете дополнительную "lib" в имена каждой библиотеки. Было бы легче общаться, если бы вы использовали пример, который сделал System.loadLibrary("1")
, System.loadLibrary("2")
В зависимости от вашего файла Gradle это может быть связано с тем, что AS выполняет только последний файл cmake, указанный в externalNativeBuild
заявление.
Вы можете заглянуть внутрь своего APK, чтобы проверить, какие библиотеки на самом деле собираются и собираются. Если вы измените расширение apk на.zip, то разархивируйте и посмотрите на lib
каталог, вы найдете список каталогов сборки, которые содержат файлы.so. Если вы не видите.so, соответствующий System.loadLibrary(<libName>);
позвоните, вы получите ошибки во время выполнения.
Проблема, которая вызвала у меня похожую проблему , заключается в том, что я пытался использовать несколько файлов cmake, соответствующих каждой библиотеке, которую я хотел включить, используя externalNativeBuild
в файле сборки моего приложения Gradle вот так:
externalNativeBuild {
cmake {
path "CMakeLists1.txt"
path "CMakeLists2.txt"
}
}
И я заметил, что выполняется только последний CMakeLists.txt, указанный в этом операторе. Это привело только к одному.so файлу для вывода на мои APK lib
каталог, а не оба, как я хотел. Я считаю, что намерение AS состоит в том, чтобы ссылаться только на один файл cmake в этом утверждении. Если вы ссылаетесь больше, как я, вероятно, он только строит последний, так что остальные (в вашем случае, все, что после "lib1") будут отсутствовать.