Как да извикате java функция и да подадете аргументи от c++ с помощта на Android NDK

Опитвам се да извикам java функция от моя c++ код, но приложението продължава да се „срива“.

Първоначално стартирам C++ кода чрез JNI повикване, което работи без проблем. След това оставям функцията, която се нарича изпълнение на обратното извикване:

#include <jni.h>

extern "C"
JNIEXPORT jstring JNICALL
Java_net_example_folder_Service_startSomething(JNIEnv *env, jobject obj) {
    invoke_class(env);
    return env->NewStringUTF("The End.\n");    //works if I only use this line
}

Опитвате се да следвате http://www.inonit.com/cygwin/jni/invocationApi/c.html (и много други ръководства/съвети и т.н.), използвам това, за да извикам java функцията:

void invoke_class(JNIEnv* env) {
    jclass helloWorldClass;
    jmethodID mainMethod;

    helloWorldClass = env->FindClass("Java/net/example/folder/helloWorldClass");

    mainMethod = env->GetStaticMethodID(helloWorldClass, "helloWorld", "()V");

    env->CallStaticVoidMethod(helloWorldClass, mainMethod);
}

За да извикате java кода:

package net.example.folder;

import android.util.Log;

public class helloWorldClass {
    public static void helloWorld() {
        Log.e("helloWorldCLass", "Hello World!");
    }
}

C++ кодът се извиква от фонова услуга. Ето функцията на дейността, която я стартира:

public void startService() {
    Intent i = new Intent(this, Service.class);
    startService(i);
}

И това е част от услугата:

public class SimService extends IntentService {

    ...

    @Override
    protected void onHandleIntent(Intent intent) {
        System.loadLibrary("native-lib");
        startSomething();
    }
}

Всичко това работи, но когато сега променя функцията "invoke_class" на:

void invoke_class(JNIEnv* env) {
    jclass helloWorldClass;
    jmethodID mainMethod;

    helloWorldClass = env->FindClass("net/example/folder/helloWorldClass");

    mainMethod = env->GetStaticMethodID(helloWorldClass, "helloWorld", "([Ljava/lang/String;)V");

    env->CallStaticVoidMethod(helloWorldClass, mainMethod, env->NewStringUTF("some text"));
}

и разбира се частта на java към:

package net.example.folder;

import android.util.Log;

public class helloWorldClass {
    public static void helloWorld(String msg) {
        Log.e("helloWorldCLass", msg);
    }
}

С това ще получа споменатия по-рано срив.

Защо така? Как да предавам аргументи правилно?


person janonymous    schedule 31.03.2018    source източник
comment
[ се използва за представяне на масиви (сякаш ако имате String[] msg), премахнете го от вашия GetStaticMethodID метод.   -  person Dmitrii Z.    schedule 01.04.2018
comment
И разбира се добавете проверка за грешки за всички JNI повиквания. Не предполагайте само, че ще успеят.   -  person Michael    schedule 01.04.2018
comment
Благодаря, без [ работи. Грешка при проверка като if(mainMethod != 0) и изпълнение на кода само тогава? Това все още ще доведе до срив на приложението ми поради някаква JNI грешка   -  person janonymous    schedule 01.04.2018


Отговори (1)


Символът [ се използва за представяне на масиви (сякаш ако имате String[] msg), премахнете го от вашия метод GetStaticMethodID.

Можете да видите повече информация за JNI типове и данни Структури тук

Също така, както каза Майкъл - трябва да проверите за Java изключения във вашия собствен код, защото в противен случай приложението ви ще се срине. Можете да го направите с помощта на функции за изключения jni. Например:

jclass exClass = env->FindClass("some/random/class");
if (exClass == nullptr || env->ExceptionOccurred()) {
    env->ExceptionClear();
    // do smth in case of failure
}
person Dmitrii Z.    schedule 01.04.2018
comment
exClass ще има стойност NULL, ако класът/методът не съществува или не може да бъде намерен. Поне в моя случай. Така че if (exClass == NULL || ...) за мен. - person janonymous; 19.06.2018