Je souhaite utiliser une bibliothèque native existante à partir d' un autre projet Android, je viens donc de copier la bibliothèque intégrée NDK ( libcalculate.so ) dans mon nouveau projet Android. Dans mon nouveau projet Android, j'ai créé un dossier libs/armeabi/
et mis libcalculate.so là-bas. 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 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'ajouter un fichier Android.mk sous jni /. Le contenu d'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 maven construire le projet avec succès. Dans le package apk final, il y a:
lib/armeabi/libcalculate.so
lib/armeabi-v7a/libcalculate.so
Mais lorsque j'exécute mon application, la même erreur renvoie:
java.lang.UnsatisfiedLinkError: ...
nativeLibraryDirectories=[/vendor/lib, /system/lib]]] couldn't find "libcalculate.so"
la source
libs/
? Vous devez probablement créer un sous-répertoire par ABI cible que vous souhaitez prendre en charge (armeabi, armeabi-v7a, x86, mips, etc.) et placer le fichier .so approprié dans chaque sous-répertoire (c'est-à-dire que le fichier .so construit pour armeabi entrelibs/armeabi/
, etc).unzip -l package.apk
, ou renommez l'apk en .zip et ouvrez-le avec une application. S'il n'y est pas, quelque chose ne va pas avec l'empaquetage (votre IDE a-t-il remarqué que le dossier était là, avez-vous besoin de rafraîchir le projet?).Réponses:
Pour enraciner 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 pas besoin de ceux-ci ni du NDK si vous ne compilez rien.
Copiez votre
libcalculate.so
fichier à l'intérieur<project>/libs/(armeabi|armeabi-v7a|x86|...)
. Lorsque vous utilisez Android Studio, c'est<project>/app/src/main/jniLibs/(armeabi|armeabi-v7a|x86|...)
, mais je vois que vous utilisez eclipse.Construisez votre APK et ouvrez-le sous forme de fichier zip , pour vérifier que votre
libcalculate.so
fichier se trouve dans lib / (armeabi | armeabi-v7a | x86 | ...) .Supprimez et installez votre application
Exécuter les packages de package dumpsys | 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érifier si votre libcalculate.so est bien là.
S'il est là, vérifiez s'il n'a pas été modifié à partir de 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 analyser libcalculate.so en utilisant readelf.
Afin de vérifier l'étape 5-7, vous pouvez utiliser mon application au lieu des lignes de commande et lire 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, 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 l'APK final
dans le nativeLibraryPath de l'application sur un appareil <5.0, et dans le legacyNativeLibraryDir / CPU_ARCH de l' application sur un appareil> = 5.0.
Où CPU_ABI est l'un des éléments suivants: armeabi, armeabi-v7a, arm64-v8a, x86, x86_64, mips, mips64 . En fonction des architectures que vous ciblez 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 complet de ce que vous utilisez, une bibliothèque qui se trouve dans le dossier armeabi ne sera pas installée sur un périphérique armeabi-v7a s'il y a des bibliothèques à l'intérieur de l' armeabi -v7a dossier de l'APK.
la source
7
section: voulez-vous dire que le .so pourrait être modifié à partir de l'APK après son installation sur l'appareil? Si tel est le cas, y aurait-il une chance que le système ruine le fichier .so?Dans gradle, après avoir copié tous les dossiers de fichiers dans
libs/
L'ajout de la ligne ci-dessus
sourceSets
dans lebuild.gradle
fichier a fonctionné. Rien d'autre n'a fonctionné du tout.la source
Utilisez-vous gradle? Si c'est le cas, mettez le
.so
fichier dans<project>/src/main/jniLibs/armeabi/
J'espère que cela aide.
la source
Dans mon cas, je dois exclure la compilation des sources par gradle et définir le chemin des libs
la source
La raison de cette erreur est qu'il existe une incompatibilité de l'ABI entre votre application et la bibliothèque native avec laquelle vous vous êtes lié. Un autre mot, votre application et votre
.so
ciblent 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
ciblage peut-êtrearmeabi-v7a
par exemple.Il existe 2 façons de résoudre ce problème:
.so
construit.Le choix 2 est sale mais je pense que vous êtes probablement plus intéressé par:
changer votre application
build.gradle
la source
Pour référence, j'avais ce message d'erreur et la solution était que lorsque vous spécifiez la bibliothèque, vous manquiez le «lib» sur le devant et le «.so» de la fin.
Donc, si vous avez un fichier libmyfablib.so, vous devez appeler:
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!
la source
System.loadLibrary
dans le codeCeci est une mise à jour Android 8.
Dans la version antérieure d'Android, aux bibliothèques partagées natives de 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 pour le dossier lib, en fonction des divers algorithmes d'installation / de mise à niveau d'apk:
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 les noms se terminent par -1 ou -2. Les applications doivent utiliser sourceDir pour obtenir le répertoire et ne pas dépendre directement du format du répertoire."
Correction, sourceDir n'est pas le moyen de trouver vos bibliothèques partagées natives; utilisez quelque chose comme. Testé pour Android 4.4.4 -> 8.0
la source
Essayez d'appeler votre bibliothèque après la
PREBUILT_SHARED_LIBRARY
section d' inclusion :Mettre à jour:
Si vous utilisez cette bibliothèque en Java, vous devez la compiler en tant que bibliothèque partagée
Et vous devez déployer la bibliothèque dans le
/vendor/lib
répertoire.la source
Vous pouvez simplement changer ABI pour utiliser des versions plus anciennes:
Vous devez également utiliser NDK obsolète en ajoutant cette ligne à
gradle.properties
:la source
veuillez ajouter tout le support
app / build.gradle
app \ src \ jni \ Application.mk
la source
D'après mon expérience, dans un mobile armeabi-v7a, lorsque les répertoires armeabi et armeabi-v7a sont présents dans l'apk, les fichiers .so dans le répertoire armeabi ne seront pas liés, bien que les fichiers .so dans armeabi seront liés dans le même mobile armeabi-v7a, si armeabi-v7a n'est pas présent.
la source
en fait, vous ne pouvez pas simplement mettre un fichier .so dans le
/libs/armeabi/
et le charger avecSystem.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 comme source.Pour ce faire, placez votre fichier .so et le fichier Android.mk dans le
jni
dossier. Votre Android.mk devrait ressembler à ceci:Source: documentation Android NDK sur le préconstruit
la source