Android NDK C ++ JNI (nie znaleziono implementacji dla natywnych…)

86

Próbuję użyć NDK z C ++ i nie mogę uzyskać poprawnej konwencji nazewnictwa metod. moja natywna metoda jest następująca:

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

z nagłówkiem zawiniętym w extern „C” {} aslo.

Wszystko dobrze się kompiluje, tworzy plik .so i kopiuje do folderu libs w moim projekcie, ale kiedy debuguję i uruchamiam w Eclipse, ciągle otrzymuję komunikat „Nie znaleziono implementacji dla natywnego…”. Czy jest coś, czego mi brakuje, ponieważ wszystkie przykłady NDK są w C?

Dzięki.

Patrick Kafka
źródło
Czy generujesz swoje kody pośredniczące JNI przy użyciu javah? Jeśli nie, powinieneś. :-P
Chris Jester-Young
7
Najprawdopodobniej dlatego, że nie zadzwoniłeśSystem.loadLibrary
IgorGanapolsky
1
Dziękuję za Twoje pytanie. Nauczyłem się dzisiaj nowej rzeczy.
Shady Mohamed Sherif

Odpowiedzi:

148

Jest kilka rzeczy, które mogą prowadzić do „braku implementacji”. Jeden z nich powoduje błędną nazwę prototypu funkcji, inny w ogóle nie ładuje pliku .so. Czy na pewno System.loadLibrary()jest wywoływana przed użyciem metody?

Jeśli nie masz JNI_OnLoadzdefiniowanej funkcji, możesz ją utworzyć i poprosić o wyplucie komunikatu dziennika tylko po to, aby sprawdzić, czy biblioteka jest pomyślnie pobierana.

Już uniknąłeś najczęstszego problemu - zapomnienia o użyciu extern "C"- więc jest to albo powyższe, albo drobna literówka. Jak wygląda deklaracja Java?

zanikać
źródło
13
Jezus! Zaoszczędziłeś mi godzin pracy - po przeczytaniu tego przypomniałem sobie, że moje wywołanie loadLibrary zostało zakomentowane ...
zeboidlund
11
Ty też mnie uratowałeś! Czterokrotnie sprawdziłem nazwę swojej funkcji i kilka innych rzeczy ... ale zapomniałem zewnętrznego „C” i nawet nie zauważyłem tego w pytaniu!
Qwertie,
1
Teraz w witrynie z dokumentacją Androida: developer.android.com/training/articles/perf-jni.html#faq_ULE
fadden
2
jest też jeden przypadek, o którym nikt nie mówił: nie można używać znaku „_” (podkreślenia) w nazwach funkcji, ponieważ znaki podkreślenia są interpretowane jako separatory pakietów. Tak więc możliwe są tylko nazwy funkcji wielbłądów
Nulik,
2
@Nulik: możesz użyć „_”, jeśli zmienisz go jako „_1”.
fadden
18

Dodatkowa przyczyna tego błędu: Twoja niezdekorowana nazwa metody natywnej nie może zawierać podkreślenia!

Na przykład chciałem wyeksportować funkcję C. o nazwie AudioCapture_Ping(). Oto moje zgłoszenie wywozowe w C:

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

Oto moja klasa Java importująca funkcję:

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

Nie mogłem zmusić Androida do dynamicznego łączenia się z moją natywną metodą, dopóki nie usunąłem podkreślenia:

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

źródło
5
Wystąpienia „_” w deklaracji języka Java należy zastąpić znakiem „_1” w deklaracji natywnej. Zobacz tabelę 2-1 w docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/… .
fadden
1
Tak oczywiste, ale nie udało mi się tego samodzielnie rozgryźć po kilku godzinach debugowania ... Dzięki, uratowałeś mnie!
George Atsev
@ user1222021 Mam pytanie, czy możemy wyeksportować metodę cpp dla wszystkich działań w projekcie, czy musimy podać nazwę działania w metodzie w pliku .cpp?
Balflear
14

Miałem ten sam problem, ale dla mnie błąd był w pliku Android.mk. Miałem to:

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

ale powinien mieć to:

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

zwróć uwagę na szczegół + = zamiast : =

Mam nadzieję że to pomogło.

ademar111190
źródło
2
Możesz też po prostu dodać je wszystkie w jednej linii lub użyć znaku łamania linii `\`.
Igor Ganapolsky
6

Wywołano extern „C”, jak podano w automatycznie wygenerowanym przykładzie Studio, ale zapomniałem owinąć całą resztę pliku, w tym następujące funkcje, w nawiasy {}. Działała tylko pierwsza funkcja.

Władca Smoków
źródło
4

Dodatkowy powód: użyj LOCAL_WHOLE_STATIC_LIBRARIES zamiast LOCAL_STATIC_LIBRARIES w android.mk. Uniemożliwia to bibliotece optymalizację nieużywanych wywołań API, ponieważ NDK nie może wykryć użycia natywnych powiązań z kodu Java.

John Twigg
źródło
1
Gdzie jest różnica w: „Użyj LOCAL_WHOLE_STATIC_LIBRARIES zamiast LOCAL_STATIC_LIBRARIES w android.mk”
Josh
4

Przykład cpp w aplikacjach w ndk: https://github.com/android/ndk-samples/blob/master/hello-gl2/app/src/main/cpp/gl_code.cpp

Megha
źródło
2
można odnaleźć pliku CPP Android NDK / samples / hello-gl2 który jest częścią dystrybucji Android NDK
Yenchi
1
@pevik Znowu nie żyje.
Mygod
link znów jest martwy
user13107
2

Użyj javah (część Java SDK). Jest to narzędzie właśnie do tego (generuje nagłówek .h z pliku .class).

MartinH
źródło
2

Jeśli nazwa twojego pakietu zawiera _ znak, powinieneś napisać 1 (jeden) po _ znaku, jak pokazano poniżej:

MainActivity.java

package com.example.testcpp_2;

native-lib.cpp

JNICALL
Java_com_example_testcpp_12_MainActivity_stringFromJNI(
oiyio
źródło
0

Próbuję wszystkich powyższych rozwiązań, ale nikt nie może rozwiązać mojego błędu kompilacji (jni java.lang.UnsatisfiedLinkError: Nie znaleziono implementacji dla ...), w końcu stwierdziłem, że zapomniałem dodać mój plik źródłowy verify.cpp do CMakeList.txt add_library segement (verify.cpp jest automatycznie generowana przez skrót Ctrl + Enter, może inna nazwa pliku), mam nadzieję, że moja odpowiedź może komuś pomóc.

moje środowisko kompilacji: Gradle + CMake

user2420449
źródło
0

Napotkałem ten sam problem, aw moim przypadku powodem było podkreślenie w nazwie pakietu „RFID_Test”. Zmieniłem nazwę pakietu i zadziałało. Dzięki user1222021

Firas Shrourou
źródło
-3

Dwukrotnie stanąłem przed tym samym problemem. Zdarzyło się, że telefon, na którym próbowałem uruchomić aplikację z Android Studio, korzystał z poziomu API , którego jeszcze nie pobrałem w Android Studio.

  1. Zaktualizuj Android Studio do najnowszej wersji
  2. Pobierz niezbędne API z Android Studio
Yuliwee
źródło