Chiamare un metodo java da c ++ in Android


91

Sto cercando di ottenere una semplice chiamata al metodo Java da C ++ mentre Java chiama il metodo nativo. Ecco il codice Java:

public class MainActivity extends Activity {
    private static String LIB_NAME = "name";

    static {
        System.loadLibrary(LIB_NAME);
    }

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        TextView tv = (TextView) findViewById(R.id.textview);
        tv.setText(this.getJniString());
    }

    public void messageMe(String text) {
        System.out.println(text);
    }

    public native String getJniString();
}

Sto cercando di chiamare il messageMemetodo dal codice nativo nel processo di getJniString*chiamata del metodo da Java a nativo.

native.cpp:

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

jstring Java_the_package_MainActivity_getJniString( JNIEnv* env, jobject obj, jint depth ){

//    JavaVM *vm;
//    JNIEnv *env;
//    JavaVMInitArgs vm_args;
//    vm_args.version = JNI_VERSION_1_2;
//    vm_args.nOptions = 0;
//    vm_args.ignoreUnrecognized = 1;
//
//    // Construct a VM
//    jint res = JNI_CreateJavaVM(&vm, (void **)&env, &vm_args);

    // Construct a String
    jstring jstr = env->NewStringUTF("This string comes from JNI");
    // First get the class that contains the method you need to call
    jclass clazz = env->FindClass("the/package/MainActivity");
    // Get the method that you want to call
    jmethodID messageMe = env->GetMethodID(clazz, "messageMe", "(Ljava/lang/String;)V");
    // Call the method on the object
    jobject result = env->CallObjectMethod(jstr, messageMe);
    // Get a C-style string
    const char* str = env->GetStringUTFChars((jstring) result, NULL);
    printf("%s\n", str);
        // Clean up
    env->ReleaseStringUTFChars(jstr, str);

//    // Shutdown the VM.
//    vm->DestroyJavaVM();

    return env->NewStringUTF("Hello from JNI!");
}

Dopo che l'app di compilazione pulita si interrompe con il messaggio successivo:

ERROR/AndroidRuntime(742): FATAL EXCEPTION: main
        java.lang.NoSuchMethodError: messageMe
        at *.android.t3d.MainActivity.getJniString(Native Method)
        at *.android.t3d.MainActivity.onCreate(MainActivity.java:22)

Apparentemente significa che il nome del metodo è sbagliato, ma a me sembra OK.


21
Pubblica la tua soluzione come una normale risposta per rendere sia la tua domanda che la soluzione più facili da leggere e quindi più utili per la comunità. Puoi anche collaborare con altre persone che hanno già risposto per completare le loro risposte.
misiu_mp

@ Denys: ho seguito la tua codifica, ma ottengo questo errore: java.lang.UnsatisfiedLinkError: getJniString. Puoi aiutarmi a correggere questo errore?
Torre Huy

@AlexTran, è stato molto tempo fa ma a giudicare dall'errore probabilmente hai scritto male o non hai collegato il getJniStringmetodo né in java né in c. Assicurati di collegare correttamente il codice c a java probabilmente tramite l'importazione di sistema (srsly non ricordo tutte queste cose ora: P)
Denys S.

1
Come si chiama un metodo java da c? È palesemente il onCreatemetodo di Java che chiama il tuo C. nativo
John

Sto ottenendo l' operando di base di '->' ha un tipo non puntatore 'JNIEnv quando viene eseguito con la variabile di ambiente (env). E se volessi fare a meno della variabile env *, come il callback da JNI al livello Java! Qualche suggerimento!
CoDe

Risposte:


45

Se è un metodo oggetto, devi passare l'oggetto a CallObjectMethod:

jobject result = env->CallObjectMethod(obj, messageMe, jstr);

Quello che stavi facendo era l'equivalente di jstr.messageMe().

Poiché il tuo è un metodo void, dovresti chiamare:

env->CallVoidMethod(obj, messageMe, jstr);

Se si desidera restituire un risultato, è necessario modificare la propria firma JNI (che ()Vindica un metodo di voidtipo restituito) e anche il tipo restituito nel codice Java.


Per favore, guidami su come farlo, grazie al mio PS :)
Denys S.

Ottengo lo stesso risultato con quello che suggerisci.
Denys S.

1
esiste effettivamente un CallVoidMethod, CallObjectMethod, ecc. ognuno con un diverso tipo di ritorno. Poiché il tuo metodo messageMe è (Ljava / lang / String;) V, devi usare CallVoidMethod.
Matthew Willis

2
nota che l'errore che stai ricevendo probabilmente indica che il tuo metodo nativo Java (nel tuo codice Java) probabilmente non è di tipo restituito void e quindi non viene trovato da GetMethodID
Matthew Willis

10

Soluzione pubblicata da Denys S. nel post di domanda:

Ho un po 'incasinato con la conversione da c a c ++ (sostanzialmente envcose variabili), ma ho funzionato con il seguente codice per C ++:

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

jstring Java_the_package_MainActivity_getJniString( JNIEnv* env, jobject obj){

    jstring jstr = (*env)->NewStringUTF(env, "This comes from jni.");
    jclass clazz = (*env)->FindClass(env, "com/inceptix/android/t3d/MainActivity");
    jmethodID messageMe = (*env)->GetMethodID(env, clazz, "messageMe", "(Ljava/lang/String;)Ljava/lang/String;");
    jobject result = (*env)->CallObjectMethod(env, obj, messageMe, jstr);

    const char* str = (*env)->GetStringUTFChars(env,(jstring) result, NULL); // should be released but what a heck, it's a tutorial :)
    printf("%s\n", str);

    return (*env)->NewStringUTF(env, str);
}

E il prossimo codice per i metodi java:

    public class MainActivity extends Activity {
    private static String LIB_NAME = "thelib";

    static {
        System.loadLibrary(LIB_NAME);
    }

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        TextView tv = (TextView) findViewById(R.id.textview);
        tv.setText(this.getJniString());
    }

    // please, let me live even though I used this dark programming technique
    public String messageMe(String text) {
        System.out.println(text);
        return text;
    }

    public native String getJniString();
}

I nativemetodi devono essere statici?
IgorGanapolsky
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.