System.loadLibrary (…) no pudo encontrar la biblioteca nativa en mi caso

Quiero usar una biblioteca nativa existente de otro proyecto de Android, así que simplemente copié la biblioteca construida de NDK ( libcalculate.so ) en mi nuevo proyecto de Android. En mi nuevo proyecto de Android, creé una carpeta libs/armeabi/ y puse libcalculate.so ahí. No hay jni / carpeta. Mi dispositivo de prueba tiene architecture ARM.

En mi código Java, cargo la biblioteca de la siguiente manera:

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

Cuando ejecuto mi nuevo proyecto de Android, recibí un error:

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

Entonces, como dice el error, la biblioteca nativa copiada no está en / verdor / lib o / system / lib, ¿cómo resolver este problema en mi caso?

(Desliqué el paquete apk, bajo lib / there es libcalculate.so)

==== ACTUALIZACIÓN =====

También traté de crear una carpeta jni / en la raíz del proyecto y agregar un archivo Android.mk en jni /. El contenido de Android.mk es:

 LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := libcalculate LOCAL_SRC_FILES := libcalculate.so include $(PREBUILT_SHARED_LIBRARY) 

Luego, bajo la raíz del proyecto, ejecuté ndk-build. Después de eso, los directorios armeabi / y armeabi-v7a / son generados por ndk-build (con libcalculate.so dentro de la carpeta).

Luego ejecuto mi proyecto maven el proyecto con éxito. En el paquete final de apk, hay:

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

Pero cuando ejecuto mi aplicación, arrojo el mismo error:

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

Para desencadenar (y quizás resolver su problema al mismo tiempo), esto es lo que puede hacer:

  1. Retire la carpeta jni y todos los archivos .mk . No necesita estos ni el NDK si no está comstackndo nada.

  2. Copie su archivo libcalculate.so dentro de /libs/(armeabi|armeabi-v7a|x86|...) . Al usar Android Studio, es /app/src/main/jniLibs/(armeabi|armeabi-v7a|x86|...) , pero veo que estás usando eclipse.

  3. Crea tu APK y libcalculate.so como un archivo zip , para verificar que tu archivo libcalculate.so esté dentro de lib / (armeabi | armeabi-v7a | x86 | …) .

  4. Retire e instale su aplicación

  5. Ejecutar paquetes de paquete dumpsys | grep yourpackagename para obtener nativeLibraryPath o legacyNativeLibraryDir de su aplicación.

  6. Ejecute ls en el nativeLibraryPath que tenía o en legacyNativeLibraryDir / armeabi , para verificar si su libcalculate.so está realmente allí.

  7. Si está allí, compruebe si no ha sido alterado desde su archivo libcalculate.so original: ¿está comstackdo contra la architecture correcta, contiene los símbolos esperados, hay dependencias faltantes? Puede analizar libcalculate.so usando readelf.

Para verificar los pasos 5-7, puede usar mi aplicación en lugar de las líneas de comandos y readelf: Native Libs Monitor

PD: Es fácil confundirse sobre dónde se deben poner o generar los archivos .so por defecto, aquí hay un resumen:

  • libs / CPU_ABI dentro de un proyecto de eclipse

  • jniLibs / CPU_ABI dentro de un proyecto de Android Studio

  • jni / CPU_ABI dentro de un AAR

  • lib / CPU_ABI dentro de la APK final

  • dentro de nativeBibraryPath de la aplicación en un dispositivo <5.0, y dentro de la aplicación LegacyNativeLibraryDir / CPU_ARCH en un dispositivo> = 5.0.

Donde CPU_ABI es cualquiera de: armeabi, armeabi-v7a, arm64-v8a, x86, x86_64, mips, mips64 . Dependiendo de las architectures a las que te diriges y tus libs han sido comstackdas.

Tenga en cuenta también que las libs no están mezcladas entre los directorios de CPU_ABI: necesita el conjunto completo de lo que está utilizando, una lib que está dentro de la carpeta armeabi no se instalará en un dispositivo armeabi-v7a si hay libs dentro de la armeabi -v7a carpeta del APK.

En gradle, después de copiar todas las carpetas de archivos a libs/

 jniLibs.srcDirs = ['libs'] 

Agregar la línea anterior a los sourceSets de sourceSets en el archivo build.gradle funcionó. Nada más funcionó en absoluto.

¿Estás usando gradle? Si es así, ponga el archivo .so en /src/main/jniLibs/armeabi/

Espero que ayude.

En mi caso, debo excluir la comstackción de fonts por gradle y establecer la ruta libs

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

Intenta llamar a tu biblioteca después de incluir la sección PREBUILT_SHARED_LIBRARY :

 LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := libcalculate LOCAL_SRC_FILES := /libcalculate.so include $(PREBUILT_SHARED_LIBRARY) #... LOCAL_SHARED_LIBRARIES += libcalculate 

Actualizar:

Si va a utilizar esta biblioteca en Java, debe comstackrla como biblioteca compartida

 LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := libcalculate LOCAL_SRC_FILES := /libcalculate.so include $(BUILD_SHARED_LIBRARY) 

Y necesita implementar la biblioteca en el directorio /vendor/lib .

Como referencia, tuve este mensaje de error y la solución fue que cuando especificas la biblioteca, pierdes la ‘lib’ del frente y ‘.so’ del final.

Entonces, si tiene un archivo libmyfablib.so, necesita llamar:

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

Después de buscar en la aplicación, instalar / desinstalar e intenté todo tipo de soluciones complejas, ¡no pude ver el simple problema que estaba justo frente a mi cara!

Esta es una actualización de Android 8.

En una versión anterior de Android, en las bibliotecas compartidas nativas de LoadLibrary (para acceder a través de JNI por ejemplo) conecté mi código nativo para recorrer un rango de posibles rutas de directorio para la carpeta lib, según los diversos algoritmos de instalación / actualización de apk:

 /data/data//lib /data/app-lib/-1/lib /data/app-lib/-2/lib /data/app/-1/lib /data/app/-2/lib 

Este enfoque es hokey y no funcionará para Android 8; desde https://developer.android.com/about/versions/oreo/android-8.0-changes.html verás que, como parte de sus cambios de “Seguridad”, ahora necesitas usar sourceDir:

“Ya no se puede asumir que los archivos APK residen en directorios cuyos nombres terminan en -1 o -2. Las aplicaciones deben usar sourceDir para obtener el directorio y no depender directamente del formato del directorio”.

Corrección, sourceDir no es la forma de encontrar sus bibliotecas compartidas nativas; usar algo como. Probado para 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; } 

El motivo de este error es que hay una discrepancia entre la ABI y la biblioteca nativa con la que se vinculó. Otra palabras, tu aplicación y tu .so apuntan a diferentes ABI.

si creas tu aplicación usando las últimas plantillas de Android Studio, probablemente arm64-v8a apuntando a arm64-v8a pero tu .so puede estar apuntando a armeabi-v7a por ejemplo.

Hay 2 formas de resolver este problema:

  1. construye tus bibliotecas nativas para cada ABI compatible con tu aplicación.
  2. cambie su aplicación para apuntar a ABI anterior que su .so construyó en contra.

La opción 2 está sucia, pero creo que probablemente te interese más:

cambia la build.gradle tu aplicación

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

por favor agregue todos los soportes

app / build.gradle

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

aplicación \ src \ jni \ Application.mk

 APP_ABI := arm64-v8a armeabi armeabi-v7a x86 x86_64 mips mips64 

En mi experiencia, en un móvil armeabi-v7a, cuando los directorios armeabi y armeabi-v7a están presentes en la apk, los archivos .so en el directorio armeabi no se vincularán, aunque los archivos .so en armeabi se vincularán en el mismo móvil armeabi-v7a, si armeabi-v7a no está presente.

en realidad, no puede simplemente poner un archivo .so en /libs/armeabi/ y cargarlo con System.loadLibrary . Necesita crear un archivo Android.mk y declarar un módulo preconstruido donde especifique su archivo .so como fuente.

Para hacerlo, coloque su archivo .so y el archivo Android.mk en la carpeta jni . Tu Android.mk debería verse así:

 LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := libcalculate LOCAL_SRC_FILES := libcalculate.so include $(PREBUILT_SHARED_LIBRARY) 

Fuente: documentación de Android NDK sobre preconstruido