2012-07-24 26 views
5

Jestem nowy dla jni i przechodziłem przez samouczek, aby wdrożyć prostą natywną metodę, ale otrzymuję niezadowalający link. O ile mi wiadomo, dokładnie postępowałem zgodnie z instrukcjami zawartymi w samouczku. Proszę pomóż mi.Używanie jni w Androidzie: UNsatisfiedLinkError

Oto kod java wrapper:

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

Oto, co wygląda jak moja Android.mk pliku:

LOCAL_PATH: = $ (zadzwonić do mojego-dir)

włączają $ (CLEAR_VARS)

LOCAL_MODULE: = do kwadratu LOCAL_SRC_FILES: = kwadrat.c

obejmują $ (BUILD_SHARED_LIBRARY)

Oto co mój plik .c wygląda następująco:

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

A oto wygląda mój plik .h jak:

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 

Odpowiedz

8

Twój Podpis JNI nie pasuje. W pliku .c, zmiana:

JNIEXPORT jint JNICALL Java_org_edwards_1research_demo_jni_SquaredWrapper_squared 

do

JNIEXPORT jint JNICALL Java_com_cookbook_jni_SquaredWrapper_squared 

Generalnie istnieją dwa sposoby na "klej" native C przez JNI do funkcji Java. Pierwszym z nich jest to, co próbujesz tutaj zrobić, czyli użyj z góry określonego podpisu, który JNI rozpozna i skojarzy z Twoim odpowiednim kodem Java. Druga to przekazywanie wskaźników funkcji, sygnatur i nazw klas Javy do JNI po dołączeniu biblioteki.

Oto druga metoda, które wiążą się z natywną funkcję do odpowiedniego kodu Java (to byłoby plik .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; 

} 

To sporo dłużej, ale daje dużo większą elastyczność przy wiążący natywny kod. Definicja kwadratu i zawarte są tak, jak można się spodziewać. w czwartej linii static const char * SquaredWrapper jest ciągiem z sekwencją znaków z pełną nazwą pakietu klasy, którą chcesz powiązać do kwadratu. W dolnej części znajdują się funkcje JNI_OnLoad i JNI_OnUnLoad, które zajmują się wiązaniem i rozłączaniem funkcji związanych z ładowaniem i rozładowywaniem bibliotek. Ostatnim elementem jest tablica JNINativeMethod. Ta tablica zawiera jako każdy wpis tablicę o rozmiarze 3, której składnikami są nazwa Java metody jako const char *, sygnatura JNI metody Java i natywny wskaźnik funkcji C do wiązania z tą metodą. Sygnatura funkcji JNI informuje środowisko o formacie listy argumentów i zwracanej wartości funkcji Java. Format to "(Arg1Arg2Arg3 ...) Ret", więc funkcja, która przyjmuje int i double i zwraca float, będzie miała podpis "(ID) F", a funkcja, która nie przyjmuje argumentów i zwraca nieważne, będzie "() V".Używam tego poręczny ściągawki pamiętać większość skrót:

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

Powodzenia :)

Edit: Oh, BTW, będziesz prawdopodobnie chcesz dodać podpisy do JNI_OnLoad i JNI_UnOnLoaduj do nagłówka i zmieniaj nazwę prototypu funkcji macierzystej, aby odzwierciedlał nowy plik .c.

+0

Dziękuję bardzo. Czuję się głupio. Właśnie skopiowałem i wkleiłem plik c z samouczka, ale użyłem innej nazwy pakietu niż on. Stąd niedopasowanie. Nie słyszałem o tej drugiej drodze. Czy mógłbyś zamieścić link gdzieś, gdzie mogę przeczytać więcej na ten temat? Dzięki jeszcze raz. – user1487736

+0

Oczywiście preferuję metodę JNI_OnLoad: http://developer.android.com/guide/practices/jni.html#native_libraries i utrzymuję tablicę wszystkich funkcji i podpisów. Lemme napisz jakiś przykładowy kod, a ja poprawię odpowiedź. – AlcoJaguar