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"
fuente
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 entralibs/armeabi/
, etc).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?).Respuestas:
Para raíz (y tal vez resolver su problema al mismo tiempo), esto es lo que puede hacer:
Elimine la carpeta jni y todos los archivos .mk . No los necesita ni el NDK si no está compilando nada.
Copie su
libcalculate.so
archivo 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.Construya su APK y ábralo como un archivo zip , para verificar que su
libcalculate.so
archivo esté dentro de lib / (armeabi | armeabi-v7a | x86 | ...) .Quita e instala tu aplicación
Ejecutar paquetes de paquetes dumpsys | grep yourpackagename para obtener nativeLibraryPath o legacyNativeLibraryDir de su aplicación.
Ejecute ls en nativeLibraryPath que tenía o en legacyNativeLibraryDir / armeabi , para verificar si su libcalculate.so está realmente allí.
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.
fuente
7
secció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?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
sourceSets
en elbuild.gradle
archivo trabajó. Nada más funcionó en absoluto.fuente
¿Estás usando gradle? Si es así, ponga el
.so
archivo en<project>/src/main/jniLibs/armeabi/
Espero que ayude.
fuente
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'] } ....
fuente
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
.so
están dirigidas a diferentes ABI.si crea su aplicación con las últimas plantillas de Android Studio, probablemente esté orientada a,
arm64-v8a
pero su.so
puede estar orientada,armeabi-v7a
por ejemplo.Hay 2 formas de resolver este problema:
.so
contra 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' } } }
fuente
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!
fuente
System.loadLibrary
en el códigoEsta 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; }
fuente
Intente llamar a su biblioteca después de incluir la
PREBUILT_SHARED_LIBRARY
secció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/lib
directorio.fuente
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
fuente
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
fuente
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.
fuente
en realidad, no puede simplemente poner un archivo .so en el
/libs/armeabi/
y cargarlo conSystem.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
jni
carpeta. 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
fuente