Qt on Android: How to create an Android service using Qt Full code samples for building with and communicating to QAndroidService background tasks
Starting with Qt 5.7, we added the ability to create Android services using Qt. In this article we’re going to see how to get started and also how to communicate between the two.
Before we get started I want to add a big bold WARNING about the performance! Because the services are run in the background for a very long time, make sure your service doesn’t drain the device battery!
Update for Qt 5.10+
Starting with Qt 5.10, you must use QAndroidService instead of QCoreApplication on the server side.
Getting started
Step I: Extend QtService
Every single Qt Android Service must have its own Service java class which extends QtService, so the first step is to create such a service:
// java file goes in android/src/com/kdab/training/MyService.java package com.kdab.training; import org.qtproject.qt5.android.bindings.QtService; public class MyService extends QtService { }
Step II: Add the service section(s) to your AndroidManifest.xml file
The next step is to add the service section(s) to your AndroidManifest.xml file. To do that you first need to copy & paste the template from https://wiki.qt.io/AndroidServices to your AndroidManifest.xml file, then set android:name attribute with your service class name, as shown in the following snippet:
<application ... > <!-- .... --> <service android:process=":qt" android:name=".MyService"> <!-- android:process=":qt" is needed to force the service to run on a separate process than the Activity --> <!-- .... --> <!-- Background running --> <meta-data android:name="android.app.background_running" android:value="true"/> <!-- Background running --> </service> <!-- .... --> </application>
BE AWARE: Every single Qt service/activity MUST run in it’s own process! Therefore for each service you must set a different android:process attribute value.
Step III: How to start the service ?
Now you need to decide how to start the service. There are two ways to do it:
- on demand
- at boot time
We’re going to check them both:
Start the service on demand
This is the most common way to start your service(s). To start the service you just need to call Context.startService(Intent intent) method. The easiest way is to add a static method to your MyService:
// java file goes in android/src/com/kdab/training/MyService.java package com.kdab.training; import android.content.Context; import android.content.Intent; import org.qtproject.qt5.android.bindings.QtService; public class MyService extends QtService { public static void startMyService(Context ctx) { ctx.startService(new Intent(ctx, MyService.class)); } }
Then simply call it from Qt to start it:
QAndroidJniObject::callStaticMethod<void>("com/kdab/training/MyService", "startMyService", "(Landroid/content/Context;)V", QtAndroid::androidActivity().object());
Start the service at boot time
This method is used quite seldom and is useful ONLY when you really need to run the service at boot time, otherwise I do recommend you to start it on demand.
First you need to add android.permission.RECEIVE_BOOT_COMPLETED permission to your AndroidManifest.xml file:
<application ... > <!-- .... --> <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" /> </application>
Then you need to add a receiver element to your AndroidManifest.xml file:
<application ... > <!-- .... --> <receiver android:name=".MyBroadcastReceiver"> <intent-filter> <action android:name="android.intent.action.BOOT_COMPLETED" /> </intent-filter> </receiver> <!-- .... --> </application>
And finally, you need to implement MyBroadcastReceiver class, as shown in the following snippet:
public class MyBroadcastReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { Intent startServiceIntent = new Intent(context, MyService.class); context.startService(startServiceIntent); } }
Step IV: Where to put your Qt Service code?
Next you need to decide where you’re going to put your service code. Qt (and qmake) has two options for you:
- in the same .so file with the application
- in a separate .so file
We’re going to check them both:
Same .so for app & service(s)
Because you’ll have one big .so file, you need a way to know when it will run as an activity or as a service. To do that you just need pass some arguments to your main function. AndroidManifest.xml allows you to easily do that:
<service ... > <!-- ... --> <!-- Application arguments --> <meta-data android:name="android.app.arguments" android:value="-service"/> <!-- Application arguments --> <!-- ... --> </service>
Then make sure you set the same android.app.lib_name metadata for both service(s) & activity elements:
<service ... > <!-- ... --> <meta-data android:name="android.app.lib_name" android:value="-- %%INSERT_APP_LIB_NAME%% --"/> <!-- ... --> </service>
I recommend you to use this method only if your activity and your service(s) share a large piece of code.
Separate .so files for app & service(s)
The second option is to create separate .so files for your app & service(s). First you need to create a separate server .pro file(s):
TEMPLATE = lib TARGET = server CONFIG += dll QT += core SOURCES += \ server.cpp
The server .so main entry is the main function:
#include <QDebug> int main(int argc, char *argv[]) { qDebug() << "Hello from service"; return 0 }
Last you need to load the server .so file:
<service ... > <!-- ... --> <meta-data android:name="android.app.lib_name" android:value="server"/> <!-- ... --> </service>
Use QtRemoteObject for communication
We’ve seen how to create and how to start a Qt on Android service, now let’s see how to do the communication between them. There are lots of solutions out there, but for any Qt project, I do recommend you use QtRemoteObject, because it will make your life so easy!
QtRemoteObjects is a playground Qt module led by Ford, for object remoting between processes/devices:
- exports QObjects remotely (properties, signals & slots)
- exports QAbstractItemModels remotely
- creates a replicant on the client side you can interface with
- repc generates source & replica (server & client) source files from .rep files
- .rep file is the QtRemoteObjects IDL (interface description language)
As you can see it’s very Qt specific! Let’s see how to add it to your projects and use it.
Get QtRemoteObjects
QtRemoteObjects project is located at http://code.qt.io/cgit/qt/qtremoteobjects.git/, to get it you need to run the following commands:
$ git clone git://code.qt.io/qt/qtremoteobjects.git $ cd qtremoteobjects $ ~/Qt/5.10.1/android_armv7/bin/qmake -r && make && make install
If needed, replace ~/Qt/5.10.1/android_armv7 with your Qt version and android ABI of choice.
Use QtRemoteObjects
Using QtRemoteObjects is pretty easy, you need to do a few easy steps:
– add QtRemoteObjects to your .pro files
# ... QT += androidextras QT += remoteobjects # ...
– create .rep file(s)
class PingPong { SLOT(void ping(const QString &msg)); SIGNAL(pong(const QString &msg)); }
– add .rep file(s) to the server .pro file
# ... REPC_SOURCE += pingpong.rep # ...
– add .rep file(s) to the client .pro file
# ... REPC_REPLICA += pingpong.rep # ...
– QtRemoteObjects source(server) side implementation
#include <QAndroidService> #include "rep_pingpong_source.h" class PingPong : public PingPongSource { public slots: // PingPongSource interface void ping(const QString &msg) override { emit pong(msg + " from server"); } }; int main(int argc, char *argv[]) { QAndroidService app(argc, argv); QRemoteObjectHost srcNode(QUrl(QStringLiteral("local:replica"))); PingPong pingPongServer; srcNode.enableRemoting(&pingPongServer); return app.exec(); }
Let’s check the code a little bit. First you need to implement all .rep interfaces (PingPongSource), then export PingPong object using enableRemoting.
– QtRemoteObjects replica(client) side implementation
#include "rep_pingpong_replica.h" // .... QRemoteObjectNode repNode; repNode.connectToNode(QUrl(QStringLiteral("local:replica"))); QSharedPointer<PingPongReplica> rep(repNode.acquire<PingPongReplica>()); bool res = rep->waitForSource(); Q_ASSERT(res); QObject::connect(rep.data(), &PingPongReplica::pong, [](const QString &msg){ qDebug() << msg; }); rep->ping("Hello"); // ....
Let’s check the code:
- use QRemoteObjectNode to connect to QRemoteObjectHost
- use QRemoteObjectNode:acquire to link the local object to the remote one
- use the acquired object as its local (call slots, connect to signals, etc.)
As you can see, using Qt + QtRemoteObject is (much?) easier and more straight forward than Android’s Java services + AIDL 😉
Limitations
- the activities & service(s) must run on a different process.
- it is not possible (yet) to use QtCreator to easily add a service section to your AndroidManifest.xml file check QTCREATORBUG-16884
- it is not possible (yet) to use QtCreator to easily generate a service subproject for us, check QTCREATORBUG-16885
- it is not possible (yet) to see the services logs in QtCreator. You’ll need to use
$ adb logcat
to see it, check QTCREATORBUG-16887
- it is not possible (yet (hopefully)) to debug the services in QtCreator. This feature will take some time to implement it, therefore I’ll not hold my breath for it, check QTCREATORBUG-16886
Please use the above bug report links to vote for your favorite tasks, the ones that have more votes (usually) are implemented first!
You can find the full source code of this article here: https://github.com/KDAB/android
Big Nice!
Impressive!! Thanks Bogdan
I didn’t know the QtRemoteObjects exitence, that will simplify the process a lot.
Many thanks for this informative blog post, Bogdan.
Another tool you can use to view android logs as well heap and system information is the Android Device Monitor, https://developer.android.com/studio/profile/monitor.html. It installs with Android Studio.
Thanks for article!
I create my own project with separate .so files for app & service similarly with your client/server example. It works nice, but I encountered some problems.
My sequencing:
1) client start service calling static java method with ‘startService’ command.
2) service run server.so lib with c++ code (specified in android.app.lib_name).
3) client and server exchange some information.
4) client stop service calling static java method with ‘stopService’ command.
My problems:
1) after ‘stopService’ command java part stopped, but c++ part continues execute (I see that client/server exchange does not stopped). It’s normal behavior? Exist some simple method stop service from client fully?
2) client subproject has access to java code and it’s work nice. But how I can access to java world from server subproject? I’m trying to add in server.pro file next code:
QT += androidextras
ANDROID_PACKAGE_SOURCE_DIR = $$PWD/android
DISTFILES += android/src/MyService.java
but this java file not building and not available from c++ code.
OK, for these days I found some working solutions for my troubles:
1) When java part destroyed, I call c++ quit method with jni and thus stop c++ part.
2) On Ubuntu I add java files to service subproject with this commands:
ANDROID_JAVA_SOURCES.path = java/package/path
ANDROID_JAVA_SOURCES.files = $$files(src/*.java)
INSTALLS += ANDROID_JAVA_SOURCES
unfortunately, on Windows with mingw this commands cause an error.
I follow the steps to use my service on demand but when i press the button to start the service my app crashed
here my AndroidManifest.xml
http://ideone.com/50J5UN
this my cpp class
http://ideone.com/WmtGU8
please I need help what make the app crashed when i start the service thank you
this my .pro file
http://ideone.com/JJNUEv
and png to my app from ide
https://s27.postimg.org/mem67dzyr/Capture.png
Does this https://github.com/KDAB/android/tree/master/examples/service example works ?
in service ,i start a QThread, but app was crash when QThread.start(), it is bug?
I’ll need more info, can you create a simple example and open a bug report on https://bugreports.qt.io ?
I have a strange error. After I start application and send some ping message to service (server), but after that, the service not working, I cannot get any pong event. When I go to setting, I saw the service restarting 0 processes and 1 service.
Hello BogDan!
Thank you so much for the article. But I have a problem. I downloaded your project from GitHub. I built and ran it. It works, but the service is killed (0 processes and 1 service) and restart after a few seconds. How I fix it?
And do I need to install Ministro service from Google Play? (I choose option “Bundles Qt libraries in APK”).
Thank you!
What Qt version are you using? There are a few fixes in 5.10.1.
No, you don’t need Ministro.
Hi BogDan!
Thanks for your answer.
My Qt version is 5.10.1.
Can you show me where I need to fix?
Some additional information: the service starts when the application starts. It starts perfectly if I do not close the application. But when I close the application, the service will restart after a few seconds. After several times, it has become “Not Active”.
Thank you very much!
Well, that’s the correct behavior.
Services that are not used by any application are usually closed.
Anyway, in a couple of days I’ll retest the example and update it if needed.
Thanks for your answer!
Yes, I know that’s the correct behavior. The service can be killed by the Android OS. But when I implement a background service in Android Studio (in onStartCommand method: return START_STICKY). It works perfectly, the service still runs even if I swipe the app in the recent menu.
Thank you very much!
Hi BogDan! Thank you for the article!
I need to implement using the same .so for app and service. I used project as base:
https://github.com/bbernhard/qtandroidservices_example
The debug is not working yet, right? So to check if my .so was running as service, I tried to create a simple folder using the main.cpp code:
if (QCoreApplication::arguments().count() > 1)
{
QCoreApplication app(argc, argv);
qDebug() << "I am the service";
QString appFolder(QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation));
QDir(appFolder).mkdir("Testing");
return app.exec();
}
But the directory was not created.
After, I was going to check if the Java Service class was running by creating a folder from inside of its onStartCommand method:
File dir = new File("/storage/emulated/0/TestDirectory");
boolean successful = dir.mkdir();
But it didn't work too!! ( I added the WRITE_EXTERNAL_STORAGE permission)
Calling this code from the activity works…
But using an app to check the running services, I see that the Java Service class is instantiated.
So, my questions are:
– Why can't I creat a directory from the Java Service class?
– Is the .so really being started as service?
Greetings from Brazil!
It’s working now! I put the libname just like the project name.
I recommend you to put here the main.cpp version of the same .so for service and app.
Thanks
Hi BogDan, I use the same .so for service and app.
I’m trying to make Android Interprocess Communication (IPC) with Messenger between the Activity and the Service (java implementation) since they are in different processes.
The communication is ok when I remove from the manifest this line:
But doing that doesn’t load the .so as service, just loads the Java Service implementation.
Is that a bug?
It seems that is not possible to load the Java Service Implementation and the .so as service together.
Actually, what I want is to receive the token and the messages from FCM services and process them in my .so service . It works fine in the app process, but the app process ends sometimes (causing an exception saying there is no implementation found for that native method).
I tried to set the same process name (:qt) for the FCM services, but they crash.
So, I want to exchange data between differents processes. Is that possible?
The line I was talking about is the meta-data: android.app.use_local_qt_libs.
Hi i have successfully implemented Android Interprocess Communication with ur example am using Qt 5.10.1 everything is fine but when i send a notification through the process the process crashes and doesnt restart the service still runs well and the notification is sent and this hapens when the main activity is not running….if the main activity is running the process sends the notification and process doesnt crash. Here is the source code for sending notification
#ifdef Q_OS_ANDROID
QAndroidJniObject titleObj = QAndroidJniObject::fromString(title);
QAndroidJniObject notificationObj = QAndroidJniObject::fromString(notification);
QAndroidJniObject acceptLabelObj = QAndroidJniObject::fromString(acceptLabel);
QAndroidJniObject rejectLabelObj = QAndroidJniObject::fromString(rejectLabel);
QAndroidJniObject::callStaticMethod(“com/HSEManagementSoftwareSolutions/HSEManagementSoftwareSolutions/ApplicationService”,
“sendNormalNotification”,
“(Ljava/lang/String;Ljava/lang/String;ILjava/lang/String;Ljava/lang/String;)V”,
titleObj.object(),
notificationObj.object(),
notification_code,
acceptLabelObj.object(),
rejectLabelObj.object());
#endif
My Service class
package com.HSEManagementSoftwareSolutions.HSEManagementSoftwareSolutions;
import org.qtproject.qt5.android.bindings.QtService;
import android.content.Context;
import android.content.Intent;
import android.app.PendingIntent;
import android.app.Notification;
import android.app.NotificationManager;
import android.media.RingtoneManager;
import com.HSEManagementSoftwareSolutions.HSEManagementSoftwareSolutions.R;
import android.graphics.Color;
public class ApplicationService extends QtService
{
private static ApplicationService applicationServiceInstance;
private static NotificationManager notificationManager;
private static Notification.Builder notificationBuilder;
static final String packageName = “com.HSEManagementSoftwareSolutions.HSEManagementSoftwareSolutions”;
static final String appName = “HSE Management Software Solutions”;
public ApplicationService()
{
applicationServiceInstance = this;
}
public static void startApplicationService(Context applicationContext)
{
applicationContext.startService(new Intent(applicationContext,ApplicationService.class));
}
@Override
public void onCreate()
{
super.onCreate();
}
@Override
public void onDestroy()
{
super.onDestroy();
}
static void sendNormalNotification(String title,String notification,int notification_code,String acceptLabel,String rejectedLabel)
{
notificationManager = (NotificationManager) applicationServiceInstance.getSystemService(Context.NOTIFICATION_SERVICE);
notificationBuilder = new Notification.Builder(applicationServiceInstance);
notificationBuilder.setSmallIcon(R.drawable.icon);
notificationBuilder.setContentTitle(title);
notificationBuilder.setContentText(notification);
notificationBuilder.setAutoCancel(true);
notificationBuilder.setPriority(Notification.PRIORITY_HIGH);
notificationBuilder.setVibrate(new long[] { 1000, 1000, 1000, 1000, 1000 });
notificationBuilder.setLights(Color.RED, 3000, 3000);
notificationBuilder.setSound(RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION));
notificationBuilder.addAction(R.drawable.yesicon,acceptLabel,PendingIntent.getActivity(applicationServiceInstance,0,new Intent(applicationServiceInstance, ApplicationActivity.class), PendingIntent.FLAG_UPDATE_CURRENT));
notificationBuilder.addAction(R.drawable.noicon,rejectedLabel,PendingIntent.getBroadcast(applicationServiceInstance.getApplicationContext(),0,new Intent(“com.HSEManagementSoftwareSolutions.HSEManagementSoftwareSolutions.NotificationCancled”).putExtra(“notification_id”,notification_code),PendingIntent.FLAG_CANCEL_CURRENT));
notificationManager.notify(notification_code,notificationBuilder.build());
}
}
Please help me cause the process should be working all the time as long as the service is running to sync with my server for notifications and updates. Thanks
Please try with Qt 5.12.1, I think I fixed a bug on this matter.
If it still not working please use https://bugreports.qt.io to file a bug report.
Great Article.
How to have that myservice running in a separate android application and still communicating with client application ?
You can use QtRemoteObjects
Hi,
I have a Qt console app that provides a web server interface to control a music player – it’s running great in Windows/Linux/Raspberry Pi… I’d like to port it into Android as a service. Would you recommend a “thin wrapper” app that shows the http: interface, or a method that uses Chrome or another browser to access the interface?
Thanks!
Are you looking for this https://doc.qt.io/qt-5/qtwebview-index.html ?
I ported my project from Qt5.9 to Qt5.12 (both LTE) and I stumbled heavily over the 5.10+ change from QCoreApplication to QAndroidService.
It cost me several days… it doesn’t crash instantly… just after approx. 10s came up a runtime exception (“W/Binder: Caught a RuntimeException from the binder stub implementation.” and that’s probably just one consequence of the misbehavior) and then the service has restarted.
Isn’t there a chance to write at least a clear message to the logcat? As you wrote already a better and more reliable integration of Android Services into the QtCreator would be desirable. Then it would be easier to catch wrong implementations at build time. But anyway, BogDan thank you very much for your long and profund development!
It will be great if you can create a simple example that I can use to reproduce the problem and create a full bug report here https://bugreports.qt.io .
Otherwise it’s very hard to know or even guess what is wrong in that code …
How to create a qwebsocket client in an android service using qt?
First of all thank you for this great article, now I am able to create android services in qt but as I have got to create a qwebsocket client in an android service using qt so now I am lost how to do it. Any pointers would be highly appreciated.
Usually you create the qwebsocket client as you create it on any application.
Thank you sir for this great post! I’m also trying to send notifications from service but nothing shows up. Any ideas? I wrote my notify function, as described in Android docs*, in AndroidService.java (which extends QtService). I call notify() via AndroidJniObject::callStaticMethod in “server.cpp”.. But it doesn’t work though same implementation exists in AndroidActivity.java (extends QtActivity) and it works as expected. I tried many things but… I even dont know if the problem is Qt-related or not. To inspect I call Log.e(QtApplication.QtTAG, “…”) in many places but only the ones in startMyService() shows up in “Application Output”. + same for adb logcat.
Thanks again!
*https://developer.android.com/training/notify-user/build-notification.html
Hello Bogdan and thanks for your post!
I managed to build a service in QT and call it from an Android project and now I am trying to communicate with it and was wondering if I could do it using AIDL files, do you have any resources or links that I can read to make it work? Please note that I do know how to do it in Android native (from an Activity to a service for eg.) but I don’t have a clue if I can implement the AIDL in a QT project, if QT knows how to implement those methods.
Thanks a lot!
Catalin
This works great for me, except I cannot get Qt creator to attach to the service process for debugging/logcat. Is there a way for the debugger to attach to both?
Sadly, QtCreator doesn’t support that feature.
Can you show a working example of the Source emitting a SIGNAL that the Client utilizes?
I have been trying to have my Source emit a SIGNAL to a Client SLOT, but do not get the code in my SLOT executed once the SIGNAL is emitted…
My Source is my app, and the Client is the service.
Hello. Thank you for post, its wery helpfull.
I use separate .so to start my QAndroidService process/
I successful start it and call jni object for create notification from background process.
when my process done his work i call stopService
QAndroidJniObject::callStaticMethod(“org/qtproject/example/neoclient/MainNotifyService”,
“stopService”,
“(Landroid/content/Context;)V”,
QtAndroid::androidActivity().object());
but when my service stooped, android show me window with message
“application NeoClient was stopped”..
this is not looking good. tell me please how can i stop my service without this message
// java file goes in android/src/com/kdab/training/MyService.java
I’m sorry for silly question, but Where exactly does go this file? Where should it be? On my android device, in my folder with QtProject? I can’t get it
In your QtProject folder.
Hi Bogdan,
Firstly, I would like to sincerely thank you for the great job you did. Your explanations are clear, and the examples are very relevant.
I am trying to implement your client/server example using the last release of Qt5.14 and android sdk 29. I use the emulator (nexus 5x android 29 x86) and the problem is that the program timeout in the method `rep->waitForSource();` even when increasing timeout value.
Have you already encountered such a problem? And if yes, did you succeed in solving it? The service on the java part starts but after that I do not know if the main server code is called.
Thanks a lot for your answer !
Best regards,
Thibaud Kloczko
It seems you’re not staring the service before you call
rep->waitForSource()
.Hi!
Thanks for you work.
I’m trying to test the source code published at KDAB’s GitHub (https://github.com/KDAB/android/tree/master/examples/service) using Qt 5.15 for Android 29 x86. The assertion for `Q_ASSERT(res)` is fails every time.
I’ve tried to write my own tests according to your article and to Qt Wiki, but it seems that the service is never started.
Have you tried to make this steps on latest Qt?
Sorry for my pure English and thank you in advance!
Please check https://doc.qt.io/qt-5/android-services.html as it has a more up to date info.
Hi,
I have the same problem, my code was working on Qt 5.12 but no longer works on 5.14/5.15
The service was running in a different process (android:process=”:qt” in the manifest) but if running in the activity process I got :
W System.err: java.lang.IllegalArgumentException: Wrong number of arguments; expected 1, got 0
W System.err: at java.lang.reflect.Method.invoke(Native Method)
W System.err: at org.qtproject.qt5.android.bindings.QtApplication.invokeDelegateMethod(QtApplication.java:157)
W System.err: at org.qtproject.qt5.android.bindings.QtServiceLoader.onCreate(QtServiceLoader.java:59)
W System.err: at org.qtproject.qt5.android.bindings.QtService.onCreateHook(QtService.java:54)
W System.err: at org.qtproject.qt5.android.bindings.QtService.onCreate(QtService.java:60)
W System.err: at android.app.ActivityThread.handleCreateService(ActivityThread.java:3756)
W System.err: at android.app.ActivityThread.access$1400(ActivityThread.java:237)
W System.err: at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1801)
W System.err: at android.os.Handler.dispatchMessage(Handler.java:106)
W System.err: at android.os.Looper.loop(Looper.java:214)
W System.err: at android.app.ActivityThread.main(ActivityThread.java:7050)
W System.err: at java.lang.reflect.Method.invoke(Native Method)
W System.err: at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:494)
W System.err: at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:965)
W System : ClassLoader referenced unknown path:
Best Regards,
Mikael
Hi Bogdan,
Thanks for your blog and your work on Android. It’s quite hard to find information on the subject with some complete examples… I don’t know much on Android OS itself but I wish to start deploying QML/Qt applications on it. I’ve successfully made my first App which can send SMS thanks to your article (Episode 5). It’s here: https://github.com/mbruel/sendSMS.
Now I’d like to be able to do a service and I’ve several questions.
First I don’t manage to deploy this Ping/Pong example. I’m confused.
Both the service and the App front end are supposed to be together in one apk right? We just have to build service.pro?
For me the service apk is building well but then when I debug it on my phone nothing is happening. I’ve a blank screen on the phone with the client app opened and this errors on QtCreator:
W ActivityThread: Application com.kdab.training is waiting for the debugger on port 8100…
The command “/home/bruel/android/sdk/platform-tools/adb” terminated with exit code 1.
adb: error: listener ‘tcp:5038’ not found
E m.kdab.trainin: Invalid ID 0x00000000.
E Qt : Can’t create main activity
E Qt : android.content.res.Resources$NotFoundException: String array resource ID #0x0
E Qt : at android.content.res.Resources.getStringArray(Resources.java:597)
E Qt : at android.content.res.MiuiResources.getStringArray(MiuiResources.java:160)
E Qt : at org.qtproject.qt5.android.bindings.QtLoader.startApp(QtLoader.java:423)
E Qt : at org.qtproject.qt5.android.bindings.QtActivityLoader.onCreate(QtActivityLoader.java:166)
E Qt : at org.qtproject.qt5.android.bindings.QtActivity.onCreateHook(QtActivity.java:266)
E Qt : at org.qtproject.qt5.android.bindings.QtActivity.onCreate(QtActivity.java:273)
E Qt : at android.app.Activity.performCreate(Activity.java:7224)
E Qt : at android.app.Activity.performCreate(Activity.java:7213)
E Qt : at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1272)
E Qt : at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2926)
E Qt : at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3081)
E Qt : at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:78)
E Qt : at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:108)
E Qt : at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:68)
E Qt : at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1831)
E Qt : at android.os.Handler.dispatchMessage(Handler.java:106)
E Qt : at android.os.Looper.loop(Looper.java:201)
E Qt : at android.app.ActivityThread.main(ActivityThread.java:6810)
E Qt : at java.lang.reflect.Method.invoke(Native Method)
E Qt : at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:547)
E Qt : at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:873)
W Looper : Slow Looper main: Activity com.kdab.training/org.qtproject.qt5.android.bindings.QtActivity is 7754ms late (wall=596ms running=0ms ClientTransaction{ callbacks=[android.app.servertransaction.LaunchActivityItem] lifecycleRequest=android.app.servertransaction.ResumeActivityItem }) because of 1 msg, msg 1 took 7849ms (late=1ms h=android.app.ActivityThread$H w=110)
Any idea why?
Here are some other questions:
1.: if the service and the front end are both in a single apk. I suppose that when we first launch the app, both the front end and the service should be started. Is it correct?
2.: If we close the app, is the service still running? How can we know it is running?
3.: If we launch again the app and if the service is still running we don’t launch a second service right?
4.: How can we build the service alone in it’s own apk if maybe it doesn’t need a front end and we just want it to run in the background? Could you explain how to create a pro file in order to build such thing.
Thanks in advance 😉
Matthieu
If you’re trying the example from https://github.com/KDAB/android you’ll need to use Qt up to 5.14, as in 5.14 we’ve changed the manifest and my repos it’s not update. I recommend you to use 5.12.x.
If you’re new to Android, IMHO, before you start working with services you should read https://developer.android.com/guide/components/services and then re-read my article one more time.
Regarding your questions:
1. Check Step III: How to start the service ? from my article.
2. yes, see https://developer.android.com/guide/components/services#Basics
3. yes, see https://developer.android.com/reference/android/content/Context#startService(android.content.Intent)
4. Usually a serice has a front end, otherwise it needs to start at boot time. You’ll need to remove the activity part from manifest file. If you check my sources you’ll see that the client & server have different .pro files, server.pro it’s what you’re looking for.
Hi again,
After investigation the problem is related to the fact that the main function of the service is never called. We tried to set the service in different .so, in the same .so, we modified the manifest with all the possibilities we found in the doc and in the forum, we are stuck.
We use Qt 5.14.(1 and 2) and android 21, 25, 28 and/or 29.
We post a message on the qt forum in the following thread that points out the same issue:
https://forum.qt.io/topic/112118/qt-android-services-documentation-and-reality
Thanks again for the great job and thanks for the help,
Sincerely,
Thibaud Kloczko.
QtAndroidService intended to use for all kind of services include Quick Settings tile services?
In principle you can use anything that doesn’t paint anything.
Hi! I made the first 3 points, but the app does not compile. I looked at the example code. Why do I need a server in the example? Is it possible to do without a server?
Please check https://doc.qt.io/qt-5/android-services.html as it has a more up to date info & sample code.
Do You have any code with this example? According to the documentation, it is unclear what to write where.
https://doc.qt.io/qt-5/android-services.html lacks info for non-extended services, with native part, which should run on boot time (or called somewhere else from OS or other app).
This seems addressed to extended services (but no mention on that):
“Note: To run a service at boot time, it has to be defined as a separate process, see Service in Separate Process.”
As i understand, if non-extended service should work at boot time its native part should be loaded somehow and it must be separate .so file. There probably needed some <meta-data… manifest declarations as for extended services.
There is also case: non-extended service that uses Qt classes ( it rely on Qt, but don't needs Qt event loop, so service can be non-extended)
Is it possible to display output (qDebug(), Log.i()) from QtService process in QtCreator?
Sadly the patches that I created to allow QtCreator to display all the logs were reverted and nobody wanted to “fix” them, therefore in this moment you can’t see the services logs in QtCreator, but you can see them using *adb logcat*.
What stays behind requirement to run QtService-extended services in separate process?
It would be handy if there is no such requirement
What stays behind the requirement to run QtService-extended service in separate process?
It would be nice if service could run in the same process with QtActivity, separate process adds extra limitations and complexity.
The problem is Qt’s architecture which can’t handle a service and an UI in the same process.
We’ll see if in Qt 6 the things will change.
I guess problem appears when QAndroidService and QGuiApplication/QApplication instantiated in same process.
It should be possible with Qt 5.1x to make service that can run in same process and have it’s separate ‘service.so’ lib with C++ functions, but without QAndroidService instance (and hence without Qt event loop & event processing). Java’s service class will call functions from ‘service.so’ as native callbacks.
As i understand, if service extends QtService, then QtService processes attributes at AndroidManifest’s service declaration, e.g. it will load ‘service.so’ library, which attributes are required for that?
If service extends android.app.Service then ‘service.so’ should be loaded other way (Google NDK guidelines)?
Without an event loop Qt it’s pretty useless (e.g. you can’t use timers, sockets, or anything that needs an event loop). If you don’t need Qt and only some native stuff, then it’s easier to use directly the Android’s Services.
Hi Bogdan,
is there a way to pass extended data to startService that can be retrieved in the main function of the service? I know I can add data to the intent with putExtra. But can I get hold of this intent somehow?
Thank you!
Toni
Hi Bogdan,
Seems to be a while since anyone has posted to this thread, but I’ll give it a try.
I am more a QT person than an Android head, so please excuse my ignorance there.
I have succeeded in getting the counter app/service example going.
I have then attempted to build up from there to do what I’d like to do, which is to have a service that periodically sends GPS coordinates to a web destination while the phone screen is off.
I have succeeded in creating a service that is able to send things to the web, so networking works (ie. QT+ networking in the service .pro file). I can trigger send that by sending the contents via QRemoteObjects.
However, I have discovered, that as soon as I add gps positioning (ie. QT+ positioning in .pro file), the service will crash, even if I never actually call or instantiate anything in QT positioning from within the service.
I toyed with trying to send positions periodically from a backgrounded UI app to the service, but Android doesn’t assure a backgrounded app will run, so it only works occasionally and randomly (depended on the target phone). The link between the app and the service also seems to break randomly once the app is no longer in foreground.
Is it currently impossible to add QT positioning to a service?
Well in 2021, starting from one android 9 starting the service using ‘BroadcastReceiver’ is prohibited.
Also the service will force the app to exit randomly with this error:
‘Android error: Stopping service due to app idle’
So we are going to need another update on this guide, i’m having a hard time understanding the java part of my project and it would be awsome if you could update this guide.
Please check the official documentation here https://doc.qt.io/qt-5/android-services.html which should be more up to date.
update: for the second problem i found this link.
http://tutorialspots.com/android-error-stopping-service-due-to-app-idle-6691.html
This is very nice but if one is using Qt6 this doesn’t work. Can you consider making a Qt6 version of this discussion? I am trying my best using Qt’s example and it doesn’t work at all.
Chris, you may find it helpful to look at the Qt documentation page on Android services: https://doc.qt.io/qt-6/android-services.html
looks like using Qt6 with separate SO doesn’t work.
Is there any references that we can try with?