Qtで作ったPC向けアプリケーションをAndroidで動かす話

# はじめに
Qt Advent Calendarの席が空いていると聞いたので寄稿させていただきました。
Qtには個人開発で非常にお世話になっているので、その魅力が少しでも伝われば幸いです。

# 開発環境
* Qt6.6.2
* Visual Studio 2019
* Android SDK 33
* Android NDK 26.1.10909125

# 動機
私は現在、Qt&C++を用いてPC向けのペイントソフトを開発してます。
このアプリはまだ開発中なのですが、将来的に何処かで展示するとなったときに、「ノートPCで展示するよりも、タブレット端末で展示したほうがかっこいいよね！」と思いAndroid対応をすることにしたのが事の始まりです。

もともとQtがAndroidやiOSに対応していることは知っていたのですが、どうもQMLの印象が強かったため、本当に同じコードでビルドができるのかは半信半疑でした。
結果としては想像よりも簡単にAndroid対応ができてしまったので、小ネタ程度の内容をまとめます。

# 作ったもの
Windows版の画面とAndroid版の画面が以下になります。

| Windows | Android |
|:-:|:-:|
| ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/588350/676ba1ce-f998-a3cb-43ed-62b05bc6fca3.png) | ![Screenshot_20241203-201928.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/588350/46a48ca7-abd3-b282-1806-a9c6f3e7ee59.png) |

ドックウィジェット周りは変える必要があったのですが、それ以外はほとんど変わりなく移植できています。
ちなみに、ビルドするところまでの過程については記事にまとめるのがしんどいので省略させていただきます。（そこを期待した方がいたらごめんなさい）
Qtのバージョンごとに利用可能なAndroid SDKの最大バージョンも異なるので、公式の記事などを参考にしながら進めるのが良いと思います。

https://doc.qt.io/qt-6/android-getting-started.html

# Android対応で修正した箇所
Androidに移植するにあたって修正が必要だったところを書いておきます。

## プラットフォーム依存のライブラリを削除する
C++自体はプラットフォームに依存しないため、ライブラリもそういった物が多いのですが、3DだとかGUIとかのライブラリになると、どうしてもプラットフォームに依存した実装が出てきます。

私の場合、[Qt-Advanced-Docking-System](https://github.com/githubuser0xFFFF/Qt-Advanced-Docking-System)（以下Qt-ADS）というライブラリが該当しており、Androidでのビルドが通りませんでした。
このライブラリを使うと[QDockWidget](https://doc.qt.io/qt-6/qdockwidget.html)をVisual Studioみたいな高性能なものに置き換えることができます。
非常に良いライブラリなので余裕があったらこちらもアドカレで記事にしたいですね。

話を戻します。このビルドが通らない問題を解決するため、Winでは`QDockWidget`、AndroidではQt-ADSのドックウィジェットを使うように実装を切り替える必要があります。
この切り替えは[Q_OS_ANDROID](https://doc.qt.io/qt-6/qtsystemdetection.html#Q_OS_ANDROID)を使ったマクロを使ったり、CMakeなどのプロジェクトレベルでソースコードを切り替えることで実現しました。（個人的には後者がおすすめ）

あとBoostをAndroid向けにビルドするのがしんどかったので、Boostの利用もやめました。

## UIの設定変更
上記の画面ですが、PCの画面に寄せるためいくつかの設定を変更してます。

### `QMenuBar`の`nativeMenuBar`を`false`にする
| `isNativeMenuBar() == false` | `isNativeMenuBar() == true` |
|:-:|:-:|
| ![Screenshot_20241203-213047.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/588350/90236022-b60c-9184-415f-bcd7f53f9b32.png) | ![Screenshot_20241203-212703.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/588350/01e589b7-f62c-b3b4-60a4-a8e3a4adfe53.png) |

この設定はメニューバーを環境依存のものにするかどうかを表すフラグで、デフォルト値はおそらく`true`になってます。
`true`にすると右図のようにAndroidのサンプルアプリでよく見るメニューバーになります。
で、Androidネイティブのメニューバーなんですが、本来あるはずの縦三点のボタンがありません。
これは調べたところ不具合のようで、環境によってはAndroidManifest.xmlの設定を弄らないと正しく表示されないらしいです。（えぇ...）
まぁ、Androidネイティブのメニューバーは項目が多いと使いづらいので、この設定は`false`にしておきましょう。

### `QStatusBar`の`sizeGripEnabled`を`false`にする
ステータスバーの左下にあるグリップを有効化するフラグで、デフォルト値は`true`です。
この設定が有効になっていると画面のリサイズができてしまうので、`false`にしましょう。
（有効化しようとしたけど表示されなかったので画像は省略します）

### `QMainWindow`の表示を`showFullScreen()`で行う
| showFullScreen() | show() |
|:-:|:-:|
| ![Screenshot (2024_12_04 23_53_22).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/588350/d536a2bb-dbae-e55d-794a-a86b69396ca2.png) | ![Screenshot_20241203-213047.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/588350/e714c425-d313-09cc-9af5-e5b60f3ce6e3.png) |

`QMainWindow::showFullScreen()`はその名の通り、ウィンドウを全画面で表示するための関数です。
Android環境だと上下のバーが非表示になって画面を広く使うことができます。
ここは好みの問題ではありますが、PC向けのアプリケーションは情報量が多いので`showFullScreen()`を使ったほうが良さそうです。

# まとめ
PCで動かすことしか考えてなかったプログラムが本当にAndroidでも動くのか怖かったのですが、ビルドを通すまでなら休日一日くらいでできたので想像以上に低コストで対応できました。
PCで動いていたネイティブアプリがモバイル環境でも動くというのは、実際に目にするとかなり感動するものですね。
ちなみにQtはiOSにも対応しているのですが、プラットフォームとライセンスの都合上、商用ライセンスを購入しないとGPLが適応されるとかなんとか。

Qtでデスクトップ向けのアプリを作っている方、試しにモバイルへの移植にチャレンジしてはいかがでしょうか。