web-dev-qa-db-fra.com

Comment résoudre l'erreur Java.lang.UnsatisfiedLinkError dans NDK sous Android?

Je suis nouveau dans le développement ndk sous Android.J'ai passé par le système de fichiers de ndk Android . Ici, en expliquant ce que j'ai fait . 1) j'ai créé un dossier nommé "jni" puis créé 2 fichiers nommés Android.mk et ndkfoo.c.

Dans Android.mk

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

# Here we give our module name and source file(s)
LOCAL_MODULE    := ndkfoo
LOCAL_SRC_FILES := ndkfoo.c

include $(BUILD_SHARED_LIBRARY)

et dans ndkfoo.c

#include <string.h>
#include <jni.h>

jstring Java_com_mindtherobot_samples_ndkfoo_NdkFooActivity_invokeNativeFunction(JNIEnv* env, jobject javaThis) {
 return (*env)->NewStringUTF(env, "Hello from native code!");
}

alors j'ai créé la classe NdkFooActivity, dans laquelle j'ai écrit

// load the library - name matches jni/Android.mk
 static {
  System.loadLibrary("ndkfoo");
 }

Mais maintenant, lorsque je construis à partir de cygwin dans xp, il crée un fichier .so avec succès, puis je lance l'application Android. Cela me donne Java.lang.UnsatisfiedLinkError dans LOGCAT.

Alors, s'il vous plaît laissez-moi savoir où je me trompe.

Merci d'avance,

25
Jassi

Je pense que vous avez oublié de changer le nom du paquet.

Java_com_mindtherobot_samples_ndkfoo

Ce devrait être à votre paquet ce que vous avez spécifié lors de la création du projet.

22
StarDust

De plus, veuillez noter que System.loadLibrary () lève toujours une exception si vous testez l'émulateur Intel Atom x86. Cela fonctionne très bien sur les émulateurs Android classiques et le débogage sur un périphérique physique.

21
Daniel Rodriguez

Bien que cela ne soit pas le problème de l'OP, j'avais le même Java.lang.UnsatisfiedLinkError car il manquait

static {
    System.loadLibrary("mylibraryname");
}
11

Il y a de bonnes chances que la signature soit fausse, comme d'autres l'ont mentionné.

Si vous exécutez l'utilitaire javah, vous pouvez trouver la signature exacte. Dans le dossier bin de votre projet, où se trouve le .apk et la racine de la hiérarchie de classes Java, exécutez:

javah -o jni_sig.h com.mindtherobot.wany.votre.package.is.NdkFooActivity

... et si le nom du paquet et le nom de la classe sont corrects, un en-tête (appelé jni_sig.h) sera écrit avec la ou les signatures de fonction correctes pour toutes les fonctions natives. Copiez cela dans votre en-tête et votre fichier .c, en ajoutant les paramètres nécessaires, et tout devrait fonctionner correctement.

5
SomeCallMeTim

Peut-être plus d'actualité, mais pour autant que je sache, vous devez également ajouter le préfixe "lib" au nom de votre bibliothèque native. Dans votre cas, vous devez remplacer Android.mk par "LOCAL_MODULE: = libndkfoo" et conserver "System.loadLibrary (" ndkfoo ");" tel quel. Vérifiez l'exemple de code ndk.

4
Elis Popescu

Je suis sûr que cela devrait être:

JNIEXPORT jstring JNICALL Java_com_mindtherobot_samples_ndkfoo_NdkFooActivity_invokeNativeFunction(JNIEnv* env, jobject javaThis) {
 return (*env)->NewStringUTF(env, "Hello from native code!");
}

Quel SDK ciblez-vous et quelle version du NDK avez-vous? L'erreur que vous obtenez indique-t-elle qu'elle ne peut pas charger la bibliothèque du tout ou qu'il existe une méthode non implémentée? Quoi qu'il en soit, assurez-vous que vous n'avez pas Android: hasCode = "false" défini sur la balise d'application dans votre manifeste. 

Vous pouvez également ouvrir le fichier APK après une compilation en utilisant winrar ou quelque chose de similaire pour vous assurer que le fichier libndkfoo.so est bien compris dans le package.

Dans les deux cas, si vous ne déclarez pas la fonction native dans NdkFooActivity, vous obtiendrez cette erreur, c'est-à-dire.

publique statique native String invokeNativeFunction ();

3
Justin Buser
JNIEXPORT jstring JNICALL Java_com_mindtherobot_samples_ndkfoo_NdkFooActivity_invokeNativeFunction(JNIEnv* env, jobject javaThis) {
 return (*env)->NewStringUTF(env, "Hello from native code!");
}

le problème est que vous compilez pour un processeur cible et que vous l'exécutez dans un autre. Si vous compilez dans ARM (armeabi), exécutez-le dans un émulateur basé sur armeabi. Créez un fichier nommé application.mk dans le même dossier qu'Android.mk et insérez-y l'un des éléments suivants:

  1. APP_ABI: = x86 
  2. APP_ABI: = armeabi
  3. APP_ABI: = mips
  4. APP_ABI: = armeabi x86 mips // à compiler dans toutes les cibles et vous obtiendrez 3 fichiers * .so

puis compilez-> lancez . ça devrait marcher.

2
SRedouane

Le nom de la méthode Java_com_mindtherobot_samples_ndkfoo_NdkFooActivity_invokeNativeFunction

peut ne pas être identique à celui de votre nom de package ou nom de classe . Pour que cette dénomination de méthode soit exactement identique, vous devez utiliser javah.

Cela créera un fichier d’en-tête qui portera le même nom de méthode que celui requis. Pour le faire, accédez au dossier classes dans le chutier de votre projet (assurez-vous d’avoir créé le fichier Java avec une méthode statique et de le construire correctement. ) par cette commande dans votre terminal

~/workspace/Android_Example2/bin/classes$

Dans ce répertoire, écrivez la commande suivante

Sudo javah -jni com.NDK.Android_example2.MainActivity

Modifiez le nom du package et le nom de la classe en fonction de votre projet. Ceci créera un com_NDK_Android_example2_MainActivity.h dans votre dossier de classes.

Il suffit de déplacer ce fichier dans votre dossier jni. Dans ce fichier, il y aura des méthodes statiques que vous avez créées dans le fichier MainActivity.Java mais elles sont juste déclarées non implémentées que vous allez implémenter dans votre fichier C

REMARQUE: lors de la copie de la méthode, vérifiez que les paramètres de la méthode doivent être déclarés. Définissez-les donc dans votre fichier C.

J'espère que cette aide.

1
Jagdeep Singh

Créez un fichier Application.mk dans un dossier jni. Copiez la ligne suivante et collez-le dans Application.mk puis enregistrez.Maintenant, générez le projet avec votre cgywin et exécutez-le à nouveau.

APP_ABI: = armeabi armeabi-v7a

1
Sajol

J'ai aussi eu une erreur Java.lang.UnsatisfiedLinkError. J'ai vérifié tout ce qui est mentionné dans les réponses ci-dessus, mais je recevais toujours l'erreur. J'ai finalement découvert que les noms de méthode JNI ne peuvent pas avoir de soulignement.

Exemple: Java_com_example_app_NativeLib_print_out_stuff <- génère Java.lang.UnsatisfiedLinkError: print_out_stuff

Renommez la fonction print_out_stuff en quelque chose sans trait de soulignement: Java_com_example_app_NativeLib_printOutStuff <- works

0
Awesomeness

voici un tutoriel comment utiliser le code natif: ici

assurez-vous de ne pas avoir d'espaces dans votre chemin de projet . vous ne pouvez pas utiliser de trait de soulignement dans le nom de votre paquet ou de votre projet 

0
karyochi

Remplacer ce 

Java_com_mindtherobot_samples_ndkfoo_NdkFooActivity_invokeNativeFunction

Avec 

Java_your_packege_name_your_Activity_Name_invokeNativeFunction

Exemple si votre paquet est com.pack et que le nom de l’activité est MainActivity, alors 

Java_com_pack1_MainActivity_invokeNativeFunction 

N'oubliez pas d'ajouter une référence dans Activity.

// charge la bibliothèque - le nom correspond à jni/Android.mk 

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

 public native String invokeNativeFunction();

Répétez toutes ces étapes ça devrait marcher :) 

0
Vinayak