You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Qt6 Android后台Service无法启动问题求助

Qt 6.2 Android后台Service无法启动排查

我使用Qt 6.2和Java开发移动应用,需要通过后台进程获取用户位置,但Android后台Service完全无法启动。怀疑问题出在Java代码或AndroidManifest文件中,而非Qt的C++代码。目前仅能打印日志“Android Service Start”,onStartCommand和onCreate方法均未被调用,main.cpp仅执行一次并打印“I am the application”,无服务进程日志输出。


相关文件内容

android/src/org/qtproject/QtAndroidService.java

package org.qtproject;

import android.content.Context;
import android.content.Intent;
import android.util.Log;
import org.qtproject.qt.android.bindings.QtService;

public class QtAndroidService extends QtService {

    @Override
    public void onCreate() {
        super.onCreate();
        Log.d("TEST", "I got created!!");
    }

    @Override
    public void onDestroy() {
        super.onDestroy();

    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.d("TEST", "I just got here");

        int ret = super.onStartCommand(intent, flags, startId);


        return ret;
    }

    public static void startQtAndroidService(Context context) {
        context.startService(new Intent(context, QtAndroidService.class));

        Log.d("TEST", "Android Service Start");
    }
}

android/AndroidManifest.xml

<?xml version="1.0"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="org.qtproject.test1"
    android:installLocation="auto"
    android:versionCode="1"
    android:versionName="1.0">
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.CAMERA" />
    <uses-permission android:name="android.permission.RECORD_AUDIO" />
    <uses-permission android:name="android.permission.BLUETOOTH" />
    <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />

    <supports-screens
        android:anyDensity="true"
        android:largeScreens="true"
        android:normalScreens="true"
        android:smallScreens="true" />
    <application
        android:name="org.qtproject.qt.android.bindings.QtApplication"
        android:extractNativeLibs="true"
        android:hardwareAccelerated="true"
        android:label="test1"
        android:requestLegacyExternalStorage="true"
        android:allowNativeHeapPointerTagging="false">
        <activity
            android:name="org.qtproject.qt.android.bindings.QtActivity"
            android:configChanges="orientation|uiMode|screenLayout|screenSize|smallestScreenSize|layoutDirection|locale|fontScale|keyboard|keyboardHidden|navigation|mcc|mnc|density"
            android:label="test1"
            android:launchMode="singleTop"
            android:screenOrientation="unspecified">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>

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

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

            <meta-data
                android:name="android.app.extract_android_style"
                android:value="minimal" />

        </activity>
        <service android:name=".QtAndroidService" android:enabled="true">
            <meta-data android:name="android.app.lib_name" android:value="service" />
            <meta-data android:name="android.app.background_running" android:value="true" />
        </service>
    </application>
</manifest>

main.cpp

#include <QApplication>
#include <QtCore/QJniObject>

int main(int argc, char *argv[])
{

    QCoreApplication app(argc, argv);

    if (QCoreApplication::arguments().count() > 1)
    {
        qDebug() << "I am the service";
    }
    else
    {
        qDebug() << "I am the application";
    }

    QJniObject::callStaticMethod<void>(
        "org/qtproject/QtAndroidService",
        "startQtAndroidService",
        "(Landroid/content/Context;)V",
        QNativeInterface::QAndroidApplication::context());

    return app.exec();
}

CMakeLists.txt

cmake_minimum_required(VERSION 3.16)
project(test1 LANGUAGES CXX)

set(CMAKE_INCLUDE_CURRENT_DIR ON)

set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)
set(CMAKE_AUTOUIC ON)

find_package(Qt6 COMPONENTS Widgets Core REQUIRED)
set(PROJECT_SOURCES
        main.cpp
)

if(ANDROID)
set(ANDROID_TARGET_SDK_VERSION 30)
    qt_add_executable(test1
        MANUAL_FINALIZATION
        ${PROJECT_SOURCES}
        )

    target_link_libraries(test1 PRIVATE Qt6::Widgets Qt6::Core Qt6::CorePrivate)

    set_property(TARGET test1 APPEND PROPERTY QT_ANDROID_PACKAGE_SOURCE_DIR
                 ${CMAKE_CURRENT_SOURCE_DIR}/android)

    qt_finalize_executable(test1)


endif()

问题排查与修复方案

1. Service包名匹配错误

QtAndroidService.java的包名是org.qtproject,但AndroidManifest.xml根包名是org.qtproject.test1,Service标签中.QtAndroidService会被解析为org.qtproject.test1.QtAndroidService,与实际类路径不匹配,导致系统找不到Service类。

修复:修改Service标签的android:name为完整包名,同时将lib_name与主应用保持一致:

<service android:name="org.qtproject.QtAndroidService" android:enabled="true">
    <meta-data android:name="android.app.lib_name" android:value="test1" />
    <meta-data android:name="android.app.background_running" android:value="true" />
</service>

2. Android 8.0+后台启动限制

目标SDK为30,Android 8.0(API 26)及以上禁止后台直接启动Service,需改用startForegroundService,且Service必须在5秒内调用startForeground显示前台通知。

修复:修改Java中的启动方法,并添加前台通知逻辑:

// 导入必要类
import android.os.Build;
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.content.pm.PackageManager;
import androidx.core.app.NotificationCompat;

public static void startQtAndroidService(Context context) {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        context.startForegroundService(new Intent(context, QtAndroidService.class));
    } else {
        context.startService(new Intent(context, QtAndroidService.class));
    }
    Log.d("TEST", "Android Service Start");
}

@Override
public void onCreate() {
    super.onCreate();
    Log.d("TEST", "I got created!!");
    
    // 创建前台通知通道并启动前台服务
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        NotificationChannel channel = new NotificationChannel("location_service", "后台定位服务", NotificationManager.IMPORTANCE_LOW);
        NotificationManager manager = getSystemService(NotificationManager.class);
        manager.createNotificationChannel(channel);
        
        Notification notification = new NotificationCompat.Builder(this, "location_service")
                .setContentTitle("定位服务运行中")
                .setContentText("正在获取位置信息")
                .setSmallIcon(R.mipmap.ic_launcher) // 需确保该图标存在
                .build();
        
        startForeground(1, notification);
    }
}

3. Qt服务进程初始化逻辑

Qt的Service需要复用主应用的库,因此android.app.lib_name必须与主Activity的lib_name一致(即test1),否则服务进程无法加载Qt运行环境,导致main.cpp的服务分支逻辑无法执行。

4. 动态权限申请

Android 6.0+需要动态申请ACCESS_FINE_LOCATION权限,否则服务无法正常获取位置,甚至可能影响启动。可在主应用启动时添加权限申请:

// 在QtActivity或自定义Java类中添加
import android.Manifest;
import android.content.pm.PackageManager;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;

// 检查并申请权限
if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
    ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, 1001);
}

内容的提问来源于stack exchange,提问作者Ивелин Иванов

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.30 16:55:54