Memanggil metode java dari c ++ di Android

91

Saya mencoba untuk mendapatkan panggilan metode Java sederhana dari C ++ sementara Java memanggil metode asli. Inilah kode 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();
}

Saya mencoba memanggil messageMemetode dari kode asli dalam proses getJniString*pemanggilan metode dari Java ke asli.

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

Setelah aplikasi kompilasi bersih berhenti dengan pesan berikutnya:

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)

Rupanya itu berarti nama metode itu salah, tetapi menurut saya tidak masalah.

Denys S.
sumber
21
Harap posting solusi Anda sebagai jawaban biasa agar pertanyaan dan solusi Anda lebih mudah dibaca dan lebih bermanfaat bagi komunitas. Anda juga dapat berkolaborasi dengan orang lain yang sudah menjawab untuk melengkapi jawaban mereka.
misiu_mp
@ Denys: Saya mengikuti pengkodean Anda, tetapi saya mendapatkan kesalahan ini: java.lang.UnsatisfiedLinkError: getJniString. Bisakah Anda membantu saya memperbaiki kesalahan ini?
Menara Huy
@AlexTran, sudah lama sekali tetapi dilihat dari kesalahannya Anda mungkin salah mengeja atau tidak menautkan getJniStringmetode ini baik di java atau di c. Pastikan untuk menghubungkan kode c dengan benar ke java mungkin dengan impor sistem (srsly tidak ingat semua hal ini sekarang: P)
Denys S.
1
Bagaimana ini memanggil metode java dari c? Ini adalah onCreatemetode Java yang secara terang-terangan memanggil C. native Anda
John
Saya mendapatkan operan dasar '->' memiliki tipe non-pointer 'JNIEnv saat dijalankan dengan variabel lingkungan (env). Juga bagaimana jika ingin dilakukan tanpa variabel env *, seperti callback dari JNI ke layer Java! Ada saran!
CoDe

Jawaban:

45

Jika ini adalah metode objek, Anda harus meneruskan objek tersebut ke CallObjectMethod:

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

Apa yang Anda lakukan sama dengan jstr.messageMe().

Karena Anda adalah metode kosong, Anda harus memanggil:

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

Jika Anda ingin mengembalikan hasil, Anda perlu mengubah tanda tangan JNI Anda ( ()Vsarana metode voidtipe pengembalian) dan juga tipe pengembalian dalam kode Java Anda.

Matthew Willis
sumber
Tolong, bimbing saya tentang bagaimana melakukan itu, karena PS saya :)
Denys S.
Saya mendapatkan hasil yang sama dengan apa yang Anda sarankan.
Denys S.
1
sebenarnya ada CallVoidMethod, CallObjectMethod, dll. masing-masing dengan tipe kembalian yang berbeda. Karena metode messageMe Anda adalah (Ljava / lang / String;) V, Anda perlu menggunakan CallVoidMethod.
Matthew Willis
2
perhatikan bahwa kesalahan yang Anda dapatkan mungkin menunjukkan bahwa metode asli Java Anda (dalam kode Java Anda) mungkin bukan tipe pengembalian void dan karenanya tidak ditemukan oleh GetMethodID
Matthew Willis
10

Solusi diposting oleh Denys S. di posting pertanyaan:

Saya cukup mengacaukannya dengan konversi c ke c ++ (pada dasarnya envvariabel), tetapi saya membuatnya berfungsi dengan kode berikut untuk 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);
}

Dan kode berikutnya untuk metode 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();
}
BartoszKP
sumber
Apakah nativemetode harus statis?
IgorGanapolsky