System.loadLibrary(...) не смог найти нативную библиотеку в моем случае
Я хочу использовать существующую нативную библиотеку из другого проекта Android, поэтому я просто скопировал встроенную библиотеку NDK (libcalculate.so) в мой новый проект Android. В моем новом проекте Android я создал папку libs/armeabi/
и поместите libcalculate.so там. Там нет jni / папка. Мое тестирующее устройство имеет архитектуру ARM.
В моем Java-коде я загружаю библиотеку:
static{
System.loadLibrary("calculate");
}
Когда я запускаю свой новый проект Android, я получил ошибку:
java.lang.UnsatisfiedLinkError: ...
nativeLibraryDirectories=[/vendor/lib, /system/lib]]] couldn't find "libcalculate.so"
Итак, как говорит ошибка, скопированная нативная библиотека не находится в / verdor / lib или / system / lib, как решить эту проблему в моем случае?
(Я разархивировал пакет apk, в lib / есть libcalculate.so)
==== =====UPDATE
Я также попытался создать папку jni / в корневом каталоге проекта и добавить файл Android.mk в папку jni /. Содержание Android.mk:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := libcalculate
LOCAL_SRC_FILES := libcalculate.so
include $(PREBUILT_SHARED_LIBRARY)
Затем в корне проекта я выполнил ndk-build . После этого каталоги armeabi / и armeabi-v7a/ генерируются с помощью ndk-build (с libcalculate.so внутри папки).
Затем я успешно запустил maven для сборки проекта. В окончательном пакете apk есть:
lib/armeabi/libcalculate.so
lib/armeabi-v7a/libcalculate.so
Но когда я запускаю свое приложение, выдается та же ошибка:
java.lang.UnsatisfiedLinkError: ...
nativeLibraryDirectories=[/vendor/lib, /system/lib]]] couldn't find "libcalculate.so"
14 ответов
Чтобы устранить причину (и, возможно, решить вашу проблему в то же время), вот что вы можете сделать:
Удалите папку jni и все файлы .mk. Вам не нужны ни эти, ни NDK, если вы ничего не компилируете.
Скопируйте свой
libcalculate.so
файл внутри<project>/libs/(armeabi|armeabi-v7a|x86|...)
, При использовании Android Studio это<project>/app/src/main/jniLibs/(armeabi|armeabi-v7a|x86|...)
Но я вижу, вы используете затмение.Создайте свой APK и откройте его в виде zip-файла, чтобы убедиться, что ваш
libcalculate.so
файл находится внутри lib / (armeabi | armeabi-v7a | x86 |...).Удалить и установить приложение
Запустить пакетные пакеты dumpsys | grep yourpackagename, чтобы получить nativeLibraryPath или legacyNativeLibraryDir вашего приложения.
Запустите ls на имеющейся у вас nativeLibraryPath или на legacyNativeLibraryDir / armeabi, чтобы проверить, действительно ли там есть ваш libcalculate.so.
Если он есть, проверьте, не был ли он изменен из вашего исходного файла libcalculate.so: скомпилирован ли он с правильной архитектурой, содержит ли он ожидаемые символы, есть ли пропущенные зависимости. Вы можете проанализировать libcalculate.so, используя readelf.
Чтобы проверить шаги 5-7, вы можете использовать мое приложение вместо командной строки и readelf: Native Libs Monitor
PS: легко запутаться в том, где.so файлы должны быть помещены или сгенерированы по умолчанию, вот краткая информация:
libs /CPU_ABI внутри проекта Eclipse
jniLibs/CPU_ABI внутри проекта Android Studio
JNI /CPU_ABI внутри AAR
lib /CPU_ABI внутри финального APK
внутри nativeLibraryPath приложения на устройстве <5.0 и внутри legacyNativeLibraryDir/CPU_ARCH приложения на устройстве>=5.0.
Где CPU_ABI - любой из: armeabi, armeabi-v7a, arm64-v8a, x86, x86_64, mips, mips64. В зависимости от того, на какую архитектуру вы нацеливаетесь и какие ваши библиотеки были скомпилированы.
Также обратите внимание, что библиотеки lib не смешиваются между каталогами CPU_ABI: вам нужен полный набор того, что вы используете, библиотека, находящаяся внутри папки armeabi, не будет установлена на устройстве armeabi-v7a, если внутри armeabi есть какие-либо библиотеки -v7a папка из APK.
В Gradle, после копирования всех файлов папок в libs/
jniLibs.srcDirs = ['libs']
Добавление вышеуказанной строки в sourceSets
в build.gradle
файл сработал. Ничто другое не сработало вообще.
Причиной этой ошибки является несоответствие ABI между вашим приложением и собственной библиотекой, с которой вы связаны. Другими словами, ваше приложение и ваш .so
ориентируется на разные ABI.
если вы создаете свое приложение с использованием новейших шаблонов Android Studio, оно, вероятно, нацелено на arm64-v8a
но твой .so
может быть целью armeabi-v7a
например.
Есть 2 способа решить эту проблему:
- создавайте свои собственные библиотеки для каждого ABI, поддерживаемого вашим приложением.
- изменить свое приложение, чтобы ориентироваться на более старый ABI, что ваш
.so
построен против.
Вариант 2 грязный, но я думаю, что вы, вероятно, больше заинтересованы в:
изменить ваше приложение build.gradle
android {
defaultConfig {
...
ndk {
abiFilters 'armeabi-v7a'
}
}
}
В моем случае я должен исключить компиляцию исходников по gradle и установить путь libs
android {
...
sourceSets {
...
main.jni.srcDirs = []
main.jniLibs.srcDirs = ['libs']
}
....
Вы используете Gradle? Если это так, поставьте .so
файл в <project>/src/main/jniLibs/armeabi/
Я надеюсь, что это помогает.
Для справки у меня было это сообщение об ошибке, и решение было таким: когда вы указываете библиотеку, вы пропускаете "lib" с начала и ".so" с конца.
Итак, если у вас есть файл libmyfablib.so, вам нужно вызвать:
System.loadLibrary("myfablib"); // this loads the file 'libmyfablib.so'
Посмотрев в апк, установил / удалил и перепробовал всевозможные сложные решения, я не увидел простую проблему, которая была прямо перед моим лицом!
Это обновление для Android 8.
В более ранней версии Android для собственных библиотек LoadLibrary (например, для доступа через JNI) я встроил свой собственный код для перебора ряда возможных путей к каталогам для папки lib на основе различных алгоритмов установки / обновления apk:
/data/data/<PackageName>/lib
/data/app-lib/<PackageName>-1/lib
/data/app-lib/<PackageName>-2/lib
/data/app/<PackageName>-1/lib
/data/app/<PackageName>-2/lib
Этот подход хоккейный и не будет работать для Android 8; из https://developer.android.com/about/versions/oreo/android-8.0-changes.html вы увидите, что в качестве части их изменений в "безопасности" вам теперь нужно использовать sourceDir:
"Вы больше не можете предполагать, что APK находятся в каталогах, имена которых заканчиваются на -1 или -2. Приложения должны использовать sourceDir для получения каталога, а не полагаться на формат каталога напрямую".
Исправление: sourceDir - это не способ найти ваши собственные общие библиотеки; использовать что-то вроде Протестировано для Android 4.4.4 -> 8.0
// Return Full path to the directory where native JNI libraries are stored.
private static String getNativeLibraryDir(Context context) {
ApplicationInfo appInfo = context.getApplicationInfo();
return appInfo.nativeLibraryDir;
}
Попробуйте позвонить в вашу библиотеку после включения PREBUILT_SHARED_LIBRARY
раздел:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := libcalculate
LOCAL_SRC_FILES := <PATH>/libcalculate.so
include $(PREBUILT_SHARED_LIBRARY)
#...
LOCAL_SHARED_LIBRARIES += libcalculate
Обновить:
Если вы будете использовать эту библиотеку в Java, вам нужно скомпилировать ее как общую библиотеку
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := libcalculate
LOCAL_SRC_FILES := <PATH>/libcalculate.so
include $(BUILD_SHARED_LIBRARY)
И вам нужно развернуть библиотеку в /vendor/lib
каталог.
Вы можете просто изменить ABI, чтобы использовать более старые сборки:
defaultConfig {
...
ndk {
abiFilters 'armeabi-v7a'
}
...
}
Вы также должны использовать устаревший NDK, добавив эту строку в gradle.properties
:
android.useDeprecatedNdk=true
На самом деле, вы не можете просто положить.so файл в /libs/armeabi/
и загрузить его System.loadLibrary
, Вам нужно создать файл Android.mk и объявить готовый модуль, в котором вы указываете свой файл.so в качестве источника.
Для этого поместите файл.so и файл Android.mk в jni
папка. Ваш Android.mk должен выглядеть примерно так:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := libcalculate
LOCAL_SRC_FILES := libcalculate.so
include $(PREBUILT_SHARED_LIBRARY)
Источник: Android NDK документация о сборке
defaultConfig {
ndk {
abiFilters "armeabi-v7a", "x86", "armeabi", "mips"
}
}
Просто добавьте эту строку на уровень приложения build.gradle
Пожалуйста, добавьте все поддержки
Приложение /build.gradle
ndk {
moduleName "serial_port"
ldLibs "log", "z", "m"
abiFilters "arm64-v8a","armeabi", "armeabi-v7a", "x86","x86_64","mips","mips64"
}
Приложение \ SRC \ JNI \Application.mk
APP_ABI := arm64-v8a armeabi armeabi-v7a x86 x86_64 mips mips64
В моем случае я просто удаляю неиспользуемые общие библиотеки, после чего приложение сможет найти общую библиотеку. В частности, я удаляю jniLibs/arm64-v8a/ и libs/arm64-v8a/, которые использовались в приложении ранее, и оставляю только jniLibs/armeabi-v7a и libs/armeabi-v7a, которые должны использоваться приложением.
По моему опыту, на мобильном устройстве armeabi-v7a, когда в apk присутствуют каталоги armeabi и armeabi-v7a, файлы.so в каталоге armeabi не будут связаны, хотя файлы.so в armeabi будут связаны в тот же armeabi-v7a мобильный, если armeabi-v7a нет.