Android NDK C ++ JNI (keine Implementierung für native gefunden…)

86

Ich versuche, das NDK mit C ++ zu verwenden, und es scheint, dass die Namenskonvention für Methoden nicht korrekt ist. Meine native Methode lautet wie folgt:

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

mit einem Header in extern "C" {} aslo.

Alles lässt sich gut kompilieren, erstellt eine .so-Datei und kopiert sie in den libs-Ordner unter meinem Projekt. Wenn ich jedoch in Eclipse debugge und ausführe, erhalte ich immer wieder die Meldung "Keine Implementierung für native gefunden ...". Fehlt mir etwas, da alle NDK-Beispiele in C sind?

Vielen Dank.

Patrick Kafka
quelle
Generieren Sie Ihre JNI-Stubs mit javah? Wenn nicht, sollten Sie sein. :-P
Chris Jester-Young
7
Höchstwahrscheinlich, weil Sie nicht angerufen habenSystem.loadLibrary
IgorGanapolsky
1
Danke, für ihre Frage. Ich habe heute etwas Neues gelernt.
Shady Sherif

Antworten:

145

Es gibt einige Dinge, die dazu führen können, dass "keine Implementierung gefunden wird". Einer hat den falschen Namen des Funktionsprototyps, ein anderer kann die .so überhaupt nicht laden. Sind Sie sicher, dass System.loadLibrary()dies aufgerufen wird, bevor die Methode verwendet wird?

Wenn Sie keine JNI_OnLoadFunktion definiert haben, möchten Sie möglicherweise eine erstellen und eine Protokollnachricht ausspucken lassen, um zu überprüfen, ob die Bibliothek erfolgreich abgerufen wird.

Sie sind bereits dem häufigsten Problem ausgewichen - Sie haben vergessen, es zu verwenden extern "C"-, also ist es entweder das oben genannte oder ein leichter Rechtschreibfehler. Wie sieht die Java-Deklaration aus?

verblassen
quelle
13
Jesus! Sie haben mir Stunden Arbeit erspart - als ich dies las, hatte ich mich gerade daran erinnert, dass ich meinen loadLibrary-Anruf auskommentiert hatte ...
zeboidlund
11
Du hast mich auch gerettet! Ich habe meinen Funktionsnamen und ein paar andere Dinge vierfach überprüft ... aber ich habe externes "C" vergessen und es in der Frage nicht einmal bemerkt!
Qwertie
1
Jetzt auf der Android-Dokumentenseite: developer.android.com/training/articles/perf-jni.html#faq_ULE
fadden
2
Es gibt auch einen Fall, von dem niemand erzählt hat: Sie können '_' (Unterstriche) nicht in Funktionsnamen verwenden, da Unterstriche als Pakettrennzeichen interpretiert werden. Es sind also nur
Kamelfallfunktionsnamen
2
@Nulik: Sie können '_' verwenden, wenn Sie es als "_1" maskieren .
Fadden
18

Eine zusätzliche Ursache für diesen Fehler: Ihr nicht dekorierter nativer Methodenname darf keinen Unterstrich enthalten!

Zum Beispiel wollte ich eine C-Funktion mit dem Namen exportieren AudioCapture_Ping(). Hier ist meine Exporterklärung in C:

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

Hier war meine Java-Klasse, die die Funktion importierte:

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

Ich konnte Android nicht dazu bringen, dynamisch auf meine native Methode zu verlinken, bis ich den Unterstrich entfernt hatte:

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!
    ...

quelle
5
Vorkommen von '_' in der Java-Deklaration müssen in der nativen Deklaration durch "_1" ersetzt werden. Siehe Tabelle 2-1 unter docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/… .
Fadden
1
So offensichtlich, aber ich habe es nach mehreren Stunden Debugging nicht geschafft, es selbst herauszufinden ... Danke, du hast mich gerettet!
George Atsev
@ user1222021 Ich habe eine Frage: Können wir die CPP-Methode für alle Aktivitäten im Projekt exportieren? Müssen wir den Aktivitätsnamen in der Methode in der CPP-Datei angeben?
Balflear
14

Ich hatte das gleiche Problem, aber für mich war der Fehler in der Datei Android.mk. Ich hatte es:

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

sollte aber folgendes haben:

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

Beachten Sie stattdessen das Detail + = : =

Ich hoffe das hilft.

ademar111190
quelle
2
Oder Sie können sie einfach alle in einer Zeile hinzufügen oder das Zeilenumbruchzeichen "\" verwenden.
IgorGanapolsky
6

Externes "C" aufgerufen, wie im automatisch generierten Studio-Beispiel angegeben, aber vergessen, den gesamten Rest der Datei, einschließlich der folgenden Funktionen, in {} Klammern zu setzen. Nur die erste Funktion funktionierte.

Drachen Lord
quelle
4

Ein weiterer Grund: Verwenden Sie LOCAL_WHOLE_STATIC_LIBRARIES anstelle von LOCAL_STATIC_LIBRARIES in android.mk. Dies verhindert, dass die Bibliothek nicht verwendete API-Aufrufe optimiert, da das NDK die Verwendung der nativen Bindungen aus Java-Code nicht erkennen kann.

John Twigg
quelle
1
Wo ist der Unterschied in: "Verwenden Sie LOCAL_WHOLE_STATIC_LIBRARIES anstelle von LOCAL_STATIC_LIBRARIES in android.mk"
Josh
4

Unter Apps in ndk gibt es ein CPP-Beispiel: https://github.com/android/ndk-samples/blob/master/hello-gl2/app/src/main/cpp/gl_code.cpp

Megha
quelle
2
Sie finden die CPP-Datei in android-ndk / samples / hello-gl2, die Teil der Android NDK-Distribution ist
Yenchi
1
@evik Es ist wieder tot.
Mygod
Link ist wieder tot
user13107
2

Verwenden Sie Javah (Teil des Java SDK). Es ist das Werkzeug genau dafür (generiert einen .h-Header aus einer .class-Datei).

MartinH
quelle
2

Wenn Ihr Paketname _ Zeichen enthält, sollten Sie 1 (eins) nach _ Zeichen schreiben, wie unten gezeigt:

MainActivity.java

package com.example.testcpp_2;

native-lib.cpp

JNICALL
Java_com_example_testcpp_12_MainActivity_stringFromJNI(
oiyio
quelle
0

Ich versuche alle oben genannten Lösungen, aber niemand kann meinen Erstellungsfehler beheben (jni java.lang.UnsatisfiedLinkError: Keine Implementierung gefunden für ...). Endlich habe ich festgestellt, dass ich vergessen habe, meine verify.cpp-Quelldatei zu CMakeList.txt hinzuzufügen add_library segement (verify.cpp wird automatisch durch Strg + Eingabetaste, möglicherweise einen anderen Dateinamen generiert), hoffe, meine Antwort kann jemandem helfen.

meine Build-Umgebung: Gradle + CMake

user2420449
quelle
0

Ich hatte das gleiche Problem und in meinem Fall war der Grund, dass ich den Paketnamen "RFID_Test" unterstrichen hatte. Ich habe das Paket umbenannt und es hat funktioniert. Vielen Dank user1222021

Firas Shrourou
quelle
-3

Ich hatte zweimal das gleiche Problem. Es kam vor, dass das Telefon, auf dem ich versucht habe, die App von Android Studio aus zu starten, eine API-Ebene verwendete , die ich in Android Studio noch nicht heruntergeladen habe.

  1. Aktualisieren Sie Android Studio auf die neueste Version
  2. Laden Sie die erforderliche API aus Android Studio herunter
Yuliwee
quelle