Qt/Androidの対応状況

# はじめに
QtのAndroidに対する対応状況について、自分の所感をざっと書いてみました。突っ込んだ話はないですが、これからQtでAndroidアプリを作ってみたいという方の参考になればと思います。

# 公式のサンプルコードが充実してきた

拙著「[QtでAndroidアプリを作ろう](https://github.com/argama147/qt-android)」を執筆した2019年8月頃は、QtのAndroidサンプル（正確にはAndroid Extrasを使用したサンプル）は、[Qt Notifier](https://doc.qt.io/qt-5/qtandroidextras-notification-example.html)しかなくて、しかもそのサンプルが微妙（※）という状況でした。KDAB社のサイトにスニペットがいくつかあるものの、そのまま動くサンプルがなかった為、自力で実装するのは難易度が高いと感じました。そこでAndroidのサンプルを増やしたいという意図から自分でサンプルを作って本を書いたりしました。（本というよりサンプル集的な感じになっちゃってますが。。。）
現在はある程度公式サンプルが充実してきています。

※static変数使い過ぎ。現在のサンプルが多少改善されている（Contextをstaticで保存しなくなった）がまだstaticを使用しているのでまだ不満。。。

# Androidの基本構成
公式サンプルの説明をしようと思うのですが、その前にAndroidの４大要素について触れておきます。
[Android Developersサイト](https://developer.android.com/guide/components/fundamentals?hl=ja#Components)にあるように、４大要素は、

* 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については後述するようにサンプルがあります。これで一応４大要素が網羅ができたということですね。

# Androidのサンプル紹介

## Activityサンプル

[Android Custom Activity](https://doc.qt.io/qt-5/qtandroidextras-customactivity-example.html)
    
Activityのサンプルはこれ１つです。C++から
QtAndroid::startActivity(const QAndroidJniObject &intent, int receiverRequestCode, std::function<void (int, int, const QAndroidJniObject &)> callbackFunc)
を使用してJava側の（Activityクラスを継承した）CustomActivityを呼び出し、処理結果をLamda形式で受け取ります。QtAndroid::startActivity()にはQAndroidActivityResultReceiverを使用するオーバーロードがありますがサンプルはない為、手前味噌ですが、[自分が書いたサンプル](https://github.com/argama147/qt-android/tree/master/ch07/QtActivitySample)を参考にしていただければと思います。

## Serviceサンプル

* [Native Android Service in Same Process](https://doc.qt.io/qt-5/qtandroidextras-services-servicesameprocess-example.html)
* [Android Service with BroadcastReceiver](https://doc.qt.io/qt-5/qtandroidextras-services-servicebroadcast-example.html)
* [Android Service with BroadcastReceiver - Same Lib File](https://doc.qt.io/qt-5/qtandroidextras-services-servicebroadcastsamelib-example.html)
* [Android Service with QAndroidBinder](https://doc.qt.io/qt-5/qtandroidextras-services-servicebinder-example.html)
* [Android Service with Qt Remote Objects](https://doc.qt.io/qt-5/qtandroidextras-services-serviceremoteobjects-example.html)
* [Android Service with Qt Remote Objects - Same Lib File](https://doc.qt.io/qt-5/qtandroidextras-services-serviceremoteobjectssamelib-example.html)

いろいろServiceのサンプルが増えました。

[Native Android Service in Same Process](https://doc.qt.io/qt-5/qtandroidextras-services-servicesameprocess-example.html)
は、org.qtproject.qt5.android.bindings.QtServiceではない、ただのServiceクラスを継承したServiceクラスがJava側に用意されていて、それをContext.startService()で開始しています。

[Android Service with BroadcastReceiver](https://doc.qt.io/qt-5/qtandroidextras-services-servicebroadcast-example.html)
[Android Service with BroadcastReceiver - Same Lib File](https://doc.qt.io/qt-5/qtandroidextras-services-servicebroadcastsamelib-example.html)
の２つがServiceとBroadcastReceiverのサンプルです。
「- Same Lib File」が付いているのと付いていないのが２つありますが、どちらもServiceをActivityのプロセスと異なるプロセスにした場合のサンプルです。Serviceを別Libraryに分離するかどうかで、main()関数をActivityがあるプロセスと共用するかしないかの違いがあります。Android/Java(or Kotlin)（言いずらいので以後Android Nativeと呼称する）の感覚ではServiceクラスを継承してAndroidManifest.xmlに記述するだけなので、Qt独自の知識と言えます。

[Android Service with QAndroidBinder](https://doc.qt.io/qt-5/qtandroidextras-services-servicebinder-example.html)
[Android Service with Qt Remote Objects](https://doc.qt.io/qt-5/qtandroidextras-services-serviceremoteobjects-example.html)
[Android Service with Qt Remote Objects - Same Lib File](https://doc.qt.io/qt-5/qtandroidextras-services-serviceremoteobjectssamelib-example.html)
は、バインドに関するサンプルです。
Android Nativeでは

* AIDL
* Messenger

の２種類の方法で通信する方法があります。AIDLはスレッドセーフではない為、自分でスレッドセーフにする処理を入れなければなりませんが、Messengerは、すべてのリクエストを1つのスレッドにキューイングするため、サービスをスレッドセーフに設計する必要はない、という違いがあります。

これに対してQt/Androidでは、

* AIDL
* Qt Remote Object

の２種類の方法で通信できます。
Android Nativeと比べるとMessengerがない代わりにQt Remote Objectが使用できるので、Qt Remote Objectがスレッドセーフなのかなと思いましたが、公式ドキュメントにはQt Remote Objectがスレッドセーフかどうかの記述が見つけられませんでした。詳しい方がいらっしゃいましたら教えて頂けると助かります。

## JNIサンプル
[Qt JNI Messenger](https://doc.qt.io/qt-5/qtandroidextras-jnimessenger-example.html)
[Qt JNI Music List](https://doc.qt.io/qt-5/qtandroidextras-musiclist-example.html)
[Qt Notifier](https://doc.qt.io/qt-5/qtandroidextras-notification-example.html)

C++からJNI経由でJavaのコードを呼び出すサンプルです。Qt JNI Music Listサンプルでは、Content Providerの機能であるContentResolverを使用しています。

# Qt6について
つい先日[Qt6がリリースされた](https://qiita.com/argama147/items/656061d4f2d8bda07224)ばかりですが、Androidに関しては使い始めるには時期尚早かも、というのが現状の感触です。あくまで現時点（Qt6.0：2020/12/13）の話ですが、「[Qt5.14で生まれ変わったQt/Androidのビルド環境](https://qiita.com/argama147/items/278e420a5369dcb26353)」で説明したようなマルチ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などの機能に関する記述は削除されていますので、注意が必要です。