Android NDK C ++ JNI (aucune implémentation trouvée pour le natif…)

86

J'essaie d'utiliser le NDK avec C ++ et je n'arrive pas à obtenir la convention de dénomination de méthode correcte. ma méthode native est la suivante:

extern "C" {
JNIEXPORT void JNICALL Java_com_test_jnitest_SurfaceRenderer_drawFromJni
(JNIEnv* env, jclass c)
{
   //
}
}

avec un en-tête enveloppé dans extern "C" {} également.

Tout se compile correctement, crée un fichier .so et se copie dans le dossier libs sous mon projet, mais quand je débogue et que je lance dans Eclipse, je continue à recevoir un message de chat de journal indiquant "aucune implémentation trouvée pour le natif ...". Y a-t-il quelque chose qui me manque car tous les exemples NDK sont en C?

Merci.

Patrick Kafka
la source
Générez-vous vos stubs JNI en utilisant javah? Sinon, vous devriez l'être. :-P
Chris Jester-Young
7
Très probablement parce que vous n'avez pas appeléSystem.loadLibrary
IgorGanapolsky
1
Merci pour votre question. J'ai appris une nouvelle chose aujourd'hui.
Shady Mohamed Sherif

Réponses:

148

Il y a plusieurs choses qui peuvent conduire à "aucune implémentation trouvée". L'un se trompe sur le nom du prototype de la fonction, un autre ne parvient pas du tout à charger le .so. Êtes-vous sûr que cela System.loadLibrary()est appelé avant que la méthode ne soit utilisée?

Si vous n'avez pas JNI_OnLoaddéfini de fonction, vous voudrez peut-être en créer une et lui faire cracher un message de journal juste pour vérifier que la bibliothèque est bien insérée.

Vous avez déjà esquivé le problème le plus courant - oublier d'utiliser extern "C"- c'est donc soit le problème ci-dessus, soit une légère faute d'orthographe. À quoi ressemble la déclaration Java?

fadden
la source
13
Jésus! Vous m'avez économisé des heures de travail - en lisant ceci, je venais de me souvenir que mon appel à loadLibrary avait été commenté ...
zeboidlund
11
Tu m'as sauvé aussi! J'ai quadruple vérifié le nom de ma fonction et quelques autres choses ... mais j'ai oublié extern "C", et je ne l'ai même pas remarqué dans la question!
Qwertie
1
Maintenant sur le site de documentation Android: developer.android.com/training/articles/perf-jni.html#faq_ULE
fadden
2
il y a aussi un cas dont personne n'a parlé: vous ne pouvez pas utiliser '_' (traits de soulignement) dans les noms de fonctions car les traits de soulignement sont interprétés comme séparateur de paquet. Ainsi, seuls les noms de fonction de cas de chameau sont possibles
Nulik
2
@Nulik: vous pouvez utiliser '_' si vous l' échappez en tant que "_1".
fadden
18

Une cause supplémentaire de cette erreur: votre nom de méthode native non décoré ne doit pas contenir de trait de soulignement!

Par exemple, je voulais exporter une fonction C nommée AudioCapture_Ping(). Voici ma déclaration d'exportation en C:

JNI_EXPORT int Java_com_obsidian_mobilehashhost_MainActivity_AudioCapture_Ping(JNIEnv *pJniEnv, jobject object);  //Notice the underscore before Ping

Voici ma classe Java important la fonction:

package com.obsidian.mobileaudiohashhost;
...
public class MainActivity extends Activity {
    private native int AudioCapture_Ping();  // FAILS
    ...

Je ne pouvais pas faire en sorte qu'Android se lie dynamiquement à ma méthode native jusqu'à ce que j'aie supprimé le trait de soulignement:

JNI_EXPORT int Java_com_obsidian_mobilehashhost_MainActivity_AudioCapturePing(JNIEnv *pJniEnv, jobject object); 

package com.obsidian.mobileaudiohashhost;
...
public class MainActivity extends Activity {
    private native int AudioCapturePing();  // THIS WORKS!
    ...

la source
5
Les occurrences de '_' dans la déclaration du langage Java doivent être remplacées par "_1" dans la déclaration native. Voir le tableau 2-1 dans docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/… .
fadden le
1
Tellement évident, pourtant je n'ai pas réussi à le comprendre seul après plusieurs heures de débogage ... Merci, vous m'avez sauvé!
George Atsev
@ user1222021 J'ai une question, pouvons-nous exporter la méthode cpp pour toutes les activités du projet, devons-nous spécifier le nom de l'activité dans la méthode dans le fichier .cpp?
Balflear
14

J'ai eu le même problème, mais pour moi, l'erreur était dans le fichier Android.mk. Je l'avais:

LOCAL_SRC_FILES := A.cpp
LOCAL_SRC_FILES := B.cpp 

mais devrait avoir ceci:

LOCAL_SRC_FILES := A.cpp
LOCAL_SRC_FILES += B.cpp 

notez le détail + = à la place : =

J'espère que cela aide.

ademar111190
la source
2
Ou vous pouvez simplement les ajouter tous sur une seule ligne, ou utiliser le caractère de saut de ligne `\`.
IgorGanapolsky
6

Appelé extern "C" comme indiqué dans l'exemple Studio généré automatiquement, mais j'ai oublié de placer le reste du fichier, y compris les fonctions suivantes, entre crochets {}. Seule la première fonction a fonctionné.

Seigneur Dragon
la source
4

Une raison supplémentaire: utilisez LOCAL_WHOLE_STATIC_LIBRARIES au lieu de LOCAL_STATIC_LIBRARIES dans android.mk. Cela empêche la bibliothèque d'optimiser les appels d'API inutilisés car le NDK ne peut pas détecter l'utilisation des liaisons natives du code java.

John Twigg
la source
1
Où est la différence dans: "Utilisez LOCAL_WHOLE_STATIC_LIBRARIES au lieu de LOCAL_STATIC_LIBRARIES dans android.mk"
Josh
4

Il y a un exemple de cpp sous les applications dans ndk: https://github.com/android/ndk-samples/blob/master/hello-gl2/app/src/main/cpp/gl_code.cpp

Megha
la source
2
vous pouvez trouver le fichier cpp dans android-ndk / samples / hello-gl2 qui fait partie de la distribution Android NDK
Yenchi
1
@pevik Il est de nouveau mort.
Mygod
link is dead again
user13107
2

Utilisez javah (qui fait partie du SDK Java). C'est l'outil exactement pour cela (génère un en-tête .h à partir du fichier .class).

MartinH
la source
2

Si le nom de votre package comprend le caractère _, vous devez écrire 1 (un) après le caractère _ comme indiqué ci-dessous:

MainActivity.java

package com.example.testcpp_2;

native-lib.cpp

JNICALL
Java_com_example_testcpp_12_MainActivity_stringFromJNI(
oiyio
la source
0

J'essaie toutes les solutions ci-dessus, mais personne ne peut résoudre mon erreur de construction (jni java.lang.UnsatisfiedLinkError: Aucune implémentation trouvée pour ...), enfin j'ai trouvé que j'avais oublié d'ajouter mon fichier source verify.cpp à CMakeList.txt add_library segement (verify.cpp est généré automatiquement par Ctrl + Entrée, peut-être un autre nom de fichier), j'espère que ma réponse pourra aider quelqu'un.

mon environnement de construction: Gradle + CMake

user2420449
la source
0

J'ai fait face au même problème, et dans mon cas, la raison était que j'avais un trait de soulignement dans le nom du paquet "RFID_Test" J'ai renommé le paquet et cela a fonctionné. Merci user1222021

Firas Shrourou
la source
-3

J'ai rencontré deux fois le même problème. Il est arrivé que le téléphone sur lequel j'ai essayé de démarrer l'application à partir d'Android Studio utilisait un niveau d'API que je n'ai pas encore téléchargé dans Android Studio.

  1. Mettre à niveau Android Studio vers la dernière version
  2. Téléchargez l'API nécessaire depuis Android Studio
Yuliwee
la source