System.loadLibrary (…) tidak dapat menemukan perpustakaan asli dalam kasus saya


91

Saya ingin menggunakan library native yang sudah ada dari project Android lain , jadi saya baru saja menyalin library yang dibuat NDK ( libcalculate.so ) ke project Android baru saya. Dalam proyek Android baru saya, saya membuat folder libs/armeabi/dan meletakkan libcalculate.so di sana. Tidak ada jni / folder. Perangkat pengujian saya memiliki arsitektur ARM.

Dalam kode java saya, saya memuat perpustakaan dengan:

  static{
    System.loadLibrary("calculate");
  }

Ketika saya menjalankan proyek android baru saya, saya mendapat kesalahan:

java.lang.UnsatisfiedLinkError:  ...
nativeLibraryDirectories=[/vendor/lib, /system/lib]]] couldn't find "libcalculate.so"

Jadi, seperti yang dikatakan kesalahan, pustaka asli yang disalin tidak ada di / verdor / lib atau / system / lib, bagaimana cara mengatasi masalah ini dalam kasus saya?

(Saya mengekstrak paket apk, di bawah lib / ada libcalculate.so)

==== UPDATE =====

Saya juga mencoba membuat folder jni / di bawah root proyek, dan menambahkan file Android.mk di bawah jni /. Konten Android.mk adalah:

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)
LOCAL_MODULE    := libcalculate
LOCAL_SRC_FILES := libcalculate.so
include $(PREBUILT_SHARED_LIBRARY)

Kemudian, di bawah project root, saya menjalankan ndk-build. Setelah itu, direktori armeabi / dan armeabi-v7a / dibuat oleh ndk-build (dengan libcalculate.so di dalam folder).

Kemudian saya menjalankan proyek maven saya dengan sukses. Dalam paket apk terakhir, ada:

lib/armeabi/libcalculate.so
lib/armeabi-v7a/libcalculate.so

Tetapi ketika saya menjalankan aplikasi saya, kesalahan yang sama muncul:

java.lang.UnsatisfiedLinkError:  ...
nativeLibraryDirectories=[/vendor/lib, /system/lib]]] couldn't find "libcalculate.so"

3
Anda meletakkan perpustakaan tepat di bawah libs/? Anda mungkin perlu membuat satu subdirektori per target ABI yang ingin Anda dukung (armeabi, armeabi-v7a, x86, mips, dll) dan menempatkan file .so yang sesuai di setiap subdirektori (yaitu file .so yang dibuat untuk armeabi masuk libs/armeabi/, dll).
Michael

@ Michael, saya baru saja melewatkannya di posting saya, saya sebenarnya meletakkannya di bawah libs / armeabi /
user842225

Periksa bahwa libcalculate.so benar-benar diambil oleh proses pengemasan - coba misalnya unzip -l package.apk, atau ganti nama apk menjadi .zip dan buka dengan beberapa aplikasi. Jika tidak ada, berarti ada yang salah dengan memaketkannya (apakah IDE Anda melihat foldernya ada di sana, apakah Anda perlu menyegarkan proyek?).
mstorsjo

@mstorsjo, saya membuka zip paket apk, di bawah lib / ada libcalculate.so
user842225

1
Anda tidak perlu memiliki Android.mk atau file terkait kompilasi. Letakkan saja file jadi di subdirektorinya yang sesuai ke jniLibs seperti di sini: github.com/Ph1b/MaterialAudiobookPlayer/tree/master/audiobook/…
Paul Woitaschek

Jawaban:


178

Untuk melakukan root (dan mungkin menyelesaikan masalah Anda dalam waktu yang sama), berikut yang dapat Anda lakukan:

  1. Hapus folder jni dan semua file .mk . Anda tidak memerlukan ini atau NDK jika Anda tidak mengompilasi apa pun.

  2. Salin libcalculate.sofile Anda di dalamnya <project>/libs/(armeabi|armeabi-v7a|x86|...). Saat menggunakan Android Studio, memang demikian <project>/app/src/main/jniLibs/(armeabi|armeabi-v7a|x86|...), tetapi saya melihat Anda menggunakan eclipse.

  3. Buat APK Anda dan buka sebagai file zip , untuk memeriksa apakah libcalculate.sofile Anda ada di dalam lib / (armeabi | armeabi-v7a | x86 | ...) .

  4. Hapus dan instal aplikasi Anda

  5. Jalankan paket paket dumpsys | grep yourpackagename untuk mendapatkan nativeLibraryPath atau legacyNativeLibraryDir aplikasi Anda.

  6. Jalankan ls di nativeLibraryPath yang Anda miliki atau di legacyNativeLibraryDir / armeabi , untuk memeriksa apakah libcalculate.so Anda memang ada di sana.

  7. Jika ada, periksa apakah belum diubah dari file libcalculate.so asli Anda : apakah dikompilasi dengan arsitektur yang benar, apakah berisi simbol yang diharapkan, apakah ada dependensi yang hilang. Anda dapat menganalisis libcalculate.so menggunakan readelf.

Untuk memeriksa langkah 5-7, Anda dapat menggunakan aplikasi saya sebagai ganti baris perintah dan readelf: Native Libs Monitor

PS: Sangat mudah untuk bingung di mana file .so harus diletakkan atau dibuat secara default, berikut ringkasannya:

  • libs / CPU_ABI di dalam proyek eclipse

  • jniLibs / CPU_ABI di dalam proyek Android Studio

  • jni / CPU_ABI di dalam AAR

  • lib / CPU_ABI di dalam APK final

  • di dalam nativeLibraryPath aplikasi pada perangkat <5.0, dan di dalam legacyNativeLibraryDir / CPU_ARCH aplikasi pada perangkat> = 5.0.

Jika CPU_ABI adalah salah satu dari: armeabi, armeabi-v7a, arm64-v8a, x86, x86_64, mips, mips64 . Bergantung pada arsitektur mana yang Anda targetkan dan libs Anda telah dikompilasi.

Perhatikan juga bahwa lib tidak tercampur antara direktori CPU_ABI: Anda memerlukan kumpulan lengkap dari apa yang Anda gunakan, lib yang ada di dalam folder armeabi tidak akan diinstal pada perangkat armeabi-v7a jika ada lib di dalam armeabi -v7a folder dari APK.


3
Pria yang luar biasa, terima kasih! Saya menggunakan Android Studio dan jni build saya disalin ke libs, bukan ke jniLibs.
Luis

4
Catatan terakhir tentang perlunya set penuh sangat penting bagi saya. Itu masalah saya, terima kasih!
Ben Trengrove

Untuk 7bagian: apakah maksud Anda .so mungkin berubah dari APK setelah diinstal di perangkat? Jika demikian, apakah ada kemungkinan sistem dapat merusak file .so?
jayatubi

5
Hebat! Dalam kasus saya yang sangat aneh, saya menggunakan kumpulan pustaka pihak ketiga (OpenCV - di folder armeabi ) dan pustaka tersebut berhenti memuat ketika saya menambahkan pustaka pihak ketiga yang berbeda melalui Gradle. Ternyata pustaka kedua tidak mendukung ARMv5 atau 6, dan dengan memasukkannya, pustaka OpenCV saya menjadi tidak terlihat (meskipun sebenarnya ada di sana ). Poin Anda tentang set lengkap memberi saya petunjuk - mengganti nama folder armeabi dan menyebutnya armeabi-v7a memperbaiki masalah (karena saya sekarang tidak mendukung ARM 5 atau 6 ...). Masalah jahat !!
Bertemu

1
Cara lain untuk menemukan tempat meletakkan file lib (* .so) adalah dengan menjalankan aplikasi Anda dan mencetak nativeLibraryDir menggunakan: System.out.println (getApplicationContext (). GetApplicationInfo (). NativeLibraryDir), nama direktori juga akan memberi Anda ABI.
David Rauca

20

Dalam gradle, setelah menyalin semua folder file ke libs/

jniLibs.srcDirs = ['libs']

Menambahkan baris di atas ke sourceSetsdalam build.gradlefile berhasil. Tidak ada lagi yang berhasil.


2
apakah "sourceSets" terletak di file build.gradle?
Ashana.Jackol

12

Apakah Anda menggunakan gradle? Jika demikian, masukkan .sofile tersebut<project>/src/main/jniLibs/armeabi/

Saya harap ini membantu.


tidak, saya tidak menggunakan gradle, saya menggunakan eclipse + maven
pengguna842225

12

Dalam kasus saya, saya harus mengecualikan sumber kompilasi oleh gradle dan mengatur jalur libs

android {

    ...
    sourceSets {
        ...
        main.jni.srcDirs = []
        main.jniLibs.srcDirs = ['libs']
    }
....

ini menyelesaikannya untuk saya juga dan saya menambahkan file armeabi di folder armeabi-v7a dan x86 tetapi saya tidak yakin apakah itu perlu.
dokam_scotland

8

Penyebab error ini adalah karena ada ketidakcocokan ABI antara aplikasi Anda dan library native yang Anda tautkan. Kata lain, aplikasi Anda dan.so menargetkan ABI yang berbeda.

jika Anda membuat aplikasi Anda menggunakan template Android Studio terbaru, itu mungkin menargetkan arm64-v8atetapi Anda .somungkin menargetkanarmeabi-v7a misalnya.

Ada 2 cara untuk mengatasi masalah ini:

  1. membangun perpustakaan asli Anda untuk setiap ABI yang didukung aplikasi Anda.
  2. ubah aplikasi Anda untuk menargetkan ABI lama yang Anda .sobuat.

Pilihan 2 kotor tapi saya pikir Anda mungkin lebih tertarik pada:

ubah aplikasi Anda build.gradle

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

bagaimana jika aplikasi saya saya di gerhana? Masalah ini datang ketika saya memigrasi aplikasi khusus yang sama dari 6 ke 9.
Bayangan

6

Sebagai referensi, saya mendapat pesan kesalahan ini dan solusinya adalah ketika Anda menentukan perpustakaan, Anda kehilangan 'lib' di depan dan '.so' dari akhir.

Jadi, jika Anda memiliki file libmyfablib.so, Anda perlu memanggil:

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

Setelah melihat apk, menginstal / mencopot pemasangan dan mencoba semua jenis solusi kompleks, saya tidak dapat melihat masalah sederhana yang ada tepat di depan wajah saya!


Itu dia. Untuk beberapa alasan yang tidak diketahui Android tidak memasang pustaka yang nama filenya tidak dimulai dengan 'lib', meskipun pustaka tersebut ada dalam paket. Ayo bayangkan ...
George Y.

Di mana saya dapat memeriksa ini dalam proyek? Maksud saya di mana saya dapat menemukan baris ini System.loadLibrarydalam kode
aleksandrbel

Terima kasih. Ini membantu!
Riskhan

5

Ini adalah pembaruan Android 8.

Di versi Android sebelumnya, ke pustaka bersama bawaan LoadLibrary (untuk akses melalui JNI misalnya) saya menyambungkan kode asli saya untuk beralih melalui berbagai jalur direktori potensial untuk folder lib, berdasarkan berbagai algoritme penginstalan / peningkatan 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

Pendekatan ini curang dan tidak akan berfungsi untuk Android 8; dari https://developer.android.com/about/versions/oreo/android-8.0-changes.html Anda akan melihat bahwa sebagai bagian dari perubahan "Keamanan", Anda sekarang perlu menggunakan sourceDir:

"Anda tidak dapat lagi berasumsi bahwa APK berada di direktori yang namanya diakhiri dengan -1 atau -2. Aplikasi harus menggunakan sourceDir untuk mendapatkan direktori, dan tidak bergantung pada format direktori secara langsung."

Koreksi, sourceDir bukanlah cara untuk menemukan perpustakaan bersama asli Anda; gunakan sesuatu seperti. Diuji untuk 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

Coba panggil perpustakaan Anda setelah PREBUILT_SHARED_LIBRARYbagian 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

Memperbarui:

Jika Anda akan menggunakan perpustakaan ini di Java, Anda perlu mengkompilasinya sebagai perpustakaan bersama

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)
LOCAL_MODULE    := libcalculate
LOCAL_SRC_FILES := <PATH>/libcalculate.so
include $(BUILD_SHARED_LIBRARY)

Dan Anda perlu menerapkan pustaka di /vendor/libdirektori.


Hanya di akhir bagian.
Alex

2

Anda bisa mengubah ABI untuk menggunakan build yang lebih lama:

defaultConfig {
    ...

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

Anda juga harus menggunakan NDK yang tidak digunakan lagi dengan menambahkan baris ini ke gradle.properties:

android.useDeprecatedNdk=true

0

tolong tambahkan semua suport

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
Bisakah Anda lebih spesifik tentang apa yang harus dilakukan?
EFrank

File .so dalam proyek Anda. Anda harus mendukung arm64-v8a armeabi armeabi-v7a x86 x86_64 mips mips64. Ketika saya melakukan itu, itu bekerja dengan baik.
Singa 耿

-1

Dalam pengalaman saya, di ponsel armeabi-v7a, ketika direktori armeabi dan armeabi-v7a ada di apk, file .so di direktori armeabi tidak akan ditautkan, meskipun file .so di armeabi AKAN ditautkan di ponsel armeabi-v7a yang sama, jika armeabi-v7a tidak ada.


-1

sebenarnya, Anda tidak bisa begitu saja meletakkan file .so /libs/armeabi/dan memuatnya denganSystem.loadLibrary . Anda perlu membuat file Android.mk dan mendeklarasikan modul bawaan tempat Anda menentukan file .so sebagai sumber.

Untuk melakukannya, letakkan file .so Anda dan file Android.mk di jnifolder. Android.mk Anda akan terlihat seperti itu:

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)
LOCAL_MODULE    := libcalculate
LOCAL_SRC_FILES := libcalculate.so
include $(PREBUILT_SHARED_LIBRARY)

Sumber: Dokumentasi Android NDK tentang bawaan

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.