Qt on Android Episode 6 - How to use Android Studio to extend and debug the Java part of your Qt application
Update: Here you have also the Chinese version, thanks goes to Foruok.
In the last Qt on Android episode we learned the basics of JNI on Android in a Qt way. In this episode I’d like to focus on tools that will help us to be more productive when we extend our Qt on Android applications.
Using an external IDE to manage Java files.
Sadly, the Java support in Qt Creator is very limited, and in order to be productive we need to use an external IDE to easily extend and debug the Java part of our application. Android provides two powerful IDEs:
- Android Studio
- Eclipse (recently deprecated).
This article will focus only on Android Studio.
But before we talk more about tools, let’s check the Android specific files which are part of your project.
As I told you in the first article, any Qt on Android application has two big parts:
- The native part, which is your C/C++ [Qt] code built into one or more .so files.
- The Android specific part:
- Android manifest file.
- Android build system file(s).
- Two Java classes which are needed to load your application dependencies, the application .so files and start the application.
- Ministro service .aidl files and other resources, e.g. assets, strings, images, etc.
All the Android specific files are needed to build your android package (as we learned in episode 3). But where are all these files? Why are only a few files copied to your sources when you press “Create templates” button (as shown in the next image)?
Well, Java, Ministro service .aidl files and some resources are kept “hidden” in your Qt SDK. We don’t want to copy them to your source tree for two reasons:
- We might change them from version to version and we might break the compatibility. If they are part of your project it will be impossible to upgrade them and your application will misbehave (e.g. Java files from Qt 5.4 might not be compatible with Qt 5.5).
- We don’t want you to change them, because the code in these files is quite sensible, hard to explain and understand and changing them might break your application behavior. If you should not change them, then all your applications will share the same files, so again there is no point in copying them :).
Before Qt 5.4 it was quite complicated to extend the Java part of your application, mostly because you could not use an external IDE (Eclipse) in a decent way (e.g. with syntax highlighting, code-completion, code-refactoring, etc.). In order to get these goodies you had to manually copy all the Java files from Qt SDK installation folder to your application source folder, but as I said, we don’t want you to do that and the only way to do it was to copy them locally and not add them to your SCM…
But starting with Qt 5.4. the situation changed when I added Gradle support to Qt 5.4 and to Qt Creator 3.3. Gradle is the new recommended android build system which is used by Android Studio. Using Gradle we can keep all these files hidden and still give you all the goodies that you expect from a 21st century IDE. So, if you are planning to extend your Java part of your application, it is highly recommended to Copy the Gradle files to Android directory as shown in the next image:
Besides the AndroidManifest.xml and res/values/libs.xml files, the wizard will copy a few more:
- build.gradle – this is the project file needed by Android Studio.
- gradlew[.bat] – build script wrapper used to build Java part and to create final APK.
- gradle/wrapper/* – build script wrapper files
build.gradle is very important, it allows you to easily add dependencies to your project.
E.g. to add PlayServices to your application you just need to add:
dependencies { ... compile 'com.google.android.gms:play-services:7.0.0' }
to build.gradle, check this page for more info on this matter.
Now let’s see how to use Android Studio with Qt:
Android Studio will be used only to:
- open the Gradle project.
- create, edit the java files.
- debug the Java part.
Android Studio will NOT be used to run your Qt application, you still need to use Qt Creator for that job!
Let’s take a look on how to import the Java part of your Qt application and how to debug it.
The import step is very easy: you just need to Open the existing build.gradle project file. Check the following image:
Warning: Qt 5.4.0 users should upgrade their gradle files using Qt 5.4.1 or later (press again Create templates button and overwrite only gradle files). This step is needed because Qt 5.4.0 uses an old Gradle plugin and, after we released it, Google, as usual, broke the compatibility with older Gradle plugins and Android Studio doesn’t import Qt 5.4.0 projects.
The last thing we are going to learn today is how to debug the Java part using Android Studio. You need to take the following steps:
- set the breakpoints
- attach debugger (Run->Attach debugger to Android process)
- start the application using QtCreator
- wait for application to start (you should see it in Attach debugger dialog).
- select the application
- click the OK button
After the last step, your application will be stopped by Android Studio when it hits first breakpoint.The problem comes when we need to start the debugging very early. To do that we are going to use the old fashioned sleep trick Debug.waitForDebugger() function.
This is how our custom onCreate function looks:
@Override public void onCreate(Bundle savedInstanceState) { Debug.waitForDebugger(); // .... super.onCreate(savedInstanceState); }
Now the application waits until a debugger attaches, then in resumes the execution.
Now that we have learned the basics of the JNI and how to use external tools to make la vie en rose (or la dolce vita), in the next article we will talk about Qt on Android apps architecture: how to extend the Java part of your application using a real life example to show how to correctly do safe calls from Qt thread to Android UI thread and vice-versa.
Instead of using Thread.sleep(10000), you should use Debug.waitForDebugger(); with the import android.os.Debug
This will be easier ^^
Thanks for the tip, I updated the post.
Hey Bogdan!
My question is not totally related to this episode (I have read all of them, maybe to the first episode more), rather to the story of Qt on Android. What I need is running QML in a single view or fragment in my existing app. Is that possible with some hacks?
I already checked that the android build generates a project which is perfectly compilible in Eclipse, for example. In theory I would like to create a qml app in QtCreator, get the generated project with all the .so files and loading/working logic and continue in Eclipse/Java world – updating the qt part from time to time when enhancing QML program. This can be done on activity level, when the QML part is given it’s own activity. But I would like to give it just a view (or fragment). I thought that in theory I can give it a surface, I even found a QtSurface class and other classes intended for drawing QML stuff. I have seen that the generated Qt activity has eventually just one view having all the program running in it.
Let me know your thoughts on this, if this is possible.
Thanks!
Theoretically it might be possible, but it will not be easy at all 🙂 .
Qt needs a SurfaceView (not a simple View !) to draw its scene, check http://www.kdab.com/future-qt-android-looks-bright for more info on this matter.
It will be easier to do it the other way around, to put native controls on top of your QML application.
If you want a pure Android UI and still use QML, J-P Nurmi started such a project, check http://lists.qt-project.org/pipermail/development/2015-April/021149.html .
Thanks, I will definitely check that! Meanwhile, I did a small hack – since I didn’t get deep enough into the codes to understand how to create that view holding qml, I just used the one created for me – overriding setContentView in QtActivity and put the view given to it wherever I want. This has a lot of limitations, of course (like only one “qml view”) but is a good starting point for research.
Karen, I need to do something similar…. Did you ever get this working?
Really informative! Really, thank you very much!
Qt as a poor documentation about JNI.
I’m currently trying to read some NFC tags from qt. I have made a small program which work perfectly with Android Studio (it just display the UID in the middle of the screen).
Can I load this Java code using natives (as you well explained on episode 5)?
I see your point for calling function, but what about onCreate, onNewIntent,etc?
Thanks again!
Thanks BogDan for these useful stuffs. But can you show me a way to continue running the C++ part by service? And the C++ part should be in interact with QML (when the user has opened the app)
The GUI (qml) part and Keep-Alive when the app closed is very important.
the C++ and QML part is ready and working like a charm but i dont know how switch it to Keep-Alive Android Service when the user closing the application.
Thank you
I think you’ll need to wait for https://codereview.qt-project.org/#/c/110625/ to be reviewd and to get in. But it will not solve all your problems, because most probably the service and the UI will run in different processes.
If you don’t want to wait that much for that patch, you can use the information from episode 5 to episode 7 and create your own service. This way you’ll have more control on how it interacts with your application.
Hi,BogDan,here is the Chinese version: http://blog.csdn.net/foruok/article/details/46115131
Thanks.
Please make an update, the images are not shown in the article. QTC_CopyAndroidTemplatesCopyGradle_o.png