Androidサービス
Qt 5.7から、Qtを使ってAndroidサービスを作成できるようになりました。サービスはバックグラウンドで動作するコンポーネントで、ユーザーインターフェイスを持ちません。GPSのログを取ったり、ソーシャルメディアの通知を待ったりなど、長期的な処理を行うのに便利です。サービスは、それを起動したアプリケーションが終了しても実行され続けます。
サービスを組み立てる
始めるには、Qt Creator の指示に従ってAndroidパッケージ・ディレクトリを作成します:Androidデバイスにアプリケーションをデプロイする。このディレクトリには、AndroidManifest.xml
ファイルが含まれます。packageディレクトリの中に、src
ディレクトリを作成します。ここには、Javaパッケージとクラスがすべて作成されます。
サービス・クラスの作成
QtService
、またはAndroid.Serviceというクラスを拡張することで、サービスを作成できます:Serviceクラスを Java クラスに拡張することでサービスを作成できます。サービス内でQtの機能を使用するか、JavaからネイティブC++関数を呼び出すかによって、QtService
またはService
のどちらかを拡張する必要があります。簡単なサービスから始めましょう:
import android.content.Context; import android.content.Intent; import android.util.Log; import org.qtproject.qt.android.bindings.QtService; public class QtAndroidService extends QtService { private static final String TAG = "QtAndroidService"; @Override public void onCreate() { super.onCreate(); Log.i(TAG, "Creating Service"); } @Override public void onDestroy() { super.onDestroy(); Log.i(TAG, "Destroying Service"); } @Override public int onStartCommand(Intent intent, int flags, int startId) { int ret = super.onStartCommand(intent, flags, startId); // Do some work return ret; } }
サービスを開始する
Androidでは、オンデマンドまたは起動時にサービスを開始することができます。Qtを使ってもその両方が可能です。
オンデマンドでサービスを開始する
以下の方法でサービスを開始できます:
- QAndroidIntent 、QJniObject 、サービス・インテントを作成し、アプリのメイン・アクティビティ・メソッドstartService()を呼び出すことで、C++から直接サービスを開始できます:
auto activity = QJniObject(QNativeInterface::QAndroidApplication::context()); QAndroidIntent serviceIntent(activity.object(), "org/qtproject/example/qtandroidservice/QtAndroidService"); QJniObject result = activity.callObjectMethod( "startService", "(Landroid/content/Intent;)Landroid/content/ComponentName;", serviceIntent.handle().object());
- Javaメソッドを呼び出してサービスを開始します。最も簡単な方法は、サービス・クラスに静的メソッドを作成することです:
public static void startQtAndroidService(Context context) { context.startService(new Intent(context, QtAndroidService.class)); }
次のJNIコールを使用して、C++からこのメソッドを呼び出すことができます:
const QJniObject context(QNativeInterface::QAndroidApplication::context()); QJniObject::callStaticMethod<void>( "org/qtproject/example/qtandroidservice/QtAndroidService", "startQtAndroidService", "(Landroid/content/Context;)V", context.object());
ブート時にサービスを開始する
ブート時にサービスを実行するには、BroadcastReceiverが必要です。
カスタム Java クラスを作成します:
public class QtBootServiceBroadcastReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { Intent startServiceIntent = new Intent(context, QtAndroidService.class); context.startService(startServiceIntent); } }
AndroidManifest.xml
ファイルの<manifest>
セクションの本文に、以下のuses-permission
を追加します:
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
また、<application>
セクションの本文にreceiver
の定義を追加する:
<receiver android:name=".QtBootServiceBroadcastReceiver" android:exported="true"> <intent-filter> <action android:name="android.intent.action.BOOT_COMPLETED" /> </intent-filter> </receiver>
注: Android 8.0では、バックグラウンド・サービスの実行にいくつかの制限が導入されたため、通常のService
クラスを使用しても動作しない場合があります。詳細については、Androidが推奨するForegroundサービスまたはJobIntentServiceを参照してください。
AndroidManifest.xmlでサービスを管理する
サービスをAndroidアプリで使えるようにするには、AndroidManifest.xml
ファイルで宣言する必要があります。まずは、サービス・セクションを追加するところから始めましょう:
Service
を拡張する場合は、サービス・セクションを通常のAndroidサービスとして宣言するだけです。<application>
:<service android:name=".QtAndroidService" android:exported="true"> <!-- Background running --> <meta-data android:name="android.app.background_running" android:value="true"/> <!-- Background running --> </service>
こうすることで、サービスが
QtActivity
と同じプロセスで開始され、Java コードからネイティブ C++ 呼び出しを使用できるようになります。別のプロセスで実行することもできますが、その場合はQtライブラリーがロードされないため、通信にネイティブ・コールを使用できません。別プロセスで実行するには、serviceタグに次のように追加します:android:process=":qt_service"
QtService
を拡張する場合、Qt に必要なすべてのライブラリをロードするための他の項目を宣言する必要があります。主に、<activity>
のセクションと同じ項目をQtActivity
に宣言します。以下を追加してください:<service android:process=":qt_service" android:name=".QtAndroidService" android:exported="true"> <meta-data android:name="android.app.lib_name" android:value="service"/> <meta-data android:name="android.app.background_running" android:value="true"/> </service>
注意: サービスをバックグラウンドで実行するために、以下を必ず定義してください:
<meta-data android:name="android.app.background_running" android:value="true"/>
サービスを宣言する方法にはいくつかのバリエーションがあります。そのうちのいくつかは、前のマニフェストのスニペットですでに使用されています。使用するケースに応じて、サービスを QtActivity と同じプロセスで実行するか、別のプロセスで実行します。
QtActivity と同じプロセス内のサービス
QtActivity と同じプロセスでサービスを実行するには、以下のようにサービスヘッダを宣言します:
<service android:name=".QtAndroidService" android:exported="true">
別プロセスのサービス
サービスを専用プロセスで実行するには、サービスヘッダを次のように宣言します:
<service android:process=":qt_service" android:name=".QtAndroidService" android:exported="true">
Qt はandroid.app.lib_name
meta-data
で定義された.so
ファイルをロードし、android.app.arguments
meta-data
で設定されたすべての引数でmain()
関数を呼び出します。別のプロセスで実行する場合、メイン・アクティビティと同じlibファイルまたは別のlibファイルを使用してサービスを開始することができます。
同じ.so libファイルを使用する
メイン・アクティビティと同じ.so
libファイルを使用することは、サービスがメイン・アクティビティと区別するための余分な引数を持つ同じエントリ・ポイントを使用することを意味します。提供された引数に従って、main()
関数でアプリケーションの実行を処理できます。次の引数宣言をサービス本体に追加してください:
<!-- Application arguments --> <meta-data android:name="android.app.arguments" android:value="-service"/> <!-- Application arguments -->
次に、サービスandroid.app.lib_name
がメイン・アクティビティと同じであることを確認し、以下を追加します:
<meta-data android:name="android.app.lib_name" android:value="-- %%INSERT_APP_LIB_NAME%% --"/>
同じ.so
libファイルを使用する場合、アプリケーションのmain()
関数は2回実行されます。1回目はメイン・アクティビティを開始するため、2回目はサービスを開始するためです。したがって、提供された引数に従って、それぞれの実行を処理する必要があります。そのための1つの方法は以下の通りです:
if(argc<= 1) {// メイン・アクティビティの実行を処理するコード}else if(argc> 1 &&strcmp(argv[1], "-service")== 0) {if(argc> 1 &&strcmp(argv[1], "-service")== 0) qDebug() << "Service starting with from the same .so file"; QAndroidServiceapp(argc,argv);returnapp.exec(); }else{. qWarning() << "Unrecognized command line argument"; return -1; }
別の.so Libファイルを使う
この場合、サービスに別の実行ファイルを提供するlib
テンプレートを持つサブプロジェクトを用意する必要があります。サンプル・プロジェクト.pro
:
TEMPLATE = lib TARGET = service CONFIG += dll QT += core core-private SOURCES += \ service_main.cpp HEADERS += servicemessenger.h
service_main.cpp
:
#include <QDebug>#include <QAndroidService>intmain(intargc, char *argv[]){ qWarning() << "Service starting from a separate .so file"; QAndroidServiceapp(argc,argv);returnapp.exec(); }
AndroidManifest.xml
で、サービスのandroid.app.lib_name
を定義する:
<meta-data android:name="android.app.lib_name" android:value="service"/>
サービスとの通信
Qt for Androidは、Androidサービスと通信するための様々なプロセス間通信(IPC)メソッドを提供しています。プロジェクトの構造に応じて、Java ServiceまたはAndroid BroadcastReceiverからのネイティブC++コールを使用できます。
Java ServiceからのネイティブC++コール
これは、QtActivity
と同じプロセスで実行されているサービスや、Service
が拡張されている場合でも機能します。
詳細については、Qt Android Notifier Exampleを参照してください。
Android BroadcastReceiverの使用
Android BroadcastReceiverを使用すると、Androidシステム、アプリ、アクティビティ、サービス間でメッセージを交換できます。他の Android 機能と同様に、Qt でもブロードキャストレシーバーを使用して、QtActivity
とサービス間でメッセージを交換できます。まず、サービスからメッセージを送信するロジックから説明します。sendBroadcast()を呼び出すサービスの実装に以下を追加します:
@Override public int onStartCommand(Intent intent, int flags, int startId) { int ret = super.onStartCommand(intent, flags, startId); Intent sendToUiIntent = new Intent(); sendToUiIntent.setAction(ActivityUtils.BROADCAST_CUSTOM_ACTION); sendToUiIntent.putExtra("message", "simple_string"); Log.i(TAG, "Service sending broadcast"); sendBroadcast(sendToUiIntent); return ret; }
次に、Qtのメイン・アクティビティからブロードキャスト・レシーバーを作成し、登録する必要があります。最も簡単な方法は、メソッドを持つカスタムクラスを作成し、Javaですべてのロジックを実装することです。次の例では、ネイティブ・メソッドsendToQt()
を呼び出して、Qt にメッセージ"simple_string"
を送信しています:
public class ServiceBroadcastUtils { private static native void sendToQt(String message); private static final String TAG = "ActivityUtils"; public static final String BROADCAST_CUSTOM_ACTION = "org.qtproject.example.qtandroidservice.broadcast.custom"; public void registerServiceBroadcastReceiver(Context context) { IntentFilter intentFilter = new IntentFilter(); intentFilter.addAction(BROADCAST_CUSTOM_ACTION); context.registerReceiver(serviceMessageReceiver, intentFilter); Log.i(TAG, "Registered broadcast receiver"); } private BroadcastReceiver serviceMessageReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { Log.i(TAG, "In OnReceive()"); if (BROADCAST_CUSTOM_ACTION.equals(intent.getAction())) { String message = intent.getStringExtra("message"); sendToQt(data); Log.i(TAG, "Service sent back message to C++: " + message); } } }; }
これらすべてを利用するには、Start the Serviceで示したようにサービスを開始し、registerServiceBroadcastReceiver()
メソッドを呼び出してブロードキャスト・レシーバーを登録します:
QJniEnvironment env; jclass javaClass = env.findClass("org/qtproject/example/qtandroidservice/ActivityUtils"); QJniObject classObject(javaClass); const QJniObject context(QNativeInterface::QAndroidApplication::context()); classObject.callMethod<void>("registerServiceBroadcastReceiver", "(Landroid/content/Context;)V", context.object());
メソッドQt Remote Objects
Qt Remote ObjectsはQtプロセス間でAPIを共有する簡単な方法を提供します。主なコンセプトは、サービスプロセスにサーバーを置き、Qtアプリケーションにレプリカを置くことです。
レプリカの準備
個別の.so
libファイルを持つサービスの例を考えてみましょう。通信クラスを定義する.rep
:
class ServiceMessenger { SLOT(void ping(const QString &message)); SIGNAL(pong(const QString &message)); }
サービス・サブプロジェクトでは、このクラスをservicemessenger.h
として定義します:
#include "rep_servicemessenger_source.h" class ServiceMessenger : public ServiceMessengerSource { public slots: void ping(const QString &name) override { emit pong("Hello " + name); } };
次に、.rep
ファイルをメインアプリケーションの.pro
ファイルとサービスの ファイルの両方に追加します:
QT += remoteobjects REPC_REPLICA += servicemessenger.rep
そして、サービスサブプロジェクトに
QT += remoteobjects REPC_SOURCE += servicemessenger.rep
ソースとレプリカを接続する
サービス・サブプロジェクトのmain()
関数で、Qt Remote Objects ソース・ノードを定義する:
#include "servicemessenger.h"#include <QDebug>#include <QAndroidService>intmain(intargc, char *argv[]){ qWarning() << "QtAndroidService starting from separate .so"; QAndroidServiceapp(argc,argv); QRemoteObjectHostsrcNode(QUrl(QStringLiteral("local:replica")); ServiceMessenger serviceMessenger; srcNode.enableRemoting(&serviceMessenger);returnapp.exec(); }
次に、アプリケーションのmain()
関数で、ソース・ノードに接続します:
QRemoteObjectNoderepNode; repNode.connectToNode(QUrl(QStringLiteral("local:レプリカ"));QSharedPointer<ServiceMessengerReplica>rep(repNode.acquire<ServiceMessengerReplica>());boolres= rep->waitForSource(); Q_ASSERT(res);QObject::connect(rep.data(), &ServiceMessengerReplica::pong, [](constQStringメッセージ qDebug() << "Service sent: " << message; }); rep->ping("Qt と Android は友達です!");
この例では、メイン・アプリケーションのプロセスからサービスにメッセージを送信しています。サービスは同じメッセージを返信し、デバッグログに出力されます。
注: 同じ.so
libファイルを使用する場合、同じ方法が使用できます。詳細については、「同じ.so Libファイルを使用する」を参照してください。
QAndroidBinderを使う
QAndroidBinder は、Androidで最も重要なメソッドであるBinderを実装することで、プロセス間通信を可能にする便利なクラスです。プロセス間で または オブジェクトを送信できます。QByteArray QVariant
注意: Qt for Androidでは、1つのプロセスで複数のサービスを実行する場合、一度に1つのサービスしか実行できないという制限があります。そのため、各サービスは個別のプロセスで実行することをお勧めします。詳細はQTBUG-78009 を参照してください。
© 2025 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.