Android NDK C ++ JNI (для нативной реализации не найдено…)

86

Я пытаюсь использовать NDK с C ++ и, похоже, не могу правильно сформулировать соглашение об именах методов. мой родной метод выглядит следующим образом:

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

с заголовком, заключенным в extern "C" {} также.

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

Спасибо.

Патрик Кафка
источник
Вы создаете свои заглушки JNI с помощью javah? Если нет, то должно быть. :-P
Крис Джестер-Янг
7
Скорее всего потому, что не позвонилиSystem.loadLibrary
Игорь Ганапольский
1
Спасибо Вам за Ваш вопрос. Сегодня я узнал новое.
Шади Мохамед Шериф

Ответы:

148

Есть несколько вещей, которые могут привести к тому, что «реализация не найдена». Один неправильно понимает имя прототипа функции, другой вообще не может загрузить .so. Вы уверены, System.loadLibrary()что этот метод вызывается до использования метода?

Если у вас не определена JNI_OnLoadфункция, вы можете создать ее, и она выдаст сообщение журнала, чтобы убедиться, что библиотека успешно загружается.

Вы уже избежали наиболее распространенной проблемы - забыли использовать extern "C"- так что это либо вышеупомянутое, либо небольшая орфография. Как выглядит декларация Java?

увядать
источник
13
Иисус! Вы сэкономили мне часы работы - прочитав это, я только что вспомнил, что мой вызов loadLibrary закомментирован ...
zeboidlund
11
Ты меня тоже спас! Я проверил имя своей функции в четыре раза и еще кое-что ... но забыл extern "C" и даже не заметил его в вопросе!
Qwertie
1
Теперь на сайте документации Android: developer.android.com/training/articles/perf-jni.html#faq_ULE
fadden
2
есть еще один случай, о котором никто не сказал: вы не можете использовать '_' (подчеркивание) в именах функций, поскольку подчеркивания считаются разделителями пакетов. Таким образом, возможны только имена функций в верблюжьем регистре
Нулик
2
@Nulik: вы можете использовать '_', если вы используете вместо него «_1».
fadden
18

Дополнительная причина этой ошибки: ваше недекорированное имя собственного метода не должно содержать подчеркивания!

Например, я хотел экспортировать функцию C с именем 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 

обратите внимание на деталь + = вместо : =

Надеюсь, это поможет.

ademar111190
источник
2
Или вы можете просто добавить их все в одну строку или использовать символ разрыва строки `\`.
Игорь Ганапольский
6

Вызывается extern «C», как указано в автоматически созданном примере Studio, но забыл заключить весь остальной файл, включая следующие функции, в квадратные скобки {}. Работала только первая функция.

DragonLord
источник
4

Дополнительная причина: используйте LOCAL_WHOLE_STATIC_LIBRARIES вместо LOCAL_STATIC_LIBRARIES в android.mk. Это не позволяет библиотеке оптимизировать неиспользуемые вызовы API, поскольку NDK не может обнаружить использование собственных привязок из кода Java.

Джон Твигг
источник
1
В чем разница: «Используйте LOCAL_WHOLE_STATIC_LIBRARIES вместо LOCAL_STATIC_LIBRARIES в android.mk»
Джош
4

В приложениях в ndk есть пример cpp: https://github.com/android/ndk-samples/blob/master/hello-gl2/app/src/main/cpp/gl_code.cpp

Мегха
источник
2
вы можете найти файл cpp в android-ndk / samples / hello-gl2, который является частью дистрибутива Android NDK
Yenchi
1
@pevik Он снова мертв.
Mygod
ссылка снова мертва
user13107 05
2

Используйте javah (часть Java SDK). Его инструмент именно для этого (генерирует заголовок .h из файла .class).

MartinH
источник
2

Если имя вашего пакета включает символ _, вы должны написать 1 (один) после символа _, как показано ниже:

MainActivity.java

package com.example.testcpp_2;

native-lib.cpp

JNICALL
Java_com_example_testcpp_12_MainActivity_stringFromJNI(
Oiyio
источник
0

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

моя среда сборки: Gradle + CMake

user2420449
источник
0

Я столкнулся с той же проблемой, и в моем случае причина заключалась в том, что у меня было подчеркивание в имени пакета «RFID_Test». Я переименовал пакет, и он сработал. Спасибо user1222021

Фирас Шруру
источник
-3

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

  1. Обновите Android Studio до последней версии
  2. Загрузите необходимый API из Android Studio
Юливи
источник