简体   繁体   English

使用Qt / C ++通过JNI调用Java代码。 FindClass找不到类

[英]Using Qt/C++ to call Java code through JNI. FindClass does not find class

I am new to JNI and this is my first program trying to call Java code from C++. 我是JNI的新手,这是我的第一个尝试从C ++调用Java代码的程序。 I am using Qt 5.2 and I am writing an Android application. 我正在使用Qt 5.2,正在编写一个Android应用程序。

I am not able to find my java class and load it into my C++ program. 我找不到我的java类并将其加载到C ++程序中。 I have read a lot of posts here on stack overflow and other places and it seems to be a common problem, but I have not been able to solve mine yet.. 我在这里已经阅读了很多有关堆栈溢出和其他地方的文章,这似乎是一个常见的问题,但是我还无法解决我的问题。

I am also not sure if the Java VM is properly set up as the Qt documentation on the QAndroidJniEnvironment is minimal. 我也不确定Java VM是否正确设置,因为QAndroidJniEnvironment上的Qt文档很少。

I am looking for a solution on how to be able to find my java class. 我正在寻找有关如何能够找到我的java类的解决方案。 I am also appreciating general feedback on other sections of the code (I assume there might be more errors). 我也很欣赏关于代码其他部分的一般反馈(我认为可能会有更多错误)。

Error msg: 错误消息:

Starting remote process.D/dalvikvm(24911): GC_CONCURRENT freed 384K, 5% free 9180K/9596K, paused 1ms+2ms, total 15ms
D/dalvikvm(24911): Trying to load lib /data/data/org.qtproject.example.AndroidTest/lib/libgnustl_shared.so 0x428b2360
D/dalvikvm(24911): Added shared lib /data/data/org.qtproject.example.AndroidTest/lib/libgnustl_shared.so 0x428b2360
D/dalvikvm(24911): No JNI_OnLoad found in /data/data/org.qtproject.example.AndroidTest/lib/libgnustl_shared.so 0x428b2360, skipping init
D/dalvikvm(24911): Trying to load lib /data/data/org.qtproject.example.AndroidTest/lib/libQt5Core.so 0x428b2360
D/dalvikvm(24911): Added shared lib /data/data/org.qtproject.example.AndroidTest/lib/libQt5Core.so 0x428b2360
D/dalvikvm(24911): Trying to load lib /data/data/org.qtproject.example.AndroidTest/lib/libQt5Network.so 0x428b2360
D/dalvikvm(24911): Added shared lib /data/data/org.qtproject.example.AndroidTest/lib/libQt5Network.so 0x428b2360
I/Qt      (24911): Network start
D/dalvikvm(24911): Trying to load lib /data/data/org.qtproject.example.AndroidTest/lib/libQt5Qml.so 0x428b2360
D/dalvikvm(24911): Added shared lib /data/data/org.qtproject.example.AndroidTest/lib/libQt5Qml.so 0x428b2360
D/dalvikvm(24911): No JNI_OnLoad found in /data/data/org.qtproject.example.AndroidTest/lib/libQt5Qml.so 0x428b2360, skipping init
D/dalvikvm(24911): Trying to load lib /data/data/org.qtproject.example.AndroidTest/lib/libQt5Gui.so 0x428b2360
D/dalvikvm(24911): Added shared lib /data/data/org.qtproject.example.AndroidTest/lib/libQt5Gui.so 0x428b2360
D/dalvikvm(24911): No JNI_OnLoad found in /data/data/org.qtproject.example.AndroidTest/lib/libQt5Gui.so 0x428b2360, skipping init
D/dalvikvm(24911): Trying to load lib /data/data/org.qtproject.example.AndroidTest/lib/libQt5Quick.so 0x428b2360
D/dalvikvm(24911): Added shared lib /data/data/org.qtproject.example.AndroidTest/lib/libQt5Quick.so 0x428b2360
D/dalvikvm(24911): No JNI_OnLoad found in /data/data/org.qtproject.example.AndroidTest/lib/libQt5Quick.so 0x428b2360, skipping init
D/dalvikvm(24911): Trying to load lib /data/data/org.qtproject.example.AndroidTest/lib/libQt5QuickParticles.so 0x428b2360
D/dalvikvm(24911): Added shared lib /data/data/org.qtproject.example.AndroidTest/lib/libQt5QuickParticles.so 0x428b2360
D/dalvikvm(24911): No JNI_OnLoad found in /data/data/org.qtproject.example.AndroidTest/lib/libQt5QuickParticles.so 0x428b2360, skipping init
D/dalvikvm(24911): Trying to load lib /data/data/org.qtproject.example.AndroidTest/lib/libQt5AndroidExtras.so 0x428b2360
D/dalvikvm(24911): Added shared lib /data/data/org.qtproject.example.AndroidTest/lib/libQt5AndroidExtras.so 0x428b2360
D/dalvikvm(24911): No JNI_OnLoad found in /data/data/org.qtproject.example.AndroidTest/lib/libQt5AndroidExtras.so 0x428b2360, skipping init
D/dalvikvm(24911): Trying to load lib /data/data/org.qtproject.example.AndroidTest/plugins/platforms/android/libqtforandroidGL.so 0x428b2360
D/dalvikvm(24911): Added shared lib /data/data/org.qtproject.example.AndroidTest/plugins/platforms/android/libqtforandroidGL.so 0x428b2360
I/Qt      (24911): qt start
W/dalvikvm(24911): dvmFindClassByName rejecting 'org/qtproject/qt5/android/QtMessageDialogHelper'
D/dalvikvm(24911): Trying to load lib /data/data/org.qtproject.example.AndroidTest/lib/libQt5QuickParticles.so 0x428b2360
D/dalvikvm(24911): Shared lib '/data/data/org.qtproject.example.AndroidTest/lib/libQt5QuickParticles.so' already loaded in same CL 0x428b2360
D/dalvikvm(24911): Trying to load lib /data/app-lib/org.qtproject.example.AndroidTest-1/libAndroidTest.so 0x428b2360
D/Qt      (24911): qml\qqmlengine.cpp:1451 (QQmlDebuggingEnabler::QQmlDebuggingEnabler(bool)): QML debugging is enabled. Only use this in a safe environment.
D/dalvikvm(24911): Added shared lib /data/app-lib/org.qtproject.example.AndroidTest-1/libAndroidTest.so 0x428b2360
D/dalvikvm(24911): No JNI_OnLoad found in /data/app-lib/org.qtproject.example.AndroidTest-1/libAndroidTest.so 0x428b2360, skipping init
W/Qt      (24911): kernel\qcoreapplication.cpp:416 (QCoreApplicationPrivate::QCoreApplicationPrivate(int&, char**, uint)): WARNING: QApplication was not created in the main() thread.
W/dalvikvm(24911): dvmFindClassByName rejecting 'org/qtproject/qt5/android/QtNativeInputConnection'
W/dalvikvm(24911): dvmFindClassByName rejecting 'org/qtproject/qt5/android/QtExtractedText'
I/Adreno-EGL(24911): <qeglDrvAPI_eglInitialize:320>: EGL 1.4 QUALCOMM Build: I0404c4692afb8623f95c43aeb6d5e13ed4b30ddbDate: 11/06/13
D/Qt      (24911): fontdatabases\basic\qbasicfontdatabase.cpp:246 (static QStringList QBasicFontDatabase::addTTFile(const QByteArray&, const QByteArray&)): FT_New_Face failed with index 0 : 90 
D/Qt      (24911): ..\AndroidTest\jnimathcppwrapper.cpp:18 (jniMathCppWrapper::jniMathCppWrapper()): JniMath class not found 
D/Qt      (24911): ..\AndroidTest\jnimathcppwrapper.cpp:43 (int jniMathCppWrapper::eleven()): Enter eleven 
F/libc    (24911): Fatal signal 11 (SIGSEGV) at 0x0000002c (code=1), thread 24933 (ple.AndroidTest)

Java Class: Java类:

package org.app.test;
public class JniMath {

    public JniMath()
    {

    }

    public int eleven()
    {
        return 11;
    }
}

.pro file: .pro文件:

# Add more folders to ship with the application, here
folder_01.source = qml/AndroidTest
folder_01.target = qml
DEPLOYMENTFOLDERS = folder_01

# Additional import path used to resolve QML modules in Creator's code model
QML_IMPORT_PATH =

# The .cpp file which was generated for your project. Feel free to hack it.
SOURCES += main.cpp #\
#    jnimathcppwrapper.cpp

# Installation path
# target.path =

# Please do not modify the following two lines. Required for deployment.
include(qtquick2applicationviewer/qtquick2applicationviewer.pri)
qtcAddDeployment()

RESOURCES += \
    resources.qrc


QT += androidextras

OTHER_FILES += \
    android/src/org/app/test/JniMath.java

HEADERS += #\
#    jnimathcppwrapper.h

android {
    SOURCES += jnimathcppwrapper.cpp
    HEADERS += jnimathcppwrapper.h
}

main.cpp: main.cpp:

#include <QtGui/QGuiApplication>
#include "qtquick2applicationviewer.h"
#include "jnimathcppwrapper.h"
#include <QDebug>
#include <QString>

int main(int argc, char *argv[])
{
    QGuiApplication app(argc, argv);

    QtQuick2ApplicationViewer viewer;
    viewer.setMainQmlFile(QStringLiteral("qml/AndroidTest/main.qml"));
    viewer.showExpanded();

    jniMathCppWrapper *test = new jniMathCppWrapper();

    qDebug() << QString::number(test->eleven());

    return app.exec();
}

jnimathcppwrapper.h: jnimathcppwrapper.h:

#ifndef JNIMATHCPPWRAPPER_H
#define JNIMATHCPPWRAPPER_H

#include <QtAndroidExtras>

class jniMathCppWrapper
{
public:
    jniMathCppWrapper();
    int eleven();

private:
    jobject jniMathObject;
};

#endif // JNIMATHCPPWRAPPER_H

jnimathcppwrapper.cpp: jnimathcppwrapper.cpp:

#include "jnimathcppwrapper.h"
#include <QtAndroidExtras>
#include <QDebug>
#include <jni.h>

static jclass jniMathClassID = 0;
static jmethodID jniMathConstructorMethodID = 0;
static jmethodID jniMathElevenMethodID = 0;

jniMathCppWrapper::jniMathCppWrapper()
{
    QAndroidJniEnvironment qjniEnv;

    //Get JniMath class ID.
    jniMathClassID = qjniEnv->FindClass("android/src/org/app/test/JniMath");
    if(jniMathClassID == NULL)
    {
        qDebug() << "JniMath class not found";
        return;
    }

    //Get constructor method ID
    jniMathConstructorMethodID = qjniEnv->GetMethodID(jniMathClassID, "<init>", "void(V)");
    if(jniMathConstructorMethodID == NULL)
    {
        qDebug() << "JniMath constructor not found";
        return;
    }

    //Create new Java object and calling the selected constructor.
    jniMathObject = qjniEnv->NewObject(jniMathClassID, jniMathConstructorMethodID);
    if(jniMathObject == NULL)
    {
        qDebug() << "JniMath Java object could not be constructed";
        return;
    }
}

int jniMathCppWrapper::eleven()
{
    QAndroidJniEnvironment qjniEnv;

    qDebug() << "Enter eleven";

    //Get eleven method ID
    jniMathElevenMethodID = qjniEnv->GetMethodID(jniMathClassID, "eleven", "void(V)");
    if(jniMathElevenMethodID == NULL)
    {
        qDebug() << "JniMath class, eleven method not found";
        return 9;
    }

    jint res = qjniEnv->CallIntMethod(jniMathObject, jniMathElevenMethodID);

    return (int) res;
}

Project structure: 项目结构:

在此处输入图片说明

EDIT: 编辑:

I also tried a different approach leading to the same error: 我还尝试了导致相同错误的其他方法:

QAndroidJniObject *myJavaClass = new QAndroidJniObject("android/src/org/app/test/JniMath");

if(myJavaClass->isValid())
{
    qDebug() << "Class found!";
}
else
{
    qDebug() << "Class NOT found!";
}

When trying to load java/lang/String instead, both methods above find the class. 当尝试加载java / lang / String时,上述两种方法都可以找到该类。

EDIT: 编辑:

Error log: 错误日志:

D/Qt      ( 3385): qml\qqmlengine.cpp:1451 (QQmlDebuggingEnabler::QQmlDebuggingEnabler(bool)): QML debugging is enabled. Only use this in a safe environment.
D/dalvikvm( 3385): Added shared lib /data/app-lib/org.qtproject.example.AndroidTest-1/libAndroidTest.so 0x428b67f8
D/Qt      ( 3385): ..\AndroidTest\jnimathcppwrapper.cpp:68 (jint JNI_OnLoad(JavaVM*, void*)): Class NOT found 
D/AndroidRuntime( 3385): Shutting down VM
W/dalvikvm( 3385): threadid=1: thread exiting with uncaught exception (group=0x41fecba8)
E/AndroidRuntime( 3385): FATAL EXCEPTION: main
E/AndroidRuntime( 3385): Process: org.qtproject.example.AndroidTest, PID: 3385
E/AndroidRuntime( 3385): java.lang.NoClassDefFoundError: org/app/test/JniMath
E/AndroidRuntime( 3385):    at java.lang.Runtime.nativeLoad(Native Method)
E/AndroidRuntime( 3385):    at java.lang.Runtime.doLoad(Runtime.java:421)
E/AndroidRuntime( 3385):    at java.lang.Runtime.loadLibrary(Runtime.java:362)
E/AndroidRuntime( 3385):    at java.lang.System.loadLibrary(System.java:526)
E/AndroidRuntime( 3385):    at org.qtproject.qt5.android.bindings.QtActivity.loadApplication(QtActivity.java:235)
E/AndroidRuntime( 3385):    at org.qtproject.qt5.android.bindings.QtActivity.startApp(QtActivity.java:522)
E/AndroidRuntime( 3385):    at org.qtproject.qt5.android.bindings.QtActivity.onCreate(QtActivity.java:744)
E/AndroidRuntime( 3385):    at android.app.Activity.performCreate(Activity.java:5231)
W/dalvikvm( 3385): threadid=1: thread exiting with uncaught exception (group=0x41fecba8)
E/AndroidRuntime( 3385): FATAL EXCEPTION: main
E/AndroidRuntime( 3385): Process: org.qtproject.example.AndroidTest, PID: 3385
E/AndroidRuntime( 3385): java.lang.NoClassDefFoundError: org/app/test/JniMath
E/AndroidRuntime( 3385):    at java.lang.Runtime.nativeLoad(Native Method)
E/AndroidRuntime( 3385):    at java.lang.Runtime.doLoad(Runtime.java:421)
E/AndroidRuntime( 3385):    at java.lang.Runtime.loadLibrary(Runtime.java:362)
E/AndroidRuntime( 3385):    at java.lang.System.loadLibrary(System.java:526)
E/AndroidRuntime( 3385):    at org.qtproject.qt5.android.bindings.QtActivity.loadApplication(QtActivity.java:235)
E/AndroidRuntime( 3385):    at org.qtproject.qt5.android.bindings.QtActivity.startApp(QtActivity.java:522)
E/AndroidRuntime( 3385):    at org.qtproject.qt5.android.bindings.QtActivity.onCreate(QtActivity.java:744)
E/AndroidRuntime( 3385):    at android.app.Activity.performCreate(Activity.java:5231)
E/AndroidRuntime( 3385):    at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1087)
E/AndroidRuntime( 3385):    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2159)
E/AndroidRuntime( 3385):    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2245)
E/AndroidRuntime( 3385):    at android.app.ActivityThread.access$800(ActivityThread.java:135)
E/AndroidRuntime( 3385):    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1196)
E/AndroidRuntime( 3385):    at android.os.Handler.dispatchMessage(Handler.java:102)
E/AndroidRuntime( 3385):    at android.os.Looper.loop(Looper.java:136)
E/AndroidRuntime( 3385):    at android.app.ActivityThread.main(ActivityThread.java:5017)
E/AndroidRuntime( 3385):    at java.lang.reflect.Method.invokeNative(Native Method)
E/AndroidRuntime( 3385):    at java.lang.reflect.Method.invoke(Method.java:515)
E/AndroidRuntime( 3385):    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:779)
E/AndroidRuntime( 3385):    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:595)
E/AndroidRuntime( 3385):    at dalvik.system.NativeStart.main(Native Method)
E/AndroidRuntime( 3385): Caused by: java.lang.ClassNotFoundException: Didn't find class "org.app.test.JniMath" on path: DexPathList[[zip file "/data/app/org.qtproject.example.AndroidTest-1.apk"],nativeLibraryDirectories=[/data/app-lib/org.qtproject.example.AndroidTest-1, /vendor/lib, /system/lib]]
E/AndroidRuntime( 3385):    at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:56)
E/AndroidRuntime( 3385):    at java.lang.ClassLoader.loadClass(ClassLoader.java:497)
E/AndroidRuntime( 3385):    at java.lang.ClassLoader.loadClass(ClassLoader.java:457)
E/AndroidRuntime( 3385):    ... 21 more

Comment: why this question is not a duplicate (by Alex Cohn) 评论:为什么这个问题不是重复的(作者Alex Cohn)

There is no doubt that the root problem here is the same as in FindClass from any thread in Android JNI , but the question asked here is a very different question, IMO. 毫无疑问,这里的根本问题与Android JNI中的任何线程的FindClass相同,但是这里提出的问题是一个非常不同的问题IMO。 The author was not looking for a generic way to access the ClassLoader from native threads. 作者并不是在寻找一种从本机线程访问ClassLoader的通用方法。 He (or she) was looking for an easy and efficient way to access a Java callback from Qt-based native code. 他(或她)正在寻找一种简单有效的方法来从基于Qt的本机代码访问Java回调。 Therefore all discussion of how class loader works in Android and how this can be patched is irrelevant for him. 因此,所有关于类加载器如何在Android中工作以及如何对其进行修补的讨论都与他无关。 If the author thinks otherwise, I will gladly agree to close this question as duplicate 如果作者有其他意见,我将很乐意同意以重复形式结束此问题

Update: this question is not even related to JNI threads 更新:这个问题甚至与JNI线程无关

Please consider the previous comment void. 请认为先前的评论无效。 This question has nothing to do with multithreading. 这个问题与多线程无关。 It's all about how to set up an Android Qt application such that it could use custom Java classes, similar to the sample . 所有有关如何设置Android Qt应用程序,使其可以使用自定义Java类的功能,类似于sample

I used this example http://www.gnuton.org/blog/2014/01/invoking-qtc-code-from-the-java-side-of-qt-for-android-application/ 我使用了以下示例http://www.gnuton.org/blog/2014/01/invoking-qtc-code-from-the-java-side-of-qt-for-android-application/

This is how I did it. 这就是我做的。 In my java main class I added a static method to call the same activity (because it has to be static): 在我的Java主类中,我添加了一个静态方法来调用同一活动(因为它必须是静态的):

static public void startFacebookActivity() {
    String msgTag = "FACEBOOK_APP";
    try {
        Log.v(msgTag, "starting activity");
        Activity mother = QtNative.activity();
        Log.v(msgTag, mother.toString());
        Log.v(msgTag, MainActivity.class.getName());
        Intent intent = new Intent(mother, MainActivity.class);
        mother.startActivity(intent);
    } catch (Exception e) {
        Log.e(msgTag, e.toString());
        e.printStackTrace();
    }
}

Then in my header file I added this: 然后在我的头文件中添加以下内容:

 class FacebookAndroid : public QObject {
    Q_OBJECT

    public:
        FacebookAndroid(QObject *parent = 0);

    public slots:
        void startAndroidFacebook();
    };

and In my cpp file I just called my java method like this: 在我的cpp文件中,我像这样调用了我的java方法:

void FacebookAndroid::startAndroidFacebook() {
QAndroidJniObject::callStaticMethod<void>("org.qtproject.example.MainActivity",
                                          "startFacebookActivity",
                                          "()V");

Is your java source directory copied into the android-build directory? 您的Java源目录是否已复制到android-build目录中? The android folder in your source folder needs to be listed in the qmake variable ANDROID_PACKAGE_SOURCE_DIR see: http://qt-project.org/doc/qt-5/deployment-android.html#qmake-variables 您的源文件夹中的android文件夹需要在qmake变量ANDROID_PACKAGE_SOURCE_DIR中列出,请参见: http : //qt-project.org/doc/qt-5/deployment-android.html#qmake-variables

The easiest way to get FindClass to work will be to call it from within the JNI_OnLoad function. 使FindClass工作最简单的方法是在JNI_OnLoad函数中调用它。 This function will automatically be called by JNI at load time in the correct thread. JNI将在加载时在正确的线程中自动调用此函数。 The old version of the notificationclient example used this method prior to commit #6500083. 提交#6500083之前,notificationclient示例的旧版本使用此方法。 This is a summary of the relevant portion of the androidjnibindings.cpp file: 这是androidjnibindings.cpp文件相关部分的摘要:

#include <QtAndroidExtras/QJNIObject>

jint JNICALL JNI_OnLoad(JavaVM *vm, void *)
{
    JNIEnv *env;
    if (vm->GetEnv(reinterpret_cast<void **>(&env), JNI_VERSION_1_4) != JNI_OK) {
        qFatal("Couldn't initialize environment!");
        return -1;
    }

    jclass clazz = env->FindClass("org/qtproject/example/notification/NotificationClient");
    if (clazz == 0) {
        //
    }    
    return JNI_VERSION_1_4;
}

This isn't in the 5.2 example code as this is no longer needed in order to call Java from the C++ code, but I'm not aware of a QT5.2 example showing calling C from Java. 这不是5.2示例代码中的内容,因为从C ++代码调用Java不再需要此代码,但我不知道显示从Java调用C的QT5.2示例。

jniMathClassID = qjniEnv->FindClass("android/src/org/app/test/JniMath"); jniMathClassID = qjniEnv-> FindClass(“ android / src / org / app / test / JniMath”);

Instead of "android/src/org/app/test/JniMath" try to give the packagename: "org/app/test/JniMath" and put it in 尝试给软件包名称:“ org / app / test / JniMath”,而不是“ android / src / org / app / test / JniMath”,并将其放入

jint JNI_OnLoad(JavaVM *vm, void *reserved)
{
    JNIEnv* env;
    if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
        qCritical()<<"Can't get the enviroument";
        return -1;
    }
    s_javaVM = vm;  // cache the JavaVM pointer
    jclass clazz= env->FindClass("org/app/test/JniMath");
    jniMathClassID = (jclass)env->NewGlobalRef(tmp);
}

Something like this... 像这样

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM