如何从使用 Qt(QJniEnvironment::RegisterNatives) 定义的本机 c++ 函数中获取 Java 的结果

How to get result in Java from native c++ Function defined with Qt(QJniEnvironment::RegisterNatives)

我正在使用 Qt6.2.4,并试图在 Java.

中从 C++ 获得答案
Logic:
C++ calls Java method, who calls C++ Method.
C++ Method (Hello from C++/Qt)
Java Method (Java:  + C++ Method)
and starter C++ Method set result on Button

My expectations:
"Java: Hello from C++/Qt",
But i see:
"Java: null"

My code:
https://github.com/dail45/JNItestw
(Sorry, i can't write code here. Editor raise warnings)

从控制台我知道: cppNativeFun 真的 运行 (我看到你好来自 Java 0) 我做错了什么?如何从 nativeFun (Java) 获取结果? 我需要做什么才能得到没有“null”的“Hello from C++/Qt”?

P.s。 对不起设计和代码,内置编辑器不断抱怨我错误地突出显示了代码。

UDP: ./JNItestw.pro QT += 核心图形用户界面

greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

CONFIG += c++17

# You can make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000    # disables all the APIs deprecated before Qt 6.0.0

SOURCES += \
    main.cpp \
    widget.cpp

HEADERS += \
    widget.h

FORMS += \
    widget.ui

# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target
ANDROID_PACKAGE_SOURCE_DIR = $$PWD/android
OTHER_FILES += \
    android/AndroidManifest.xml \
    android/src/org/example/JNItest/MyJNI.java

./main.cpp

#include "widget.h"

#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    Widget w;
    w.show();
    return a.exec();
}

./widget.cpp

#include "widget.h"
#include "ui_widget.h"

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    auto activity = QJniObject(QNativeInterface::QAndroidApplication::context());
    QJniObject MyJni = QJniObject("org/example/JNItest/MyJNI",
                                  "(Landroid/app/Activity;)V",
                                  activity.object<jobject>());
    QJniEnvironment env;
    jclass objectClass = env->GetObjectClass(MyJni.object<jobject>());
    JNINativeMethod methods[] = {{"nativeFun", "()Ljava/lang/String;", reinterpret_cast<void*>(cppNativeFunction)}};
    env->RegisterNatives(objectClass, methods, sizeof(methods) / sizeof(methods[0]));
    env->DeleteLocalRef(objectClass);
    layout->addWidget(btn);
    btn->setText("click me");
    btn->setStyleSheet("QPushButton {padding: 25px;}");
    QObject::connect(btn, &QPushButton::clicked, this, [this]() {
        auto activity = QJniObject(QNativeInterface::QAndroidApplication::context());
        QJniObject MyJni = QJniObject("org/example/JNItest/MyJNI",
                                      "(Landroid/app/Activity;)V",
                                      activity.object<jobject>());
        QJniObject res = MyJni.callObjectMethod("jniFun", "()Ljava/lang/String;").object<jobject>();
        this->btn->setText(res.toString());
    });
}

Widget::~Widget()
{
    delete ui;
}

int counter = 0;
jstring Widget::cppNativeFunction(JNIEnv *env, jobject obj) {
        qDebug() << "Hello from java!" << QString::number(counter++);
        return QJniObject::fromString("Hello from C++/Qt!").object<jstring>();
    }

./widget.h

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QJniObject>
#include <QJniEnvironment>
#include <jni.h>
#include <QPushButton>
#include <QDebug>
#include <QHBoxLayout>

QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE
class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = nullptr);
    ~Widget();
    QHBoxLayout *layout = new QHBoxLayout(this);
    QPushButton *btn = new QPushButton(this);
    static jstring cppNativeFunction(JNIEnv *env, jobject obj);

private:
    Ui::Widget *ui;
};
#endif // WIDGET_H

./android/src/org/example/JNItest/MyJNI.java

package org.example.JNItest;
import android.app.Activity;

public class MyJNI
{
    private final Activity m_MainActivity;
    public MyJNI(final Activity MainActivity) {
        m_MainActivity = MainActivity;
    }
    public native String nativeFun();
    public String jniFun() {
        String a = nativeFun();
        System.out.println(a);
        return "Java: " + a;
    }
}

./android/AndroidManifest.xml

<?xml version="1.0"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="org.example.JNItestw" android:installLocation="auto" android:versionCode="1" android:versionName="1.0">

    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>


    <supports-screens android:anyDensity="true" android:largeScreens="true" android:normalScreens="true" android:smallScreens="true"/>
    <application android:name="org.qtproject.qt.android.bindings.QtApplication" android:extractNativeLibs="true" android:hardwareAccelerated="true" android:label="JNItestw" android:requestLegacyExternalStorage="true" android:allowNativeHeapPointerTagging="false">
        <activity android:name="org.qtproject.qt.android.bindings.QtActivity" android:configChanges="orientation|uiMode|screenLayout|screenSize|smallestScreenSize|layoutDirection|locale|fontScale|keyboard|keyboardHidden|navigation|mcc|mnc|density" android:label="JNItestw" android:launchMode="singleTop" android:screenOrientation="unspecified">
            <intent-filter>
                <action android:name="android.intent.action.MAIN"/>
                <category android:name="android.intent.category.LAUNCHER"/>
            </intent-filter>
            <meta-data android:name="android.app.lib_name" android:value="JNItestw"/>
            <meta-data android:name="android.app.arguments" android:value=""/>
            <meta-data android:name="android.app.extract_android_style" android:value="minimal"/>
        </activity>
    </application>
<!-- %%INSERT_PERMISSIONS -->
    <!-- %%INSERT_FEATURES -->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
</manifest>

好的...我读了这本书的一部分:https://www.informit.com/store/java-native-interface-programmers-guide-and-specification-9780201325775 并获得了一些信息。

jstring Widget::cppNativeFunction(JNIEnv *env, jobject obj) {
        return (*env).NewStringUTF("Hello from C++/Qt!");
}
  • 这是真的。我终于在我的按钮上看到“Java:来自 C++/Qt 的你好!”