System.loadLibrary (…) n’a pas pu trouver la bibliothèque native dans mon cas

Je veux utiliser une bibliothèque native existante à partir d’ un autre projet Android, alors je viens de copier la bibliothèque construite NDK ( libcalculate.so ) sur mon nouveau projet Android. Dans mon nouveau projet Android, j’ai créé un dossier libs/armeabi/ et y ai placé libcalculate.so . Il n’y a pas de dossier jni /. Mon appareil de test a une architecture ARM.

Dans mon code java, je charge la bibliothèque par:

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

Lorsque je lance mon nouveau projet Android, j’ai eu une erreur:

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

Donc, comme le dit l’erreur, la bibliothèque native copiée n’est pas dans / verdor / lib ou / system / lib, comment résoudre ce problème dans mon cas?

(J’ai décompressé le paquet apk, sous lib / il y a libcalculate.so)

==== MISE À JOUR =====

J’ai également essayé de créer un dossier jni / sous la racine du projet et d’append un fichier Android.mk sous jni /. Le contenu de Android.mk est:

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

Ensuite, sous root du projet, j’ai exécuté ndk-build. Après cela, les répertoires armeabi / et armeabi-v7a / sont générés par ndk-build (avec libcalculate.so dans le dossier).

Puis je lance ma construction de projet avec succès. Dans le paquet apk final, il y a:

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

Mais quand je lance mon application, la même erreur se produit:

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

Pour enraciner (et peut-être résoudre votre problème en même temps), voici ce que vous pouvez faire:

  1. Supprimez le dossier jni et tous les fichiers .mk . Vous n’avez pas besoin de ceux-ci ni du NDK si vous ne comstackz rien.

  2. Copiez votre fichier libcalculate.so dans /libs/(armeabi|armeabi-v7a|x86|...) . Lorsque vous utilisez Android Studio, c’est /app/src/main/jniLibs/(armeabi|armeabi-v7a|x86|...) , mais je constate que vous utilisez eclipse.

  3. Construisez votre APK et ouvrez-le comme un fichier zip pour vérifier que votre fichier libcalculate.so trouve dans lib / (armeabi | armeabi-v7a | x86 | …) .

  4. Supprimer et installer votre application

  5. Exécuter les packages de packages dumpsys | grep yourpackagename pour obtenir le nativeLibraryPath ou legacyNativeLibraryDir de votre application.

  6. Exécutez ls sur le nativeLibraryPath que vous aviez ou sur legacyNativeLibraryDir / armeabi , pour vérifier si votre libcalculate.so est bien là.

  7. Si c’est le cas, vérifiez s’il n’a pas été modifié depuis votre fichier libcalculate.so d’ origine: est-il compilé avec la bonne architecture, contient-il les symboles attendus, y a-t-il des dépendances manquantes? Vous pouvez parsingr libcalculate.so en utilisant readelf.

Pour vérifier les étapes 5-7, vous pouvez utiliser mon application à la place des lignes de commande et de la liste de lecture: Native Libs Monitor

PS: il est facile de se confondre sur l’endroit où les fichiers .so doivent être placés ou générés par défaut, voici un résumé:

  • libs / CPU_ABI dans un projet eclipse

  • jniLibs / CPU_ABI dans un projet Android Studio

  • jni / CPU_ABI dans un AAR

  • lib / CPU_ABI dans le dernier APK

  • dans le fichier nativeLibraryPath de l’application sur un périphérique <5.0 et dans le fichier legacyNativeLibraryDir / CPU_ARCH de l’ application sur un périphérique> = 5.0.

CPU_ABI est l’un des suivants: armeabi, armeabi-v7a, arm64-v8a, x86, x86_64, mips, mips64 . Selon les architectures que vous visez et pour lesquelles vos bibliothèques ont été compilées.

Notez également que les bibliothèques ne sont pas mélangées entre les répertoires CPU_ABI: vous avez besoin de l’ensemble de ce que vous utilisez, une lib qui se trouve dans le dossier armeabi ne sera pas installée sur un périphérique armeabi-v7a . -v7a dossier de l’APK.

Dans gradle, après avoir copié tous les dossiers de fichiers dans libs/

 jniLibs.srcDirs = ['libs'] 

L’ajout de la ligne ci-dessus à sourceSets dans le fichier build.gradle fonctionné. Rien d’autre n’a fonctionné.

Utilisez-vous gradle? Si oui, mettez le fichier .so dans /src/main/jniLibs/armeabi/

J’espère que ça aide.

Dans mon cas, je dois exclure les sources de compilation par gradle et définir le chemin des libs

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

Essayez d’appeler votre bibliothèque après la section include 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 

Mettre à jour:

Si vous utilisez cette bibliothèque en Java, vous devez la comstackr en tant que bibliothèque partagée

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

Et vous devez déployer la bibliothèque dans le répertoire /vendor/lib .

Pour référence, j’ai eu ce message d’erreur et la solution était que lorsque vous spécifiez la bibliothèque, vous manquez la “lib” avant et le “.so” de la fin.

Donc, si vous avez un fichier libmyfablib.so, vous devez appeler:

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

Après avoir regardé dans l’apk, installé / désinstallé et essayé toutes sortes de solutions complexes, je ne pouvais pas voir le problème simple qui était juste devant mon visage!

Ceci est une mise à jour Android 8.

Dans les versions précédentes d’Android, les bibliothèques partagées natives de LoadLibrary (pour l’access via JNI par exemple), j’ai câblé mon code natif pour parcourir une série de chemins de répertoire potentiels pour le dossier lib, basés sur les différents algorithmes d’installation / mise à jour apk:

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

Cette approche est hokey et ne fonctionnera pas pour Android 8; à partir de https://developer.android.com/about/versions/oreo/android-8.0-changes.html, vous verrez que dans le cadre de leurs modifications de “sécurité”, vous devez maintenant utiliser sourceDir:

“Vous ne pouvez plus supposer que les fichiers APK résident dans des répertoires dont le nom se termine par -1 ou -2. Les applications doivent utiliser sourceDir pour obtenir le répertoire et ne pas utiliser directement le format de répertoire.”

Correction, sourceDir n’est pas la manière de trouver vos bibliothèques partagées natives; utiliser quelque chose comme. Testé pour Android 4.4.4 -> 8.0

 // Return Full path to the directory where native JNI libraries are stored. private static Ssortingng getNativeLibraryDir(Context context) { ApplicationInfo appInfo = context.getApplicationInfo(); return appInfo.nativeLibraryDir; } 

La raison de cette erreur est qu’il n’ya pas une correspondance entre l’ABI et votre bibliothèque native. Un autre mot, votre application et votre .so cible différents ABI.

Si vous créez votre application à l’aide des derniers modèles d’Android Studio, sa cible est probablement arm64-v8a mais votre .so peut cibler armeabi-v7a par exemple.

Il y a 2 façons de résoudre ce problème:

  1. Construisez vos bibliothèques natives pour chaque ABI pris en charge par votre application.
  2. changez votre application pour cibler les anciennes ABI intégrées à votre .so .

Le choix 2 est sale mais je pense que vous êtes probablement plus intéressé par:

changer le build.gradle votre application

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

veuillez append tout 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 

Dans mon expérience, dans un mobile armeabi-v7a, lorsque les deux répertoires armeabi et armeabi-v7a sont présents dans l’apk, les fichiers .so du répertoire armeabi ne seront pas liés, bien que les fichiers .so dans armeabi soient liés dans le répertoire. même armeabi-v7a mobile, si armeabi-v7a n’est pas présent.

En fait, vous ne pouvez pas simplement placer un fichier .so dans /libs/armeabi/ et le charger avec System.loadLibrary . Vous devez créer un fichier Android.mk et déclarer un module prédéfini dans lequel vous spécifiez votre fichier .so en tant que source.

Pour ce faire, placez votre fichier .so et le fichier Android.mk dans le dossier jni . Votre Android.mk devrait ressembler à ceci:

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

Source: documentation Android NDK sur la pré-construction