2012-07-24 8 views
5

Soy nuevo en jni, y estaba repasando un tutorial para implementar un método nativo simple, pero estoy obteniendo un error insatisfecho. Por lo que sé, seguí los pasos en el tutorial exactamente. Por favor, ayúdame.Uso de jni en Android: UNsatisfiedLinkError

Aquí está el código de Java envoltorio:

package com.cookbook.jni; 

public class SquaredWrapper { 

    // Declare native method (and make it public to expose it directly) 
    public static native int squared(int base); 

    // Provide additional functionality, that "extends" the native method 
    public static int to4(int base) 
    { 
     int sq = squared(base); 
     return squared(sq); 
    } 

    // Load library 
    static { 
     System.loadLibrary("squared"); 
    } 
} 

Esto es lo que se ve mi archivo Android.mk como:

LOCAL_PATH: = $ (llamar a mi-dir)

incluyen $ (CLEAR_VARS)

LOCAL_MODULE: = cuadrado LOCAL_SRC_FILES: = squared.c

incluyen $ (BUILD_SHARED_LIBRARY)

Esto es lo que se ve mi archivo .c como:

#include "squared.h" 
#include <jni.h> 

JNIEXPORT jint JNICALL Java_org_edwards_1research_demo_jni_SquaredWrapper_squared 
    (JNIEnv * je, jclass jc, jint base) 
{ 
    return (base*base); 
} 

Y aquí es lo que parece mi archivo .h como:

enter code here/* DO NOT EDIT THIS FILE - it is machine generated */ 
#include <jni.h> 
/* Header for class com_cookbook_jni_SquaredWrapper */ 

#ifndef _Included_com_cookbook_jni_SquaredWrapper 
#define _Included_com_cookbook_jni_SquaredWrapper 
#ifdef __cplusplus 
extern "C" { 
#endif 
/* 
* Class:  com_cookbook_jni_SquaredWrapper 
* Method: squared 
* Signature: (I)I 
*/ 
JNIEXPORT jint JNICALL Java_com_cookbook_jni_SquaredWrapper_squared 
    (JNIEnv *, jclass, jint); 

#ifdef __cplusplus 
} 
#endif 
#endif 

Respuesta

8

Su La firma JNI no coincide. En el archivo .c, cambie:

JNIEXPORT jint JNICALL Java_org_edwards_1research_demo_jni_SquaredWrapper_squared 

a

JNIEXPORT jint JNICALL Java_com_cookbook_jni_SquaredWrapper_squared 

Generalmente hay dos maneras de "pegamento" C nativa a través de JNI a una función de Java. Lo primero es lo que intenta hacer aquí, es decir, usar una firma predeterminada que JNI reconocerá y asociará con su código Java apropiado. El segundo es pasar los punteros a las funciones, las firmas y los nombres de las clases Java a JNI cuando se incluye la biblioteca.

Aquí está el segundo método que obligar a la función nativa al código Java adecuada (este sería el archivo .c):

#include "squared.h" 
#include <jni.h> 

static const char* SquaredWrapper = "com/cookbook/jni/SquaredWrapper"; 

jint squared(JNIEnv * env, jobject this, jint base) { 
    return (base*base); 
} 

// Methods to register for SquaredWrapper 
static JNINativeMethod SquareWrapperMethods[] = { 
     {"squared", "(I)I", squared} 
}; 

jint JNI_OnLoad(JavaVM* vm, void* reserved) { 
    JNIEnv* env; 
    if ((*vm)->GetEnv(vm, (void **) &env, JNI_VERSION_1_6) != JNI_OK) 
     return JNI_ERR; 

    jclass class = (*env)->FindClass(env, SquaredWrapper); 
    (*env)->RegisterNatives(env, class, SquaredWrapperMethods, sizeof(SquaredWrapperMethods)/sizeof(SquaredWrapperMethods[0])); 

    return JNI_VERSION_1_6; 
} 

void JNI_OnUnload(JavaVM* vm, void* reserved) { 
    JNIEnv* env; 
    if ((*vm)->GetEnv(vm, (void**) &env, JNI_VERSION_1_6) != JNI_OK) 
     return; 

    jclass class = (*env)->FindClass(env, SquaredWrapper); 
    (*env)->UnregisterNatives(env, class); 

    return; 

} 

Es mucho más tiempo pero le da mucha más flexibilidad a la hora código nativo vinculante. La definición de cuadrado y las inclusiones son las que cabría esperar. en la 4ª línea, el static const char * SquaredWrapper es una cadena escapada con el nombre completo del paquete de la clase a la que desea enlazar al cuadrado. Cerca de la parte inferior se encuentran las funciones JNI_OnLoad y JNI_OnUnLoad que se encargan de vincular y desvincular las funciones de carga y descarga de la biblioteca. La última pieza es la matriz JNINativeMethod. Esta matriz contiene como entrada una matriz de tamaño 3 cuyos componentes son el nombre Java del método como const char *, la firma JNI del método Java y el puntero de la función C nativo para enlazar a ese método. La firma de la función JNI le dice al entorno el formato de la lista de argumentos y el valor de retorno de la función Java. El formato es "(Arg1Arg2Arg3 ...) Ret", por lo que una función que toma un int y un doble y devuelve un flotante tendría una firma de "(ID) F", y una función que no toma argumentos y devuelve vacía sería "() V".Yo uso esta hoja de trucos práctica de recordar la mayor parte de la taquigrafía:

http://dev.kanngard.net/Permalinks/ID_20050509144235.html

Buena suerte :)

Editar: Ah, por cierto, es probable que desee añadir las firmas para JNI_OnLoad y JNI_UnOnLoad a su encabezado, y cambie el nombre de su prototipo nativo de función para reflejar el nuevo archivo .c.

+0

Muchas gracias. Me siento estupido. Acabo de copiar y pegar el archivo c del tutorial, pero utilicé un nombre de paquete diferente que él. De ahí el desajuste. No he oído hablar de esa segunda forma. ¿Podría publicar un enlace a algún lugar donde pueda leer más sobre él? Gracias de nuevo. – user1487736

+0

Claro, el método que prefiero es usar JNI_OnLoad: http://developer.android.com/guide/practices/jni.html#native_libraries y mantener una matriz de todas mis funciones y firmas. Déjame escribir un código de ejemplo y voy a editar mi respuesta. – AlcoJaguar