Android NDK C ++ JNI (реалізація не знайдена для рідної ...)


86

Я намагаюся використовувати NDK із C ++ і, здається, не можу правильно визначити правильність іменування методів. мій рідний метод такий:

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

із заголовком, загорнутим у зовнішній "C" {} також.

Все добре компілюється, створює файл .so та копіює у папку libs під моїм проектом, але коли я налагоджую та запускаю в Eclipse, я постійно отримую повідомлення коту журналу про те, що "жодної реалізації не знайдено для рідної ...". Чи є щось, чого мені не вистачає, оскільки всі приклади NDK містяться в C?

Дякую.


Ви генеруєте свої заглушки JNI за допомогою javah? Якщо ні, ви повинні бути. :-P
Кріс Джестер-Янг

7
Швидше за все тому, що ви не дзвонилиSystem.loadLibrary
ІгорГанапольський

1
Дякую за Ваше запитання. Сьогодні я дізнався нове.
Shady Mohamed Sherif

Відповіді:


148

Є кілька речей, які можуть призвести до того, що "впровадження не знайдено". Один неправильно вводить ім’я прототипу функції, інший взагалі не вдається завантажити .so. Ви впевнені, System.loadLibrary()що викликається перед використанням методу?

Якщо у вас не JNI_OnLoadвизначена функція, можливо, ви захочете створити її і запропонувати їй виплеснути повідомлення журналу лише для того, щоб переконатися, що бібліотека успішно втягується.

Ви вже уникли найпоширенішої проблеми - забувши скористатися extern "C"- отже, це або вищезазначене, або якась незначна помилка. Як виглядає декларація Java?


13
Ісусе! Ви заощадили мені годину роботи - прочитавши це, я щойно згадав, що прокоментував свій дзвінок loadLibrary ...
zeboidlund

11
Ти врятував і мене! Я в чотири рази перевірив своє ім'я функції та ще кілька речей ... але я забув зовнішнє "С" і навіть не помітив цього у питанні!
Кверті

1
Тепер на веб-сайті документів Android: developer.android.com/training/articles/perf-jni.html#faq_ULE
зникає

2
також є один випадок, про який ніхто не розповідав: ви не можете використовувати '_' (підкреслення) в іменах функцій, оскільки підкреслення інтерпретуються як роздільник пакетів. Отже, можливі лише назви функцій регістру верблюда
Nulik

2
@Nulik: ви можете використовувати '_', якщо уникнути його як "_1".
зникає

18

Додаткова причина цієї помилки: ваше не прикрашене власне ім’я методу не повинно містити підкреслення!

Наприклад, я хотів би експортувати функцію З ім'ям AudioCapture_Ping(). Ось моя декларація про експорт на C:

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

Ось мій клас Java, який імпортував функцію:

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

Я не зміг змусити Android динамічно пов’язувати свій рідний метод, поки не видалив підкреслення:

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

5
Події '_' у декларації на мові Java повинні бути замінені на "_1" у рідній декларації. Див. Таблицю 2-1 у docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/… .
fadden

1
Так очевидно, але мені не вдалося розібратися самостійно після кількох годин налагодження ... Дякую, ти врятував мене!
Георгій Ацев

@ user1222021 У мене запитання, чи можемо ми експортувати метод cpp для всіх дій у проекті, чи потрібно вказувати ім'я діяльності в методі у файлі .cpp?
Balflear

14

У мене була та сама проблема, але для мене помилка була у файлі Android.mk. У мене було:

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

але слід мати таке:

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

зверніть увагу на деталь + = замість цього : =

Я сподіваюся, що це допоможе.


2
Або ви можете просто додати їх усіх в один рядок, або використовувати символ \ 'розриву рядка.
ІгорГанапольський

6

Викликається extern "C", як передбачено в автоматично згенерованому прикладі Studio, але забув обернути весь решту файлу, включаючи наступні функції, у дужки {}. Працювала лише перша функція.


4

Додаткова причина: Використовуйте LOCAL_WHOLE_STATIC_LIBRARIES замість LOCAL_STATIC_LIBRARIES в android.mk. Це перешкоджає бібліотеці оптимізувати невикористані виклики API, оскільки NDK не може виявити використання власних прив'язок з коду Java.


1
Де різниця в: "Використовуйте LOCAL_WHOLE_STATIC_LIBRARIES замість LOCAL_STATIC_LIBRARIES в android.mk"
Джош,

4

Існує приклад cpp під програмами в ndk: https://github.com/android/ndk-samples/blob/master/hello-gl2/app/src/main/cpp/gl_code.cpp


2
ви можете знайти файл cpp в android-ndk / sample / hello-gl2, який є частиною дистрибутиву Android NDK
Yenchi


1
@pevik Знову мертвий.
Mygod


посилання знову мертве
user13107

2

Використовуйте javah (частина Java SDK). Це інструмент саме для цього (генерує заголовок .h із файлу .class).


2

Якщо назва вашого пакету містить _ символ, слід написати _ (один) після _ символу, як показано нижче:

MainActivity.java

package com.example.testcpp_2;

native-lib.cpp

JNICALL
Java_com_example_testcpp_12_MainActivity_stringFromJNI(

0

Я пробую всі вищезазначені рішення, але ніхто не може вирішити мою помилку збірки (jni java.lang.UnsatisfiedLinkError: Не знайдено реалізацію для ...), нарешті я виявив, що забув додати свій вихідний файл verify.cpp до CMakeList.txt add_library розділення (verify.cpp автоматично генерується за допомогою Ctrl + Enter короткий ключ, можливо, інше ім'я файлу), сподіваюся, моя відповідь може комусь допомогти.

моє середовище збірки: Gradle + CMake


0

Я зіткнувся з тією ж проблемою, і в моєму випадку причиною було те, що в назві пакета "RFID_Test" я підкреслив, я перейменував Пакет, і він спрацював. Дякую користувачеві1222021


-3

Я двічі стикався з однією проблемою. Траплялося, що телефон, який я намагався запустити програму з Android Studio, використовував рівень API, який я ще не завантажував в Android Studio.

  1. Оновіть Android Studio до останньої версії
  2. Завантажте необхідний API з Android Studio
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.