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"

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 у відповідних підкаталогах у jniLibs, як тут: github.com/Ph1b/MaterialAudiobookPlayer/tree/master/audiobook/…
Paul Woitaschek

Відповіді:


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|...), але я бачу, що ви використовуєте затемнення.

  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.


3
Чудовий чоловік, дякую! Я використовую Android Studio, і мої збірки jni копіювались у бібліотеки замість jniLibs.
Луїс,

4
Ця остання примітка про необхідність повного набору була для мене вирішальною. Це була моя проблема, дякую!
Бен Тренгрове

Для 7розділу: ви маєте на увазі, що .so може бути змінено з файлу .apk після встановлення на пристрій? Якщо так, чи є можливість, що система може зіпсувати файл .so?
джаятубі

5
Чудово! У моєму дуже дивному випадку я використовував сторонній набір бібліотек (OpenCV - у папці armeabi ), і ці бібліотеки перестали завантажуватися, коли я додав іншу сторонній бібліотеку через Gradle. Виявляється, друга бібліотека не підтримує ARMv5 або 6, і включивши її, мої бібліотеки OpenCV стали невидимими (хоча насправді там були ). Ваша думка щодо повного набору дала мені підказку - перейменування папки armeabi та її виклик armeabi-v7a вирішило проблему (оскільки я зараз не підтримую ARM 5 або 6 ...). Зла проблема !!
Мете

1
Інший спосіб знайти, куди покласти файл lib (* .so) - це запустити програму та роздрукувати nativeLibraryDir за допомогою: System.out.println (getApplicationContext (). GetApplicationInfo (). NativeLibraryDir), ім'я каталогу також буде забезпечити вас ABI.
Девід Раука,

20

У gradle, після копіювання всіх папок файлів в libs/

jniLibs.srcDirs = ['libs']

Додавання вище рядки sourceSetsв build.gradleфайлі працювало. Більше нічого не працювало.


2
чи "sourceSets" знаходиться у файлі build.gradle?
Ашана. Яколь,

12

Ви використовуєте gradle? Якщо так, поставте.so файл у<project>/src/main/jniLibs/armeabi/

Сподіваюся, це допоможе.


ні, я не використовую gradle, я використовую eclipse + maven
user842225

12

У моєму випадку я повинен виключити компіляцію джерел за допомогою gradle та встановити шлях libs

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'
        }
   }
}

а що, якщо моя програма i в eclipse? Ця проблема виходить, коли я переношу ту саму спеціальну програму з 6 на 9
Тінь

6

Для довідки, у мене було це повідомлення про помилку, і рішення було в тому, що коли ви вказуєте бібліотеку, ви пропускаєте 'lib' спереду і '.so' з кінця.

Отже, якщо у вас є файл libmyfablib.so, вам потрібно зателефонувати:

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

Заглянувши в apk, встановивши / видаливши та спробувавши всілякі складні рішення, я не міг побачити просту проблему, яка стояла прямо перед моїм обличчям!


Це було все. З якоїсь невідомої причини Android не встановлює бібліотеки, чиє ім’я файлу не починається з 'lib', навіть якщо вони присутні в пакеті. Йди до фігури ...
Джордж Ю.

Де я можу це перевірити в проекті? Я маю на увазі, де я можу знайти цей рядок System.loadLibraryу коді
aleksandrbel

Дякую. Це допомогло!
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розділу включення :

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каталозі.


Лише в кінці розділу.
Олексій

2

Ви можете просто змінити ABI для використання старих збірок:

defaultConfig {
    ...

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

Вам також слід використовувати застарілий NDK, додавши цей рядок до gradle.properties:

android.useDeprecatedNdk=true

0

будь-ласка, додайте всю підтримку

app / build.gradle

ndk {
        moduleName "serial_port"
        ldLibs "log", "z", "m"
        abiFilters "arm64-v8a","armeabi", "armeabi-v7a", "x86","x86_64","mips","mips64"
}

app \ 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. Коли я це робив, це добре працювало.
Лев 耿

-1

З мого досвіду, у мобільному телефоні armeabi-v7a, коли в apk присутні як каталоги armeabi, так і armeabi-v7a, файли .so в каталозі armeabi не будуть пов’язані, хоча файли .so в armeabi БУДУть зв’язані в той самий мобільний Armeabi-V7a, якщо Armeabi-V7a відсутній.


-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 про попередньо побудовану версію

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.