はじめに
QtのAndroidに対する対応状況について、自分の所感をざっと書いてみました。突っ込んだ話はないですが、これからQtでAndroidアプリを作ってみたいという方の参考になればと思います。
公式のサンプルコードが充実してきた
拙著「QtでAndroidアプリを作ろう」を執筆した2019年8月頃は、QtのAndroidサンプル(正確にはAndroid Extrasを使用したサンプル)は、Qt Notifierしかなくて、しかもそのサンプルが微妙(※)という状況でした。KDAB社のサイトにスニペットがいくつかあるものの、そのまま動くサンプルがなかった為、自力で実装するのは難易度が高いと感じました。そこでAndroidのサンプルを増やしたいという意図から自分でサンプルを作って本を書いたりしました。(本というよりサンプル集的な感じになっちゃってますが。。。)
現在はある程度公式サンプルが充実してきています。
※static変数使い過ぎ。現在のサンプルが多少改善されている(Contextをstaticで保存しなくなった)がまだstaticを使用しているのでまだ不満。。。
Androidの基本構成
公式サンプルの説明をしようと思うのですが、その前にAndroidの4大要素について触れておきます。
Android Developersサイトにあるように、4大要素は、
- Activity
- Service
- BroadcastReceiver
- Content Provider
です。この内、Android ExtrasがサポートしているのはActivityとServiceです。
ActivityやService内でQtの機能を使用したい場合はそれぞれ、
Android:org.qtproject.qt5.android.bindings.QtActivity
Service:org.qtproject.qt5.android.bindings.QtService
を継承したクラスを作成する必要があります。逆に言えば、Qtの機能を使用しないのであれば、素のActivityクラスやServiceクラスを継承しても動作します。Android Studioを作成したクラスを取り込んで動作することも可能です。
BroadcastReceiverやContent Providerについては、Java/Kotlin側で実装し、C++からJNI経由で呼び出す形になります。JNIについてもAndroid Extrasに便利クラスが用意されている為多少は書きやすいと思います(書くのがメンドクサイといえばメンドクサイ部分ですが)。BroadcastReceiverやContent Providerについては後述するようにサンプルがあります。これで一応4大要素が網羅ができたということですね。
Androidのサンプル紹介
Activityサンプル
Activityのサンプルはこれ1つです。C++から
QtAndroid::startActivity(const QAndroidJniObject &intent, int receiverRequestCode, std::function callbackFunc)
を使用してJava側の(Activityクラスを継承した)CustomActivityを呼び出し、処理結果をLamda形式で受け取ります。QtAndroid::startActivity()にはQAndroidActivityResultReceiverを使用するオーバーロードがありますがサンプルはない為、手前味噌ですが、自分が書いたサンプルを参考にしていただければと思います。
Serviceサンプル
- Native Android Service in Same Process
- Android Service with BroadcastReceiver
- Android Service with BroadcastReceiver - Same Lib File
- Android Service with QAndroidBinder
- Android Service with Qt Remote Objects
- Android Service with Qt Remote Objects - Same Lib File
いろいろServiceのサンプルが増えました。
Native Android Service in Same Process
は、org.qtproject.qt5.android.bindings.QtServiceではない、ただのServiceクラスを継承したServiceクラスがJava側に用意されていて、それをContext.startService()で開始しています。
Android Service with BroadcastReceiver
Android Service with BroadcastReceiver - Same Lib File
の2つがServiceとBroadcastReceiverのサンプルです。
「- Same Lib File」が付いているのと付いていないのが2つありますが、どちらもServiceをActivityのプロセスと異なるプロセスにした場合のサンプルです。Serviceを別Libraryに分離するかどうかで、main()関数をActivityがあるプロセスと共用するかしないかの違いがあります。Android/Java(or Kotlin)(言いずらいので以後Android Nativeと呼称する)の感覚ではServiceクラスを継承してAndroidManifest.xmlに記述するだけなので、Qt独自の知識と言えます。
Android Service with QAndroidBinder
Android Service with Qt Remote Objects
Android Service with Qt Remote Objects - Same Lib File
は、バインドに関するサンプルです。
Android Nativeでは
- AIDL
- Messenger
の2種類の方法で通信する方法があります。AIDLはスレッドセーフではない為、自分でスレッドセーフにする処理を入れなければなりませんが、Messengerは、すべてのリクエストを1つのスレッドにキューイングするため、サービスをスレッドセーフに設計する必要はない、という違いがあります。
これに対してQt/Androidでは、
- AIDL
- Qt Remote Object
の2種類の方法で通信できます。
Android Nativeと比べるとMessengerがない代わりにQt Remote Objectが使用できるので、Qt Remote Objectがスレッドセーフなのかなと思いましたが、公式ドキュメントにはQt Remote Objectがスレッドセーフかどうかの記述が見つけられませんでした。詳しい方がいらっしゃいましたら教えて頂けると助かります。
JNIサンプル
Qt JNI Messenger
Qt JNI Music List
Qt Notifier
C++からJNI経由でJavaのコードを呼び出すサンプルです。Qt JNI Music Listサンプルでは、Content Providerの機能であるContentResolverを使用しています。
Qt6について
つい先日Qt6がリリースされたばかりですが、Androidに関しては使い始めるには時期尚早かも、というのが現状の感触です。あくまで現時点(Qt6.0:2020/12/13)の話ですが、「Qt5.14で生まれ変わったQt/Androidのビルド環境」で説明したようなマルチABIによるビルドができなくなっていたり、Qt6.0用のサンプルコードが入っていなかったりで、まだQt6環境への対応が終わっていない印象です。おそらく日々よくなってくるとは思いますが、しばらくはQt5.15.2を使用した方がよさそうです。
あと、Qtのドキュメントを見て気づいたのですが、
「Qt for Android」のページが
Qt5がhttps://doc.qt.io/qt-5/android.html であるのに対し、Qt6はhttps://doc-snapshots.qt.io/qt6-dev/android.html
となっており、まだスナップショットという位置づけで、Qt6.2で対応予定のQt SerialPortなどの機能に関する記述は削除されていますので、注意が必要です。