2012-07-24 9 views
5

Sono un neofita di jni e stavo esaminando un tutorial per implementare un semplice metodo nativo, ma sto ottenendo un insoddisfiedlinkerror. Per quanto ne so, ho seguito esattamente i passaggi del tutorial. Mi aiuti per favore.Utilizzo di jni in Android: UNsoddisfiedLinkError

Ecco il codice Java con avvolgitore:

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"); 
    } 
} 

Ecco quello che il mio file Android.mk assomiglia:

local_path: = $ (chiamare il mio-dir)

includono $ (CLEAR_VARS)

LOCAL_MODULE: = quadrato LOCAL_SRC_FILES: = squared.c

includono $ (BUILD_SHARED_LIBRARY)

Ecco ciò che il mio file .c assomiglia:

#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); 
} 

Ed ecco ciò che il mio file h assomiglia:

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 

risposta

8

tuo La firma JNI non corrisponde. Nel file .c, il cambiamento:

JNIEXPORT jint JNICALL Java_org_edwards_1research_demo_jni_SquaredWrapper_squared 

a

JNIEXPORT jint JNICALL Java_com_cookbook_jni_SquaredWrapper_squared 

Generalmente ci sono due modi per "colla" C nativo tramite JNI a una funzione Java. Il primo è ciò che stai tentando di fare qui, cioè utilizzare una firma predeterminata che JNI riconoscerà e assocerà al tuo codice Java appropriato. Il secondo consiste nel passare i puntatori di funzione, le firme e i nomi delle classi Java in JNI quando si include la libreria.

Ecco il secondo metodo che avrebbe legato la funzione originaria del codice Java appropriata (questo sarebbe il tuo file .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; 

} 

E 'un buon affare più, ma ti dà molta più flessibilità codice nativo vincolante. La definizione per il quadrato e gli include è come ci si aspetterebbe. sulla quarta riga, const char statico * SquaredWrapper è una stringa con caratteri di escape con il nome del pacchetto completo della classe a cui si desidera associare. Vicino al fondo ci sono le funzioni JNI_OnLoad e JNI_OnUnLoad che si occupano di legare e slegare le funzioni sul carico e scarico della libreria. L'ultimo pezzo è l'array JNINativeMethod. Questa matrice contiene come ogni voce una matrice di dimensione 3 i cui componenti sono il nome Java del metodo come const char *, la firma JNI del metodo Java e il puntatore della funzione C nativa per collegarsi a tale metodo. La firma della funzione JNI comunica all'ambiente il formato dell'elenco degli argomenti e il valore restituito dalla funzione Java. Il formato è "(Arg1Arg2Arg3 ...) Ret", quindi una funzione che accetta un int e raddoppia e restituisce un float avrà una firma di "(ID) F", e una funzione che non accetta argomenti e restituisce void sarebbe "() V".Io uso questo cheat sheet utile per ricordare la maggior parte della stenografia:

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

Buona fortuna :)

Edit: Oh, a proposito, è probabile che desidera aggiungere le firme per JNI_OnLoad e JNI_UnOnLoad all'intestazione e modifica il nome del prototipo della funzione nativa in modo che rifletta il nuovo file .c.

+0

Grazie mille. Mi sento stupido. Ho appena copiato e incollato il file c dal tutorial, ma ho usato un nome di pacchetto diverso da quello che ha fatto. Da qui la mancata corrispondenza. Non ho sentito di quella seconda strada. Potrebbe postare un link dove posso leggere di più? Grazie ancora. – user1487736

+0

Certo, il metodo che preferisco è usare JNI_OnLoad: http://developer.android.com/guide/practices/jni.html#native_libraries e mantenere un array di tutte le mie funzioni e firme. Fammi scrivere un codice di esempio e modificherai la mia risposta. – AlcoJaguar

Problemi correlati