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"
sumber
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 masuklibs/armeabi/
, dll).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?).Jawaban:
Untuk melakukan root (dan mungkin menyelesaikan masalah Anda dalam waktu yang sama), berikut yang dapat Anda lakukan:
Hapus folder jni dan semua file .mk . Anda tidak memerlukan ini atau NDK jika Anda tidak mengompilasi apa pun.
Salin
libcalculate.so
file 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.Buat APK Anda dan buka sebagai file zip , untuk memeriksa apakah
libcalculate.so
file Anda ada di dalam lib / (armeabi | armeabi-v7a | x86 | ...) .Hapus dan instal aplikasi Anda
Jalankan paket paket dumpsys | grep yourpackagename untuk mendapatkan nativeLibraryPath atau legacyNativeLibraryDir aplikasi Anda.
Jalankan ls di nativeLibraryPath yang Anda miliki atau di legacyNativeLibraryDir / armeabi , untuk memeriksa apakah libcalculate.so Anda memang ada di sana.
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.
sumber
7
bagian: apakah maksud Anda .so mungkin berubah dari APK setelah diinstal di perangkat? Jika demikian, apakah ada kemungkinan sistem dapat merusak file .so?Dalam gradle, setelah menyalin semua folder file ke
libs/
jniLibs.srcDirs = ['libs']
Menambahkan baris di atas ke
sourceSets
dalambuild.gradle
file berhasil. Tidak ada lagi yang berhasil.sumber
Apakah Anda menggunakan gradle? Jika demikian, masukkan
.so
file tersebut<project>/src/main/jniLibs/armeabi/
Saya harap ini membantu.
sumber
Dalam kasus saya, saya harus mengecualikan sumber kompilasi oleh gradle dan mengatur jalur libs
android { ... sourceSets { ... main.jni.srcDirs = [] main.jniLibs.srcDirs = ['libs'] } ....
sumber
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-v8a
tetapi Anda.so
mungkin menargetkanarmeabi-v7a
misalnya.Ada 2 cara untuk mengatasi masalah ini:
.so
buat.Pilihan 2 kotor tapi saya pikir Anda mungkin lebih tertarik pada:
ubah aplikasi Anda
build.gradle
android { defaultConfig { ... ndk { abiFilters 'armeabi-v7a' } } }
sumber
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!
sumber
System.loadLibrary
dalam kodeIni 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; }
sumber
Coba panggil perpustakaan Anda setelah
PREBUILT_SHARED_LIBRARY
bagian 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/lib
direktori.sumber
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
sumber
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
sumber
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.
sumber
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
jni
folder. 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
sumber