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

91

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

En mi código java, cargo la biblioteca por:

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

Cuando ejecuto mi nuevo proyecto de Android, recibí el 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?

(Descomprimí el paquete apk, en lib / hay libcalculate.so)

==== ACTUALIZAR =====

También intenté 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, en 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 maven construyendo el proyecto con éxito. En el paquete apk final, hay:

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

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

java.lang.UnsatisfiedLinkError:  ...
nativeLibraryDirectories=[/vendor/lib, /system/lib]]] couldn't find "libcalculate.so"
user842225
fuente
3
¿Pusiste la biblioteca directamente debajo libs/? Probablemente necesite crear un subdirectorio por ABI de destino que desee admitir (armeabi, armeabi-v7a, x86, mips, etc.) y colocar el archivo .so apropiado en cada subdirectorio (es decir, el archivo .so creado para armeabi entra libs/armeabi/, etc).
Michael
@Michael, me lo perdí en mi publicación, de hecho lo puse en libs / armeabi /
user842225
Compruebe que libcalculate.so sea realmente recogido por el proceso de empaquetado - intente unzip -l package.apk, por ejemplo , o cambie el nombre de la apk a .zip y ábralo con alguna aplicación. Si no está allí, algo está mal al empaquetarlo (¿su IDE notó que la carpeta está allí, necesita actualizar el proyecto?).
mstorsjo
@mstorsjo, descomprimí el paquete apk, en lib / hay libcalculate.so
user842225
1
no es necesario tener un Android.mk o cualquier archivo relacionado con la compilación. Simplemente coloque los archivos so en sus subdirectorios correspondientes a jniLibs como aquí: github.com/Ph1b/MaterialAudiobookPlayer/tree/master/audiobook/…
Paul Woitaschek

Respuestas:

177

Para raíz (y tal vez resolver su problema al mismo tiempo), esto es lo que puede hacer:

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

  2. Copie su libcalculate.soarchivo adentro <project>/libs/(armeabi|armeabi-v7a|x86|...). Cuando usas Android Studio, lo es <project>/app/src/main/jniLibs/(armeabi|armeabi-v7a|x86|...), pero veo que estás usando eclipse.

  3. Construya su APK y ábralo como un archivo zip , para verificar que su libcalculate.soarchivo esté dentro de lib / (armeabi | armeabi-v7a | x86 | ...) .

  4. Quita e instala tu aplicación

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

  6. Ejecute ls en 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 de su archivo libcalculate.so original : ¿está compilado con la arquitectura correcta, contiene los símbolos esperados, si faltan dependencias? Puede analizar libcalculate.so usando readelf.

Para verificar el paso 5-7, puede usar mi aplicación en lugar de líneas de comando y readelf: Native Libs Monitor

PD: Es fácil confundirse sobre dónde se deben colocar o generar los archivos .so de forma predeterminada, 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 del APK final

  • dentro de nativeLibraryPath de la aplicación en un dispositivo <5.0, y dentro del legacyNativeLibraryDir / CPU_ARCH de la aplicación en un dispositivo> = 5.0.

Donde CPU_ABI es cualquiera de: armeabi, armeabi-v7a, arm64-v8a, x86, x86_64, mips, mips64 . Dependiendo de las arquitecturas a las que se dirija y para las que se hayan compilado sus bibliotecas.

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

ph0b
fuente
3
¡Hombre impresionante, gracias! Estoy usando Android Studio y mis compilaciones jni se estaban copiando en libs en lugar de jniLibs.
Luis
4
Esa última nota sobre la necesidad del juego completo fue crucial para mí. Ese fue mi problema, gracias!
Ben Trengrove
Para la 7sección: ¿quiere decir que el .so podría cambiarse del APK después de que se haya instalado en el dispositivo? Si es así, ¿existe la posibilidad de que el sistema arruine el archivo .so?
Jayatubi
5
¡Maravilloso! En mi caso muy extraño, estaba usando un conjunto de bibliotecas de terceros (OpenCV - en la carpeta armeabi ) y esas bibliotecas dejaron de cargarse cuando agregué una biblioteca de terceros diferente a través de Gradle. Resulta que la segunda biblioteca no es compatible con ARMv5 o 6, y al incluirla, mis bibliotecas OpenCV se volvieron invisibles (aunque en realidad estaban allí ). Su punto sobre el conjunto completo me dio la pista: cambiar el nombre de la carpeta armeabi y llamarla armeabi-v7a solucionó el problema (ya que ahora no soy compatible con ARM 5 o 6 ...). ¡¡Mal problema !!
Mete
1
Otra forma de encontrar dónde poner su archivo lib (* .so) es ejecutar su aplicación e imprimir el nativeLibraryDir usando: System.out.println (getApplicationContext (). GetApplicationInfo (). NativeLibraryDir), el nombre del directorio también proporcionarle el ABI.
David Rauca
20

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

jniLibs.srcDirs = ['libs']

La adición de la línea anterior a sourceSetsen el build.gradlearchivo trabajó. Nada más funcionó en absoluto.

Mukund Muralikrishnan
fuente
2
¿Dónde se encuentra "sourceSets" en el archivo build.gradle?
Ashana.Jackol
12

¿Estás usando gradle? Si es así, ponga el .soarchivo en<project>/src/main/jniLibs/armeabi/

Espero que ayude.

Assaf Gamliel
fuente
no, no estoy usando gradle, estoy usando eclipse + maven
user842225
12

En mi caso, debo excluir las fuentes de compilación por gradle y establecer la ruta de las bibliotecas

android {

    ...
    sourceSets {
        ...
        main.jni.srcDirs = []
        main.jniLibs.srcDirs = ['libs']
    }
....
Dawid Drozd
fuente
esto también me resolvió y agregué los archivos de armeabi en las carpetas armeabi-v7a y x86, pero no estoy seguro de si era necesario.
dokam_scotland
8

El motivo de este error es que hay una falta de coincidencia de la ABI entre su aplicación y la biblioteca nativa con la que se vinculó. En otras palabras, su aplicación y su .soestán dirigidas a diferentes ABI.

si crea su aplicación con las últimas plantillas de Android Studio, probablemente esté orientada a, arm64-v8apero su .sopuede estar orientada, armeabi-v7apor ejemplo.

Hay 2 formas de resolver este problema:

  1. Cree sus bibliotecas nativas para cada ABI que admita su aplicación.
  2. cambie su aplicación para apuntar a un ABI más antiguo .socontra el que está construido.

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

cambia tu aplicación build.gradle

android {
    defaultConfig {
        ...
        ndk {
            abiFilters 'armeabi-v7a'
        }
   }
}
wdanxna
fuente
¿Qué pasa si mi aplicación está en eclipse? Este problema surge cuando migro la misma aplicación personalizada de 6 a 9.
Shadow
6

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

Entonces, si tiene un archivo libmyfablib.so, debe llamar a:

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

Después de haber mirado en el apk, instalado / desinstalado y probado todo tipo de soluciones complejas, ¡no podía ver el problema simple que estaba justo frente a mi cara!

Andy Krouwel
fuente
Eso fue todo. Por alguna razón desconocida, Android no instala bibliotecas cuyo nombre de archivo no comience con 'lib', incluso si están presentes en el paquete. Imagínate ...
George Y.
¿Dónde puedo comprobar esto en el proyecto? Quiero decir, ¿dónde puedo encontrar esta línea System.loadLibraryen el código
Aleksandrbel
Gracias. ¡Esto ayudó!
Riskhan
5

Esta es una actualización de Android 8.

En una versión anterior de Android, para las bibliotecas compartidas nativas de LoadLibrary (para acceder a través de JNI, por ejemplo), configuré mi código nativo para iterar a través de una variedad de posibles rutas de directorio para la carpeta lib, según los diversos algoritmos de instalación / actualización de 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

Este enfoque es tonto y no funcionará para Android 8; de https://developer.android.com/about/versions/oreo/android-8.0-changes.html verá que como parte de sus cambios de "Seguridad" ahora necesita usar sourceDir:

"Ya no puede suponer que los 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; usa 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;
}
ÁlgebraInvierno
fuente
4

Intente llamar a su biblioteca después de incluir la PREBUILT_SHARED_LIBRARYsección:

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

Actualizar:

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

LOCAL_PATH := $(call my-dir)

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

Y necesita implementar la biblioteca en el /vendor/libdirectorio.

Alex
fuente
Solo al final de la sección.
Alex
2

Podría simplemente cambiar ABI para usar compilaciones más antiguas:

defaultConfig {
    ...

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

También debe usar el NDK obsoleto agregando esta línea a gradle.properties:

android.useDeprecatedNdk=true
rezam
fuente
0

por favor agregue todo el apoyo

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
León 耿
fuente
1
¿Podría ser más específico sobre qué hacer?
EFrank
El archivo .so en su proyecto. Deberías ser compatible con arm64-v8a armeabi armeabi-v7a x86 x86_64 mips mips64. Cuando hice eso, funcionó bien.
León 耿
-1

En mi experiencia, en un móvil armeabi-v7a, cuando los directorios armeabi y armeabi-v7a están presentes en el apk, los archivos .so en el directorio armeabi no estarán vinculados, aunque los archivos .so en armeabi ESTARÁN vinculados en el mismo armeabi-v7a móvil, si armeabi-v7a no está presente.

loopscn
fuente
-1

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

Para hacerlo, coloque su archivo .so y el archivo Android.mk en la jnicarpeta. 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 precompilado

Yannshu
fuente