Gọi một phương thức java từ c ++ trong Android


91

Tôi đang cố gắng nhận một cuộc gọi phương thức Java đơn giản từ C ++ trong khi Java gọi phương thức gốc. Đây là mã 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();
}

Tôi đang cố gắng gọi messageMephương thức từ mã gốc trong quá trình getJniString*gọi phương thức từ Java sang bản địa.

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

Sau khi ứng dụng biên dịch sạch sẽ dừng với thông báo tiếp theo:

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)

Rõ ràng nó có nghĩa là tên phương thức đó bị sai, nhưng nó có vẻ ổn đối với tôi.


21
Vui lòng đăng giải pháp của bạn như một câu trả lời thông thường để làm cho cả câu hỏi của bạn và giải pháp dễ đọc hơn và do đó hữu ích hơn cho cộng đồng. Bạn cũng có thể cộng tác với những người khác đã trả lời để hoàn thành câu trả lời của họ.
misiu_mp

@Denys: Tôi đã làm theo mã của bạn, nhưng tôi gặp lỗi này: java.lang.UnsatisfiedLinkError: getJniString. Bạn có thể giúp tôi sửa lỗi này không?
Huy Tower

@AlexTran, cũng lâu rồi nhưng xét lại lỗi có lẽ bạn đã viết sai chính tả hoặc không liên kết getJniStringphương thức trong java hoặc trong c. Đảm bảo liên kết đúng mã c với java có thể bằng cách nhập hệ thống (srsly không nhớ tất cả những thứ này bây giờ: P)
Denys S.

1
Cách gọi phương thức java từ c? Đó là cách trắng trợn của Java onCreatephương pháp gọi C. mẹ đẻ của mình
John

Tôi đang nhận toán hạng cơ sở của '->' có kiểu không phải là con trỏ 'JNIEnv khi thực thi với biến môi trường (env). Ngoài ra, nếu bạn muốn làm gì mà không có biến env *, như callback từ JNI đến lớp Java! Bất kì lời đề nghị nào!
CoDe

Câu trả lời:


45

Nếu đó là một phương thức đối tượng, bạn cần phải chuyển đối tượng đến CallObjectMethod:

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

Những gì bạn đang làm tương đương với jstr.messageMe().

Vì của bạn là một phương thức void, bạn nên gọi:

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

Nếu bạn muốn trả về một kết quả, bạn cần thay đổi chữ ký JNI của mình ( ()Vnghĩa là một phương thức của voidkiểu trả về) và cả kiểu trả về trong mã Java của bạn.


Vui lòng hướng dẫn tôi cách làm điều đó, vì PS của tôi :)
Denys S.

Tôi nhận được kết quả tương tự với những gì bạn đang đề xuất.
Denys S.

1
thực sự có một CallVoidMethod, CallObjectMethod, v.v. mỗi cái có một kiểu trả về khác nhau. Vì phương thức messageMe của bạn là (Ljava / lang / String;) V, bạn cần sử dụng CallVoidMethod.
Matthew Willis

2
lưu ý rằng các lỗi mà bạn đang nhận được có thể chỉ ra rằng phương pháp có nguồn gốc Java của bạn (trong mã Java của bạn) có lẽ không phải của kiểu trả về void và như vậy là không được tìm thấy bởi GetMethodID
Matthew Willis

10

Giải pháp được đăng bởi Denys S. trong bài đăng câu hỏi:

Tôi khá rắc rối với việc chuyển đổi c sang c ++ (về cơ bản là những envthứ có thể biến đổi), nhưng tôi đã làm cho nó hoạt động với mã sau cho 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);
}

Và mã tiếp theo cho các phương thức 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();
}

Các nativephương thức có phải tĩnh không?
IgorGanapolsky
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.