Je souhaite utiliser une bibliothèque native existante à partir de ne autre Android projet, donc je viens de copier la bibliothèque générée par NDK (libcalculate.so) dans mon nouveau Android projet. Dans mon nouveau projet Android, j'ai créé un dossier libs/armeabi/
et y mettre libcalculate.so. Il y a no jni/folder. Mon appareil de test a l'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 l'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)
==== UPDATE =====
J'ai également essayé de créer un dossier jni/sous la racine du projet et d'ajouter 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 la racine 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).
Ensuite, je lance mon navigateur pour construire le projet avec succès. Dans le paquet final apk, il y a:
lib/armeabi/libcalculate.so
lib/armeabi-v7a/libcalculate.so
Mais quand je lance mon application, la même erreur jette:
Java.lang.UnsatisfiedLinkError: ...
nativeLibraryDirectories=[/vendor/lib, /system/lib]]] couldn't find "libcalculate.so"
Pour trouver la cause (et peut-être résoudre votre problème en même temps), voici ce que vous pouvez faire:
Supprimez le dossier jni et tous les fichiers . Mk . Vous n'avez besoin ni de ceux-ci ni du NDK si vous ne compilez rien.
Copiez votre fichier libcalculate.so
à l'intérieur de <project>/libs/(armeabi|armeabi-v7a|x86|...)
. Lorsque vous utilisez Android Studio, il s’agit de <project>/app/src/main/jniLibs/(armeabi|armeabi-v7a|x86|...)
, mais je vois que vous utilisez Eclipse.
Construisez votre APK et ouvrez-le en tant que fichier Zip , afin de vérifier que votre fichier libcalculate.so
est à l'intérieur lib/(armeabi | armeabi-v7a | x86 | ...).
Supprimer et installer votre application
Exécuter dumpsys package packages | grep yourpackagename pour obtenir le nativeLibraryPath ou legacyNativeLibraryDir de votre application.
Exécutez ls sur le nativeLibraryPath que vous aviez ou sur legacyNativeLibraryDir/armeabi , pour vérifiez si votre libcalculate.so est bien là.
S'il est présent, vérifiez s'il n'a pas été modifié depuis votre fichier d'origine libcalculate.so : est-il compilé avec la bonne architecture, contient-il les symboles attendus, existe-t-il des dépendances manquantes. Vous pouvez analyser libcalculate.so en utilisant readelf.
Afin de vérifier les étapes 5 à 7, vous pouvez utiliser mon application au lieu des lignes de commande et vous-même: Native Libs Monitor
PS: Il est facile de ne pas savoir où les fichiers .so doivent être placés ou générés par défaut. En 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 à l'intérieur du dernier APK
nativeLibraryPath de l'application sur un périphérique <5.0, et à l'intérieur de l'application legacyNativeLibraryDir/CPU_Arch sur un périphérique> = 5.0.
Où CPU_ABI est l'un des nombres suivants: armeabi, armeabi-v7a, arm64-v8a, x86, x86_64, mips, mips64 . Selon les architectures que vous ciblez et 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 tout ce que vous utilisez, une bibliothèque située dans le dossier armeabi ne sera pas installée sur un ordinateur. armeabi-v7a périphérique s'il y a des bibliothèques dans le dossier armeabi-v7a de l'APK.
En dégradé, après avoir copié tous les dossiers de fichiers dans libs/
jniLibs.srcDirs = ['libs']
L'ajout de la ligne ci-dessus au fichier sourceSets
dans le fichier build.gradle
a fonctionné. Rien d'autre n'a fonctionné que ce soit.
Utilisez-vous Gradle? Si c'est le cas, placez le fichier .so
dans <project>/src/main/jniLibs/armeabi/
J'espère que ça aide.
Dans mon cas, je dois exclure la compilation des sources par gradle et définir le chemin de la bibliothèque
Android {
...
sourceSets {
...
main.jni.srcDirs = []
main.jniLibs.srcDirs = ['libs']
}
....
Cette erreur s’explique par le fait qu’il existe une incompatibilité de l’ABI entre votre application et la bibliothèque native à laquelle vous êtes lié. Un autre mot, votre application et votre .so
vise différents ABI.
si vous créez votre application à l'aide des derniers modèles Android Studio, elle cible probablement le arm64-v8a
, mais votre .so
peut cibler armeabi-v7a
par exemple.
Il y a 2 façons de résoudre ce problème:
.so
a été construit.Le choix 2 est sale mais je pense que vous avez probablement plus intéressé par:
changer le build.gradle
de votre application
Android {
defaultConfig {
...
ndk {
abiFilters 'armeabi-v7a'
}
}
}
Pour référence, j'ai eu ce message d'erreur et la solution a été que lorsque vous spécifiez la bibliothèque, vous manquez la 'lib' au premier plan et le '.so' à 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 se trouvait juste devant mon visage!
Ceci est une mise à jour Android 8.
Dans les versions antérieures d'Android, dans les bibliothèques partagées natives LoadLibrary (pour un accès via JNI, par exemple), j'ai câblé mon code natif pour itérer à travers une gamme de chemins de répertoire potentiels du dossier lib, basés sur les divers algorithmes d'installation/mise à niveau d'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
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 "Sécurité", vous devez maintenant utiliser sourceDir :
"Vous ne pouvez plus présumer que les fichiers APK se trouvent 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 s'appuyer directement sur le format du répertoire."
Correction, sourceDir n'est pas le moyen 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 String getNativeLibraryDir(Context context) {
ApplicationInfo appInfo = context.getApplicationInfo();
return appInfo.nativeLibraryDir;
}
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 := <PATH>/libcalculate.so
include $(PREBUILT_SHARED_LIBRARY)
#...
LOCAL_SHARED_LIBRARIES += libcalculate
Mise à jour:
Si vous voulez utiliser cette bibliothèque dans Java, vous devez le compiler en tant que bibliothèque partagée.
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := libcalculate
LOCAL_SRC_FILES := <PATH>/libcalculate.so
include $(BUILD_SHARED_LIBRARY)
Et vous devez déployer la bibliothèque dans le répertoire /vendor/lib
.
s'il vous plaît ajouter 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