簡體   English   中英

使用Qt / C ++通過JNI調用Java代碼。 FindClass找不到類

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

我是JNI的新手,這是我的第一個嘗試從C ++調用Java代碼的程序。 我正在使用Qt 5.2,正在編寫一個Android應用程序。

我找不到我的java類並將其加載到C ++程序中。 我在這里已經閱讀了很多有關堆棧溢出和其他地方的文章,這似乎是一個常見的問題,但是我還無法解決我的問題。

我也不確定Java VM是否正確設置,因為QAndroidJniEnvironment上的Qt文檔很少。

我正在尋找有關如何能夠找到我的java類的解決方案。 我也很欣賞關於代碼其他部分的一般反饋(我認為可能會有更多錯誤)。

錯誤消息:

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類:

package org.app.test;
public class JniMath {

    public JniMath()
    {

    }

    public int eleven()
    {
        return 11;
    }
}

.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:

#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:

#ifndef JNIMATHCPPWRAPPER_H
#define JNIMATHCPPWRAPPER_H

#include <QtAndroidExtras>

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

private:
    jobject jniMathObject;
};

#endif // JNIMATHCPPWRAPPER_H

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;
}

項目結構:

在此處輸入圖片說明

編輯:

我還嘗試了導致相同錯誤的其他方法:

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

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

當嘗試加載java / lang / String時,上述兩種方法都可以找到該類。

編輯:

錯誤日志:

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

評論:為什么這個問題不是重復的(作者Alex Cohn)

, but the question asked here is a very different question, IMO. 毫無疑問,這里的根本問題與相同,但是這里提出的問題是一個非常不同的問題IMO。 作者並不是在尋找一種從本機線程訪問ClassLoader的通用方法。 他(或她)正在尋找一種簡單有效的方法來從基於Qt的本機代碼訪問Java回調。 因此,所有關於類加載器如何在Android中工作以及如何對其進行修補的討論都與他無關。 如果作者有其他意見,我將很樂意同意以重復形式結束此問題

更新:這個問題甚至與JNI線程無關

請認為先前的評論無效。 這個問題與多線程無關。 所有有關如何設置Android Qt應用程序,使其可以使用自定義Java類的功能,類似於sample

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

這就是我做的。 在我的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();
    }
}

然后在我的頭文件中添加以下內容:

 class FacebookAndroid : public QObject {
    Q_OBJECT

    public:
        FacebookAndroid(QObject *parent = 0);

    public slots:
        void startAndroidFacebook();
    };

在我的cpp文件中,我像這樣調用了我的java方法:

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

您的Java源目錄是否已復制到android-build目錄中? 您的源文件夾中的android文件夾需要在qmake變量ANDROID_PACKAGE_SOURCE_DIR中列出,請參見: http : //qt-project.org/doc/qt-5/deployment-android.html#qmake-variables

使FindClass工作最簡單的方法是在JNI_OnLoad函數中調用它。 JNI將在加載時在正確的線程中自動調用此函數。 提交#6500083之前,notificationclient示例的舊版本使用此方法。 這是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;
}

這不是5.2示例代碼中的內容,因為從C ++代碼調用Java不再需要此代碼,但我不知道顯示從Java調用C的QT5.2示例。

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

嘗試給軟件包名稱:“ 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);
}

像這樣

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM