2010-07-16 11 views
24

Soy nuevo en el desarrollo de ndk en Android. He pasado por el sistema de archivos de ndk android. Aquí, explicando lo que hice. 1) he creado una carpeta llamada "jni" y luego creo 2 archivos llamados Android.mk y ndkfoo.c.¿Cómo resolver el java.lang.UnsatisfiedLinkError en NDK en Android?

En Android.mk

LOCAL_PATH := $(call my-dir) 

include $(CLEAR_VARS) 

# Here we give our module name and source file(s) 
LOCAL_MODULE := ndkfoo 
LOCAL_SRC_FILES := ndkfoo.c 

include $(BUILD_SHARED_LIBRARY) 

y en ndkfoo.c

#include <string.h> 
#include <jni.h> 

jstring Java_com_mindtherobot_samples_ndkfoo_NdkFooActivity_invokeNativeFunction(JNIEnv* env, jobject javaThis) { 
return (*env)->NewStringUTF(env, "Hello from native code!"); 
} 

continuación, he creado clase NdkFooActivity, en la que he escrito

// load the library - name matches jni/Android.mk 
static { 
    System.loadLibrary("ndkfoo"); 
} 

pero ahora cuando construir desde cygwin en xp crea archivo .so con éxito luego ejecuto como aplicación de Android. Me da java.lang.UnsatisfiedLinkError en LOGCAT.

Por lo tanto, hágamelo saber dónde estoy equivocado.

Gracias de antemano,

+0

¿Estás seguro de que la clase en la que declaraste invokeNativeFunction() es realmente com.mindtherobot.samples.ndkfoo.NdkFooActivity? Puede publicar todo el código – ognian

+2

Específicamente, incluya la declaración del método nativo en el archivo .java. Muestra las declaraciones de "paquete" y "clase" también. Además, agregue una función JNI_OnLoad a su biblioteca compartida y coloque algunos registros allí para asegurarse de que la biblioteca se esté cargando correctamente. – fadden

+0

Compruebe esta declaración en la ndkfoo.c Java_com_mindtherobot_samples_ndkfoo_NdkFooActivity_invokeNativeFunction, esto debería cambiar a su nombre de paquete como Java_com_your_package_ndkfoo_NdkFooActivity_invokeNativeFunction – pradeep

Respuesta

5

Hay una buena probabilidad de que la firma es incorrecta, como otros han mencionado.

Si ejecuta la utilidad javah, puede encontrar la firma exacta. En la carpeta bin en su proyecto, en el que el APK y es la raíz de la jerarquía de clases de Java se genera, ejecute:

javah -o jni_sig.h com.mindtherobot.whatever.your.package.is.NdkFooActivity

... y, si tiene el nombre del paquete y el nombre de clase correcto, escribirá un encabezado (llamado jni_sig.h) con la (s) firma (s) de función correctas para cualquier función nativa. Copie eso en su encabezado y archivo .c, agregue parámetros según sea necesario, y debería funcionar correctamente.

+1

Gracias. En mi sistema, debe ejecutarse desde el subdirectorio Clases. – weston

23

Creo que olvidó cambiar el nombre del paquete.

Java_com_mindtherobot_samples_ndkfoo

Debe ser su paquete de lo que se ha especificado la creación del proyecto.

3

estoy bastante seguro de que debe ser:

JNIEXPORT jstring JNICALL Java_com_mindtherobot_samples_ndkfoo_NdkFooActivity_invokeNativeFunction(JNIEnv* env, jobject javaThis) { 
return (*env)->NewStringUTF(env, "Hello from native code!"); 
} 

Qué SDK se le focalización y la versión del NDK tiene usted? ¿El error que recibes dice que no pudo cargar la biblioteca o que hubo un método no implementado? De cualquier manera, asegúrese de que no tenga android: hasCode = "false" establecido en la etiqueta de la aplicación en su manifiesto.

También puede abrir el archivo APK después de una compilación utilizando winrar o algo similar para asegurarse de que el archivo libndkfoo.so realmente se está incluyendo con el paquete.

De cualquier manera si no está declarando la función nativa en NdkFooActivity obtendrá ese error, es decir

pública invokeNativeFunction cadena nativa estática();

11

Aunque este no ha sido el problema del OP, tuve el mismo java.lang.UnsatisfiedLinkError debido a la falta

static { 
    System.loadLibrary("mylibraryname"); 
} 
+0

normalmente causa el siguiente problema: 'java.lang.ExceptionInInitializerError java.lang.UnsatisfiedLinkError: Library xyz ... not found' – ademar111190

+0

¿Cómo lo resuelves en el caso anterior? – Ahmed

1

Crear un archivo Application.mk en folder.Copy JNI siguiente línea y pegarlo en Application.mk y save.Now construir el proyecto con su cgywin y correr de nuevo

APP_ABI: = armeabi armeabi-v7a

4

Quizás ya no sea relevante pero, hasta donde yo sé, también necesita agregar el prefijo "lib" al nombre de su biblioteca nativa. En su caso, debe cambiar Android.mk a "LOCAL_MODULE: = libndkfoo" y mantener "System.loadLibrary (" ndkfoo ");" como están las cosas. Verifique el código de muestra ndk.

+0

No resuelve el problema que aún permanece ... –

20

También (acabo de enterarme de este problema), tenga en cuenta que System.loadLibrary() arrojará siempre una excepción si está probando el emulador Intel Atom x86. Funciona muy bien en los emuladores regulares de Android y la depuración en un dispositivo físico.

+0

+1 Eso ayudó. ¿Cómo supiste esto? – quinestor

+2

@Daniel Rodriguez: Muchas gracias, muuuuuuuucho. :) :) :) –

+0

+1, y sí, ¿cómo lo supiste? –

0

También tuve un error java.lang.UnsatisfiedLinkError. Verifiqué todo lo mencionado en las respuestas anteriores, pero aún recibía el error. Finalmente descubrí que los nombres del método JNI no pueden tener guiones bajos.

Ejemplo: Java_com_example_app_NativeLib_print_out_stuff < - genera java.lang.UnsatisfiedLinkError: print_out_stuff

cambiar la función de print_out_stuff a algo sin subrayados: Java_com_example_app_NativeLib_printOutStuff < - obras

0

aquí hay un tutorial de cómo utilizar código nativo: here

asegúrese de no tener ningún espacio en la ruta del proyecto. tampoco puede usar un guión bajo en el nombre de su paquete o proyecto.

1

El nombre del método Java_com_mindtherobot_samples_ndkfoo_NdkFooActivity_invokeNativeFunction

no puede ser igual que el de su nombre de paquete o nombre de la clase. Para que este nombre de método sea exactamente el mismo, debe usar javah.

Esto hará un archivo de encabezado que tendrá el mismo nombre de método que se requiere. Para hacer que este archivo de encabezado vaya a la carpeta de clases en el contenedor de su proyecto (asegúrese de haber creado el archivo java con método estático y construir adecuadamente) por este comando en su terminal

~/workspace/Android_Example2/bin/classes$

en este directorio escribir el siguiente comando

sudo javah -jni com.NDK.android_example2.MainActivity 

Cambiar el nombre del paquete y la clase nombre de acuerdo a su proyecto. Esto creará una com_NDK_android_example2_MainActivity.h en su carpeta de clases.

Simplemente mueva este archivo a su carpeta jni. En este archivo, habrá métodos estáticos que haya creado en el archivo MainActivity.java pero que se hayan declarado no implementados y que implementará en su archivo C.

NOTA: Al copiar el método, compruebe que los parámetros del método deben declararse, por lo que debe declararlos en su archivo C.

Espero que esta ayuda.

0

Reemplazar esta

Java_com_mindtherobot_samples_ndkfoo_NdkFooActivity_invokeNativeFunction 

Con

Java_your_packege_name_your_Activity_Name_invokeNativeFunction 

Ejemplo si la caja contiene com.pack y el nombre Nombre de la actividad es MainActivity continuación

Java_com_pack1_MainActivity_invokeNativeFunction 

No se olvide de añadir una referencia en Actividad.

// cargar la biblioteca - nombre coincide con JNI/Android.mk

static { 
     System.loadLibrary("ndkfoo"); 
     } 

public native String invokeNativeFunction(); 

Repita todos estos pasos que debería funcionar :)

2
JNIEXPORT jstring JNICALL Java_com_mindtherobot_samples_ndkfoo_NdkFooActivity_invokeNativeFunction(JNIEnv* env, jobject javaThis) { 
return (*env)->NewStringUTF(env, "Hello from native code!"); 
} 

el problema es que se compila para un procesador objetivo y ejecutar en otro. si compila en ARM (armeabi), entonces ejecute emulador basado en armeabi. crear un archivo llamado application.mk en misma carpeta que Android.mk y poner dentro de él uno de lo siguiente:

  1. APP_ABI: = x 86
  2. APP_ABI: = armeabi
  3. APP_ABI: = MIPS
  4. APP_ABI: = armeabi x86 mips // para compilar en todos los destinos y obtendrás 3 * .so archivos

y luego compilar-> ejecutar. debería funcionar.

+0

Ejecutado en un dispositivo real, y funcionó. Gracias.... –