Class 尝试在 QT 项目中调用 Java 代码时未发现异常

Class not found exception while trying to call Java code in a QT project

我正在尝试在 Android 应用程序的 QT Creator 项目中使用一些用 Java 编写的代码。我的最终目标是在此项目中使用通过 Android Studio 创建的 classes 和方法。

为了测试我是否理解 QT Java 包装器 class 我从 Android Studio 创建了一个 Java class:

文件>>新建模块>>Android库>>完成

在这个库中我创建了一个 class 如下:

package com.example.testclass;

public class MyJavaClass {
   public static int fibonacci (int n){
       if (n <2)
           return n;
       return fibonacci(n-1) + fibonacci(n-2);
   }
}

然后'Build>>Make module'

在我的 QT 项目 .pro 文件中,我添加了:QT += androidextras 并复制了 .aar 文件(也尝试解压缩和复制.jar 文件同样尝试将 ...\testclass\src\main 复制到 javalib\ 目录在我的项目文件中。 现在,在这一点上,我尝试了很多方法来使这个文件对我的项目可见。我通过添加编辑 .pro 文件:

OTHER_FILES += \
    javalib/java/com/example/testclass/MyJavaClass.java \
    javalib/AndroidManifest.xml

我试图通过 gradle 文件添加项目中已经存在的文件以及其他一些我不记得的东西。

但仍然遵循从 'MyJavaClass';

调用 'fibonacci' 方法的代码
void MainWindow::on_javaButton_clicked()
{
    int fibo = QAndroidJniObject::callStaticMethod<jint>("com/example/testclass/MyJavaClass", "fibonacci", "(I)I", 5);
    qDebug() << "JAVA OUTPUT: " << fibo << endl;
}

在 运行 时间抛出 class 未找到异常:

W System.err: java.lang.ClassNotFoundException: Didn't find class "com.example.testclass.MyJavaClass" on path: DexPathList[[],nativeLibraryDirectories=[/system/lib64, /system/vendor/lib64]]
W System.err:   at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:93)
W System.err:   at java.lang.ClassLoader.loadClass(ClassLoader.java:379)
W System.err:   at java.lang.ClassLoader.loadClass(ClassLoader.java:312)
W System.err:   at org.qtproject.qt5.android.QtNative.startQtApplication(Native Method)
W System.err:   at org.qtproject.qt5.android.QtNative.run(QtNative.java:390)
W System.err:   at org.qtproject.qt5.android.QtThread.run(QtThread.java:61)
W System.err:   at java.lang.Thread.run(Thread.java:764)
D libBlueToothTest.so: JAVA OUTPUT:  0

我尝试使用来自 QT 站点和其他来源的文档,例如 https://www.qtdeveloperdays.com/sites/default/files/BogdanVatra_Extending_Qt_Android_Apps_with_JNI.pdf

我是 QT 新手,Android 和 Java。 尽管有文档和示例,但我仍在努力解决这个问题,我将不胜感激。

我现在的 .pro 文件:

QT       += core gui bluetooth androidextras

greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

CONFIG += c++11

# The following define makes your compiler emit warnings if you use
# any Qt feature that has been marked deprecated (the exact warnings
# depend on your compiler). Please consult the documentation of the
# deprecated API in order to know how to port your code away from it.
DEFINES += QT_DEPRECATED_WARNINGS

# You can also make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
# You can also select to disable deprecated APIs only up to a certain version of Qt.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000    # disables all the APIs deprecated before Qt 6.0.0

SOURCES += \
    BlueTooth/BlueToothManager.cpp \
    BlueTooth/bluetoothclient.cpp \
    BlueTooth/bluetoothserver.cpp \
    main.cpp \
    mainwindow.cpp \

HEADERS += \
    BlueTooth/BlueToothManager.h \
    BlueTooth/bluetoothclient.h \
    BlueTooth/bluetoothserver.h \
    mainwindow.h \

FORMS += \
    mainwindow.ui

OTHER_FILES += \
    javalib/java/com/example/testclass/MyJavaClass.java \
    javalib/AndroidManifest.xml

# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target

DISTFILES += \
    android/AndroidManifest.xml \
    android/build.gradle \
    android/gradle/wrapper/gradle-wrapper.jar \
    android/gradle/wrapper/gradle-wrapper.properties \
    android/gradlew \
    android/gradlew.bat \
    android/res/values/libs.xml

contains(ANDROID_TARGET_ARCH,armeabi-v7a) {
    ANDROID_PACKAGE_SOURCE_DIR = \
        $$PWD/android
}

我的 gradle 文件截至目前:

buildscript {
    repositories {
        google()
        jcenter()
    }

    dependencies {
        classpath 'com.android.tools.build:gradle:3.2.0'
    }
}

repositories {
    google()
    jcenter()
}

apply plugin: 'com.android.application'

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar', '*.aar'])
}

android {
    /*******************************************************
     * The following variables:
     * - androidBuildToolsVersion,
     * - androidCompileSdkVersion
     * - qt5AndroidDir - holds the path to qt android files
     *                   needed to build any Qt application
     *                   on Android.
     *
     * are defined in gradle.properties file. This file is
     * updated by QtCreator and androiddeployqt tools.
     * Changing them manually might break the compilation!
     *******************************************************/

    compileSdkVersion androidCompileSdkVersion.toInteger()

    buildToolsVersion androidBuildToolsVersion

    sourceSets {
        main {
            manifest.srcFile 'AndroidManifest.xml'
            java.srcDirs = [qt5AndroidDir + '/src', 'src', 'java']
            aidl.srcDirs = [qt5AndroidDir + '/src', 'src', 'aidl']
            res.srcDirs = [qt5AndroidDir + '/res', 'res']
            resources.srcDirs = ['src']
            renderscript.srcDirs = ['src']
            assets.srcDirs = ['assets']
            jniLibs.srcDirs = ['libs']
       }
    }

    lintOptions {
        abortOnError false
    }
}

好的,我在这方面工作的时间太长了。经过大量的反复试验,我终于找到了解决这个问题的方法。 Java 的代码和 C++ 端都没有任何问题。问题出在 gradle 或 Android 清单文件中。

-我复制了 ...\AndroidStudioProjects\qtTest\testclass\src\main\java 文件(包含根据 Java 代码中的 'package' 关键字连接的文件夹以及 .java 源文件)到我的 Android 包目录,在我的例子中是 android\(见下一步)

-要从 QT 项目调用 Java 方法和 类,您需要将 android 包目录添加到 .pro 文件(我已经在底部有一个,它只是指向到我的项目目录中的 "android" 文件夹)。我不确切知道该文件一开始包含什么。我假设它是关于包装 C++ 代码来为 Android 构建程序。无论如何...

-下一步是为程序准备一个正确的模板。 项目>>构建步骤>>构建 Android APK>>创建模板 将您带到模板向导,其中已经有一个从 .pro 文件中获取的包源目录。我没有删除 "Copy the Gradle files to Android directory" 的勾号,但是我不知道它是否有任何不同。

-覆盖向导要求的所有内容。

在代码正常运行后,瞧瞧一个干净的构建!