Android NDK C ++ JNI (no se encontró implementación para nativo…)

86

Estoy tratando de usar el NDK con C ++ y parece que no puedo conseguir que la convención de nomenclatura del método sea correcta. mi método nativo es el siguiente:

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

con un encabezado envuelto en extern "C" {} también.

Todo se compila bien, crea un archivo .so y lo copia en la carpeta libs debajo de mi proyecto, pero cuando depuro y ejecuto en Eclipse sigo recibiendo un mensaje de log cat que dice "no se encontró implementación para nativo ...". ¿Hay algo que me falta ya que todos los ejemplos de NDK están en C?

Gracias.

Patrick Kafka
fuente
¿Está generando sus stubs JNI usando javah? Si no, deberías estarlo. :-P
Chris Jester-Young
7
Probablemente porque no System.loadLibrary
llamaste
1
Gracias por su pregunta. Hoy aprendí algo nuevo.
Shady Mohamed Sherif

Respuestas:

148

Hay un par de cosas que pueden llevar a que "no se encuentre implementación". Uno está equivocando el nombre del prototipo de la función, otro no carga el .so en absoluto. ¿Estás seguro de que System.loadLibrary()se está llamando antes de que se utilice el método?

Si no tiene una JNI_OnLoadfunción definida, es posible que desee crear una y hacer que escupe un mensaje de registro solo para verificar que la biblioteca se esté ingresando correctamente.

Ya esquivó el problema más común, olvidarse de usar extern "C", por lo que es lo anterior o un pequeño error ortográfico. ¿Cómo se ve la declaración de Java?

fadden
fuente
13
¡Jesús! Me ahorraste horas de trabajo; al leer esto, acababa de recordar que había comentado mi llamada a loadLibrary ...
zeboidlund
11
¡Tú también me salvaste! Verifiqué cuádruple el nombre de mi función y un par de cosas más ... ¡pero olvidé el externo "C" y ni siquiera lo noté en la pregunta!
Qwertie
1
Ahora en el sitio de documentos de Android: developer.android.com/training/articles/perf-jni.html#faq_ULE
fadden
2
También hay un caso del que nadie habló: no puede usar '_' (guiones bajos) en los nombres de las funciones, ya que los guiones bajos se interpretan como separadores de paquetes. Por lo tanto, solo son posibles los nombres de función de caso de camello
Nulik
2
@Nulik: se puede utilizar '_' si escapas que como "_1".
fadden
18

Una causa adicional de este error: el nombre de su método nativo sin decorar no debe contener un guión bajo.

Por ejemplo, quería exportar una función de C llamada AudioCapture_Ping(). Aquí está mi declaración de exportación en C:

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

Aquí estaba mi clase de Java importando la función:

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

No pude hacer que Android se vincule dinámicamente a mi método nativo hasta que elimine el guión bajo:

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

fuente
5
Las apariciones de '_' en la declaración del lenguaje Java deben reemplazarse por "_1" en la declaración nativa. Consulte la tabla 2-1 en docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/… .
fadden
1
Tan obvio, pero no logré resolverlo por mi cuenta después de varias horas de depuración ... ¡Gracias, me salvaste!
George Atsev
@ user1222021 Tengo una pregunta, ¿podemos exportar el método cpp para todas las actividades del proyecto? ¿Necesitamos especificar el nombre de la actividad en el método en el archivo .cpp?
Balflear
14

Tuve el mismo problema, pero para mí el error estaba en el archivo Android.mk. Lo tuve:

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

pero debería tener esto:

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

nota el detalle + = en su lugar : =

Espero que eso ayude.

ademar111190
fuente
2
O simplemente puede agregarlos todos en una línea, o usar el carácter de salto de línea `\`.
IgorGanapolsky
6

Llamado externo "C" como se indica en el ejemplo de Studio generado automáticamente, pero se olvidó de envolver todo el resto del archivo, incluidas las funciones siguientes, entre corchetes {}. Solo funcionó la primera función.

Señor de los Dragones
fuente
4

Una razón adicional: use LOCAL_WHOLE_STATIC_LIBRARIES en lugar de LOCAL_STATIC_LIBRARIES en android.mk. Esto evita que la biblioteca optimice las llamadas API no utilizadas porque el NDK no puede detectar el uso de los enlaces nativos del código Java.

John Twigg
fuente
1
¿Dónde está la diferencia en: "Use LOCAL_WHOLE_STATIC_LIBRARIES en lugar de LOCAL_STATIC_LIBRARIES en android.mk"
Josh
2

Utilice javah (parte del SDK de Java). Es la herramienta exactamente para esto (genera un encabezado .h a partir del archivo .class).

MartinH
fuente
2

Si el nombre de su paquete incluye el carácter _, debe escribir 1 (uno) después del carácter _ como se muestra a continuación:

MainActivity.java

package com.example.testcpp_2;

native-lib.cpp

JNICALL
Java_com_example_testcpp_12_MainActivity_stringFromJNI(
oiyio
fuente
0

Intento todas las soluciones anteriores, pero nadie puede resolver mi error de compilación (jni java.lang.UnsatisfiedLinkError: No se encontró implementación para ...), finalmente descubrí que olvidé agregar mi archivo fuente verify.cpp a CMakeList.txt add_library segement (verify.cpp se genera automáticamente mediante Ctrl + Enter tecla corta, tal vez otro nombre de archivo), espero que mi respuesta pueda ayudar a alguien.

mi entorno de compilación: Gradle + CMake

usuario2420449
fuente
0

Enfrenté el mismo problema y, en mi caso, la razón fue que tenía un subrayado en el nombre del paquete "RFID_Test". Cambié el nombre del paquete y funcionó. Gracias user1222021

Firas Shrourou
fuente
-3

Enfrenté el mismo problema dos veces. Sucedió que el teléfono que intenté iniciar la aplicación desde Android Studio usaba un nivel de API que aún no había descargado en Android Studio.

  1. Actualice Android Studio a la última versión
  2. Descargue la API necesaria desde Android Studio
Yuliwee
fuente