System.loadLibrary (…) не смог найти родную библиотеку в моем случае

91

Я хочу использовать существующую собственную библиотеку из другого проекта 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)

==== ОБНОВЛЕНИЕ =====

Я также попытался создать папку 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"
user842225
источник
3
Вы ставите библиотеку прямо под libs/? Вероятно, вам нужно создать один подкаталог для каждого целевого ABI, который вы хотите поддерживать (armeabi, armeabi-v7a, x86, mips и т. Д.), И поместить соответствующий файл .so в каждый подкаталог (т. Е. Файл .so, созданный для armeabi, входит libs/armeabi/, так далее).
Майкл
@Michael, я просто пропустил это в своем посте, я на самом деле поместил его в libs / armeabi /
user842225
Убедитесь, что libcalculate.so действительно улавливается процессом упаковки - попробуйте, например unzip -l package.apk, или переименуйте apk в .zip и откройте его в каком-нибудь приложении. Если его там нет, значит, что-то не так с его упаковкой (заметила ли ваша среда IDE, что папка есть, нужно ли обновить проект?).
mstorsjo
@mstorsjo, я распаковал apk-пакет, в разделе lib / есть libcalculate.so
user842225
1
вам не нужно иметь Android.mk или какие-либо файлы, связанные с компиляцией. Просто поместите файлы so в соответствующие подкаталоги jniLib, как здесь: github.com/Ph1b/MaterialAudiobookPlayer/tree/master/audiobook/…
Пол Войташек

Ответы:

177

Чтобы устранить первопричину (и, возможно, решить вашу проблему одновременно), вот что вы можете сделать:

  1. Удалите папку jni и все файлы .mk . Ни они, ни NDK не нужны, если вы ничего не компилируете.

  2. Скопируйте ваш libcalculate.soфайл внутрь <project>/libs/(armeabi|armeabi-v7a|x86|...). При использовании Android Studio да, <project>/app/src/main/jniLibs/(armeabi|armeabi-v7a|x86|...)но я вижу, что вы используете eclipse.

  3. Создайте APK и откройте его как zip-файл , чтобы убедиться, что ваш libcalculate.soфайл находится внутри lib / (armeabi | armeabi-v7a | x86 | ...) .

  4. Удалите и установите ваше приложение

  5. Запустить пакет пакетов dumpsys | grep yourpackagename, чтобы получить nativeLibraryPath или legacyNativeLibraryDir вашего приложения.

  6. Запустите команду ls для используемого вами nativeLibraryPath или для legacyNativeLibraryDir / armeabi , чтобы проверить, действительно ли существует ваш libcalculate.so.

  7. Если он есть, проверьте, не был ли он изменен из исходного файла 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 . В зависимости от того, на какие архитектуры вы нацеливаетесь и для которых были скомпилированы ваши библиотеки.

Также обратите внимание, что библиотеки не смешиваются между каталогами CPU_ABI: вам нужен полный набор того, что вы используете, библиотека, которая находится внутри папки armeabi , не будет установлена ​​на устройстве armeabi-v7a, если внутри armeabi есть какие-либо библиотеки Папка -v7a из APK.

ph0b
источник
3
Офигенный мужик, спасибо! Я использую Android Studio, и мои сборки jni копировались в библиотеки вместо jniLibs.
Луис
4
Последнее замечание о необходимом полном наборе было для меня решающим. Это была моя проблема, спасибо!
Бен Тренгроув,
Что касается 7раздела: вы имеете в виду, что .so может быть изменен из APK после того, как он был установлен на устройстве? Если да, есть ли вероятность, что система испортит файл .so?
jayatubi 03
5
Замечательно! В моем очень странном случае я использовал сторонний набор библиотек (OpenCV - в папке armeabi ), и эти библиотеки перестали загружаться, когда я добавил другую стороннюю библиотеку через Gradle. Оказывается, вторая библиотека не поддерживает ARMv5 или 6, и, включив ее, мои библиотеки OpenCV стали невидимыми (хотя на самом деле они там были ). Ваше мнение о полном наборе дало мне ключ к разгадке - переименование папки armeabi и ее вызов armeabi-v7a устранили проблему (поскольку теперь я не поддерживаю ARM 5 или 6 ...). Злая проблема !!
Mete
1
Другой способ найти, где разместить ваш файл библиотеки (* .so), - запустить ваше приложение и распечатать nativeLibraryDir, используя: System.out.println (getApplicationContext (). GetApplicationInfo (). NativeLibraryDir), имя каталога также будет предоставить вам ABI.
Дэвид Раука,
20

В gradle после копирования всех папок с файлами в libs/

jniLibs.srcDirs = ['libs']

Добавление указанной выше строки sourceSetsв build.gradleфайл сработало. Больше ничего не работало.

Мукунд Мураликришнан
источник
2
были ли "sourceSets" расположены в файле build.gradle?
Ashana.Jackol
12

Вы используете Gradle? Если да, поместите .soфайл в<project>/src/main/jniLibs/armeabi/

Я надеюсь, что это помогает.

Ассаф Гамлиэль
источник
нет, я не использую gradle, я использую eclipse + maven
user842225
12

В моем случае я должен исключить компиляцию источников с помощью gradle и установить путь к библиотекам

android {

    ...
    sourceSets {
        ...
        main.jni.srcDirs = []
        main.jniLibs.srcDirs = ['libs']
    }
....
Давид Дрозд
источник
это тоже решило для меня, и я добавил файлы armeabi в папки armeabi-v7a и x86, но я не уверен, было ли это необходимо.
dokam_scotland
8

Причина этой ошибки в том, что существует несоответствие ABI между вашим приложением и собственной библиотекой, с которой вы связались. Другими словами, ваше приложение и ваше .soнацелены на разные ABI.

если вы создаете свое приложение с использованием последних шаблонов Android Studio, вероятно, оно нацелено на, arm64-v8aно ваше .soможет быть нацелено, armeabi-v7aнапример.

Есть 2 способа решить эту проблему:

  1. создавайте собственные библиотеки для каждого ABI, поддерживаемого вашим приложением.
  2. измените свое приложение, чтобы настроить таргетинг на более старый ABI, на котором вы .soпостроили.

Вариант 2 грязный, но я думаю, что вас, вероятно, больше интересуют:

измените свое приложение build.gradle

android {
    defaultConfig {
        ...
        ndk {
            abiFilters 'armeabi-v7a'
        }
   }
}
Wdanxna
источник
что, если мое приложение находится в затмении? Эта проблема возникает, когда я переношу одно и то же настроенное приложение с 6 на 9.
Shadow
6

Для справки, у меня было это сообщение об ошибке, и решение заключалось в том, что когда вы указываете библиотеку, вы пропускаете «lib» спереди и «.so» с конца.

Итак, если у вас есть файл libmyfablib.so, вам нужно вызвать:

   System.loadLibrary("myfablib"); // this loads the file 'libmyfablib.so' 

Посмотрев в apk, установив / деинсталлировав и попробовав всевозможные сложные решения, я не увидел простую проблему, которая стояла прямо перед моим лицом!

Энди Кроувел
источник
Вот и все. По какой-то неизвестной причине Android не устанавливает библиотеки, имя файла которых не начинается с «lib», даже если они присутствуют в пакете.
Джордж Ю.
Где я могу это проверить в проекте? Я имею в виду, где я могу найти эту строчку System.loadLibraryв коде
александрбель
Спасибо. Это помогло!
Riskhan
5

Это обновление 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;
}
АлгебраЗима
источник
4

Попробуйте позвонить в свою библиотеку после PREBUILT_SHARED_LIBRARYраздела include :

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каталоге.

Alex
источник
Только в конце раздела.
Alex
2

Вы можете просто изменить ABI, чтобы использовать более старые сборки:

defaultConfig {
    ...

    ndk {
        abiFilters 'armeabi-v7a'
    }
    ...
}

Вы также должны использовать устаревший NDK, добавив эту строку в gradle.properties:

android.useDeprecatedNdk=true
Резам
источник
0

пожалуйста, добавьте всю поддержку

приложение / 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
Лев 耿
источник
1
Не могли бы вы уточнить, что делать?
EFrank
Файл .so в вашем проекте. Вы должны поддерживать arm64-v8a armeabi armeabi-v7a x86 x86_64 mips mips64. Когда я это делал, это работало хорошо.
Lion 耿
-1

По моему опыту, на мобильном устройстве armeabi-v7a, когда каталоги armeabi и armeabi-v7a присутствуют в apk, файлы .so в каталоге armeabi не будут связаны, хотя файлы .so в armeabi БУДУТ связаны в папке тот же armeabi-v7a mobile, если armeabi-v7a нет.

loopscn
источник
-1

на самом деле вы не можете просто поместить файл .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 о сборке

Янньшу
источник