はじめに
Android Studioで作成したJavaクラスをJarファイル化し、JarファイルをQtプロジェクトに取り込んで、Qt/AndroidアプリからJarファイルのクラスを使用する方法を紹介します。
開発環境
- Android Studio:3.5.3
- Android端末:SO-02J(Android8.0.0)
- Qt Creator:4.13.3
- コンパイラ:Android Qt 5.15.2 Clang Multi-Abi
Android StudioでJarファイルを作成する
Android StudioにはJarファイル単体を作成するプロジェクトはない為、まず使い捨ての空プロジェクトを作成します。
File -> New -> New Moduleを選択します。
Java Libraryを選択してNextを押下します。
Library nameをmyLibraryに変更し、Finishを押下します。
すると、ツリーにmyLibraryが追加され、MyClass.javaが作成されます。
MyClassに次のようにgetWord()メソッドを追加します。
package com.argama147.mylibrary;
public class MyClass {
public String getWord() {
return "test";
}
}
View -> Tool Windows -> Gradleを選択します。
Gradleウィンドウで、myLibrary -> Tasks -> buildにあるjarをダブルクリックします。
するとプロジェクトディレクトリ/myLibrary/build/libs/にmyLibrary.jarが作成されます。
作成されたライブラリの中身を確認
Jarファイルはいくつかのコマンドを使用することで逆アセンブルできますが、http://java-decompiler.github.io/ のJD-GUIというツールを使用すれば簡単に中身を確認することができます。
Qt/Androidアプリ作成
Qt CreatorでQt Quickアプリを作成します。サンプルはGitHubに格納してあります。
プロジェクトテンプレートでQt Quickアプリを作成します。
Android用の設定
プロジェクトファイル
QT += quick androidextras
プロジェクトファイルにandroidextrasを追加します。
Android固有ファイルを追加
プロジェクト -> Build Android APK -> Application にあるCreate Templatesボタンを押下します。
すると、プロジェクトディレクトリ直下にandroidディレクトリが作成され、AndroidManifest.xml等のファイルが作成されます。
Jarファイルのコピー
Jarファイルは$ANDROID_PACKAGE_SOURCE_DIR/libs下に格納すると認識されます。先程のCreate Templatesの操作で、プロジェクトファイルに
ANDROID_PACKAGE_SOURCE_DIR = $$PWD/android
のように追加されていますので、プロジェクトディレクトリ/android/下にlibsディレクトリを作成し、Android Studioで作成したmyLibrary.jarをコピーします。
QMLコードを改造
Javaクラスで取得した文字列を画面に表示したい為、main.qmlを次のように改造します。
import QtQuick 2.15;
import QtQuick.Controls 2.15;
import QtQuick.Layouts 1.15;
ApplicationWindow {
id: window
visible: true
header: ToolBar {
RowLayout {
id: rowlayout
anchors.fill: parent
Label {
text: "JarSample"
font.pixelSize: 20
color: "white"
anchors.right: menu.right
anchors.left: parent.left
Layout.alignment: Qt.AlignTop | Qt.AlignBottom
horizontalAlignment: Qt.AlignHCenter
verticalAlignment: Qt.AlignVCenter
Layout.fillWidth: true
Layout.fillHeight: true
background: Rectangle {
gradient: Gradient {
orientation: Gradient.Horizontal
GradientStop { position: 0.0; color: "lightsteelblue" }
GradientStop { position: 1.0; color: "blue" }
}
}
}
}
}
StackView {
id: stackView
anchors.fill: parent
initialItem: Pane {
id: pane
RowLayout {
anchors.fill: parent
Label {
objectName: "resultText"
horizontalAlignment: Text.AlignLeft
verticalAlignment: Text.AlignTop
wrapMode: Label.Wrap
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
}
}
}
}
}
「anchors.fill: parent」の部分で、
のようにM16エラーが出ていますが、動作には問題ありません。MinGWやMSVCコンパイラではエラーが出ない為、Androidコンパイラ固有の問題のようです。
この問題についてはQTBUG-89519で扱っています(QTCREATORBUG-24232で報告したらQTBUG-89519のreopenの形になった)。
C++からJavaクラスを使用する
C++からJNI経由でJavaクラスを使用するコードを追加します。
// Create MyClass Class Instance
QAndroidJniObject *instance = new QAndroidJniObject("com/argama147/mylibrary/MyClass");
// Call Method
QAndroidJniObject ret = instance->callObjectMethod("getWord","()Ljava/lang/String;");
QString str = ret.toString();
qDebug() << "ret" << str;
delete instance;
// Update Property
QObject* root = engine.rootObjects().first();
QQuickItem *resultText = root->findChild<QQuickItem *>("resultText");
resultText->setProperty("text", str);
QAndroidJniObjectでJavaのcom.argama147.mylibrary.MyClassクラスを生成し、callObjectMethod()でgetWord()メソッドを呼び出しています。取得した文字列を「resultText」に渡しています。