このページでは

Androidサービス

Qt を使用して Android サービスを作成できます。サービスはバックグラウンドで実行されるコンポーネントであるため、ユーザーインターフェースはありません。GPS の記録やソーシャルメディアの通知待ちなど、長時間の処理を実行するのに役立ちます。サービスは、それを起動したアプリケーションが終了しても実行され続けます。

サービスの構築

まず、『Extending Qt with Android Facilities』の手順に従って、Androidパッケージディレクトリを作成します。このディレクトリには、AndroidManifest.xml ファイルが含まれています。パッケージディレクトリ内にsrc ディレクトリを作成します。ここに、すべてのJavaパッケージとクラスが作成されます。

サービスクラスの作成

QtService とAndroid Serviceのどちらを使用するか決定する際には、Activityの場合と同様の判断基準が適用されます。Qtのネイティブコールやイベント処理など、Qtライブラリの読み込みを必要とする機能を使用する場合を除き、Service を拡張すれば問題なく動作するはずです。

QtService または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 を使用しても、どちらの方法も利用可能です。

オンデマンドでのサービスの起動

サービスは以下の方法で起動できます:

  • C++から直接、QAndroidIntent およびQJniObject を使用し、サービスインテントを作成して、アプリのメインアクティビティのstartService()メソッドを呼び出す方法:
    // Outside of the function body
    Q_DECLARE_JNI_CLASS(Intent, "android/content/Intent")
    Q_DECLARE_JNI_CLASS(ComponentName, "android/content/ComponentName")
    Q_DECLARE_JNI_CLASS(QtAndroidService, "org/qtproject/example/qtandroidservice/QtAndroidService")
    
    // Inside function body
    using namespace QtJniTypes;
    using namespace QNativeInterface;
    
    auto *androidApp = qGuiApp->nativeInterface<QAndroidApplication>();
    Q_ASSERT(androidApp);
    Context context = androidApp->context();
    
    QJniEnvironment env;
    auto serviceClass = env.findClass(Traits<QtAndroidService>::className());
    Intent serviceIntent(context, serviceClass);
    context.callMethod<ComponentName>("startService", serviceIntent);
  • Java メソッドを呼び出してサービスを起動します。最も簡単な方法は、サービスクラスに静的メソッドを作成することです:
    public static void startQtAndroidService(Context context) {
            context.startService(new Intent(context, QtAndroidService.class));
    }

    その後、以下のJNI呼び出しを使用してC++からそれを呼び出すことができます:

    using namespace QtJniTypes;
    using namespace QNativeInterface;
    // ...
    auto *androidApp = qGuiApp->nativeInterface<QAndroidApplication>();
    Q_ASSERT(androidApp);
    Context context = androidApp->context();
    QtAndroidService::callStaticMethod<void>("startQtAndroidService", context);

起動時にサービスを起動する

起動時にサービスを実行するには、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 15.0 では、BOOT_COMPLETED を受信した後のフォアグラウンドサービスの起動にいくつかの制限が導入されました。詳細については、「BOOT_COMPLETED に関する制限」を参照してください。
  • Android 8.0では、バックグラウンドサービスの実行に関していくつかの制限が導入されました。そのため、通常のService クラスを使用しても正常に動作しない可能性があります。詳細については、「フォアグラウンドサービスまたはJobIntentServiceのいずれかを使用することに関するAndroidの推奨事項」を参照してください。

AndroidManifest.xml でのサービスの管理

Android アプリでサービスを使用するには、AndroidManifest.xml ファイルにサービスを宣言する必要があります。まず、サービスセクションを追加することから始めましょう。

  • Service を拡張する際は、通常の Android サービスと同様にサービスセクションを宣言します。<application> セクション内に、以下のコードを追加してください:
    <service android:name=".QtAndroidService" android:exported="true">
        <meta-data android:name="android.app.background_running" android:value="true"/>
    </service>

    こうすることで、サービスはQtActivity と同じプロセス内で起動し、JavaコードからネイティブC++呼び出しを使用できるようになります。別のプロセスで実行することも可能ですが、その場合はQtライブラリがそのプロセスには読み込まれていないため、通信のためのネイティブ呼び出しは一切使用できません。別のプロセスで実行するには、サービスタグに以下を追加してください:

    android:process=":qt_service"
  • QtService を拡張する場合、Qtに必要なすべてのライブラリを読み込むために、他の項目を宣言する必要があります。主に、QtActivity の「<activity> 」セクションにある項目と同じものです。以下を追加してください:
    <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 ライブラリファイルを使用する

メインアクティビティと同じ.so ライブラリファイルを使用する場合、サービスはメインアクティビティと区別するために追加の引数付きで同じエントリポイントを使用することになります。main() 関数内で、渡された引数に応じてアプリケーションの実行を処理できます。サービス本体に以下の引数宣言を追加してください:

<meta-data android:name="android.app.arguments" android:value="-service"/>

次に、サービスのandroid.app.lib_name がメインアクティビティと同じであることを確認し、以下を追加してください:

<meta-data android:name="android.app.lib_name" android:value="-- %%INSERT_APP_LIB_NAME%% --"/>

同じ.so ライブラリファイルを使用する場合、アプリケーションのmain() 関数は 2 回実行されます。1 回目はメインアクティビティの起動時、2 回目はサービスの起動時です。したがって、渡された引数に応じて各実行を適切に処理する必要があります。そのための方法の一つは以下の通りです:

if(argc<= 1) {
    // メインアクティビティの実行を処理するコード
}else if(argc> 1&&strcmp(argv[1], "-service")== 0) {
    qDebug() << "Service starting with from the same .so file";
    QAndroidService app(argc,argv);
    returnapp.exec();
}else{
    qWarning() << "Unrecognized command line argument";
   return-1;
}
別の .so ライブラリファイルを使用する

この場合、サービス用に別の実行ファイルを提供する「lib 」テンプレートを使用したサブプロジェクトが必要です。サンプルプロジェクトは以下の通りです:

  • CMakeでは:
    find_package(Qt6 REQUIRED COMPONENTS Core)
    
    qt_add_library(service SHARED
        servicemessenger.h
        service_main.cpp
    )
    
    target_link_libraries(service
        PRIVATE
            Qt::Core
            Qt::CorePrivate
    )
  • qmakeの場合:
    TEMPLATE = lib
    TARGET = service
    CONFIG += dll
    QT += core core-private
    
    SOURCES += \
        service_main.cpp
    
    HEADERS += servicemessenger.h

service_main.cpp では、次のように記述できます:

#include <QDebug>
#include <QAndroidService>
#include <QtCore/private/qandroidextras_p.h>

intmain(intargc, char *argv[])
{
    qWarning() << "Service starting from a separate .so file";
    QAndroidService app(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 サービスからのネイティブ C++ 呼び出し、または Android BroadcastReceiver のいずれかを使用できます。

Java サービスからのネイティブ C++ 呼び出し

これは、QtActivity と同じプロセスで実行されているサービスに対して機能し、Service が拡張されている場合でも動作します。

詳細については、「Qt for Android Notifier」のサンプルを参照してください。

Android BroadcastReceiver の使用

AndroidのBroadcastReceiverを使用すると、Androidシステム、アプリ、アクティビティ、およびサービス間でメッセージのやり取りが可能になります。他のAndroid機能と同様に、QtでもBroadcastReceiverを使用して、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() を呼び出すことで、"simple_string" というメッセージをQtに送信しています:

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(message);
                Log.i(TAG, "Service sent back message to C++: " + message);
            }
        }
    };
}

これらすべてを活用するには、「サービスの起動」の説明に従ってサービスを起動し、次にメソッド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アプリケーション側にそのレプリカを用意することです。これにより、シグナルとスロットを使用して、これら2つの部分が相互にデータをやり取りできるようになります。

レプリカの準備

.so という独立したライブラリファイルを持つサービスの例を考えてみましょう。通信クラスを定義する.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 ファイルをメインアプリケーションと、メインアプリケーション内のサービスの両方に追加します。

  • CMakeでは:
    find_package(Qt6 REQUIRED COMPONENTS RemoteObjects)
    
    qt_add_repc_replicas(service
        ../servicemessenger.rep
    )
    
    target_link_libraries(service PRIVATE Qt6::RemoteObjects)
  • qmakeでは:
    QT += remoteobjects
    REPC_REPLICA += servicemessenger.rep

また、serviceサブプロジェクトでは:

  • CMakeでは:
    find_package(Qt6 REQUIRED COMPONENTS RemoteObjects)
    
    qt_add_repc_sources(service
        ../servicemessenger.rep
    )
    target_link_libraries(service PRIVATE Qt6::RemoteObjects)
  • qmakeでは:
    QT += remoteobjects
    REPC_SOURCE += servicemessenger.rep

ソースとレプリカを接続する

serviceサブプロジェクトのmain() 関数内で、Qt Remote Objects ソースノードを定義します:

#include "servicemessenger.h"

#include <QDebug>
#include <QAndroidService>
#include <QtCore/private/qandroidextras_p.h>

intmain(intargc, char *argv[])
{
    qWarning() << "QtAndroidService starting from separate .so";
    QAndroidService app(argc,argv);

    QRemoteObjectHost srcNode(QUrl(QStringLiteral("local:replica")));
    ServiceMessenger serviceMessenger;
    srcNode.enableRemoting(&serviceMessenger);

    returnapp.exec();
}

次に、アプリケーションのmain() 関数内で、ソースノードに接続します:

QRemoteObjectNode repNode;
repNode.connectToNode(QUrl(QStringLiteral("local:replica")));
QSharedPointer<ServiceMessengerReplica>rep(repNode.acquire<ServiceMessengerReplica>());
boolres= rep->waitForSource();
Q_ASSERT(res);

QObject::connect(rep.data(), &ServiceMessengerReplica::pong, [](constQString&message){
    qDebug() << "Service sent: " << message;
});
rep->ping("QtとAndroidは仲良し!");

この例では、メインアプリケーションのプロセスからサービスへメッセージを送信します。サービスは同じメッセージで応答し、そのメッセージはデバッグ用logcatに出力されます。

注: 同じ.so ライブラリファイルを使用する場合も、この方法 を利用できます。詳細については、「同じ.soライブラリファイルの使用」を参照してください。

QAndroidBinderの使用

QAndroidBinder は、Binderの最も重要なメソッドを実装することで、プロセス間通信を可能にする利便性向上のためのクラスです。これにより、プロセス間でQByteArray またはQVariant オブジェクトを送信することができます。

注:Qt for Androidには、1つのプロセス内で複数のサービスを実行する場合、一度に1つのサービスのみを実行するように強制する制限があります。そのため、各サービスをそれぞれ独自のプロセスで実行することを推奨します。詳細については、QTBUG-78009を参照してください。

© 2026 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.