Porting program to Android
I wrote a music player for Linux/Windows using QML and C++. Now I would like to port it to Android too. I have 2 problems and I couldn't find a solution myself. I don't even know if a solution exists.
These are the problems I can see:
I use taglib for reading tags. This library works perfectly on Windows and Linux. But I have no idea how can I compile it for Android (ARM architecture) and then include it with my application in APK. What should be the steps?
Another probably more complicated problem is that I need a background service for my application which can not be killed by the OS. I'm not sure if this is possible in Qt at all.
- I don't this library, but I see it uses cmake. I'd say it's very likely that you can build it for Android. First of all you need to get NDK and then make a standalone toolchain out of it. After that you should be able to compile it using the standard procedure for cross compilation.
- This service needs to be native. You can't do it in pure Qt, but that's not a problem. On Qt for Android you can add java source to your app and interact with it using JNI.
I finally found some time to try something out. I studied about the JNI and the interaction between Qt and Java parts.
Also I found out how to cross compile the library for Android. So this is now done. My code compiles fine but when I try to run it in emulator, I get this error:
E/dalvikvm( 2290): dlopen("/data/app-lib/org.qtproject.muzika-2/libMuzika.so") failed: dlopen failed: could not load library "libtag.so.1" needed by "libMuzika.so"; caused by library "libtag.so.1" not found D/AndroidRuntime( 2290): Shutting down VM
The compilation of TagLib created 3 files: libtag.so, libtag.so.1 and libtag.so.1.15.1. These 3 files are identical, just the names are different.
In QtCreatir using Projects->Run->Additional Libraries->Add... I can only choose the .so file. This file is then included in the created APK. But the program for a (to me) unknown reason tries to load the libtag.so.1 library.
I also found this information: https://bugreports.qt.io/browse/QTCREATORBUG-11062
Is it still valid? Is the problem in the way I compiled the TagLib library? Thank you.
Hi. I also had the same problem. The only way I could get it to work was using static linkage.
Since I try to keep the same toolchain and build process for all platforms (win32, desktop Linux, Android), I would like to keep the dynamic link.
But I don't know at which part the problem is located. QtCreator or CMake? CMake creates 3 libaries as I mentioned. QtCreator packages the .so to an APK but then links to .so.1. So I would guess there is a problem in QtCreator.
If I compile for Windows I also don't have any library versions and QtCreator links correctly the libtag.dll. Unfortunately I don't have enough knowledge to figure this out myself. :-(
@vlada, I think your problem is related to the way your building your shared library for Android, and not related to Qt or Qt Creator at all.
I succeed building and using F5 steganography libray (see https://github.com/harlo/F5Android) which it only ends up providing a single .so file (no symlinks at all for .so.x).
Please see also PixelKnot (https://github.com/guardianproject/PixelKnot) a project using the F5 library. You'll find instructions there to build it, but essentially narrows down to "ndk-build -C external/F5Android/", I mean building the library with the NDK.
Once I finally got the .so file build (see that it looks like you are getting the real file as .so.1 and .so is just a symlink to it) I copied the library in my Qt project under a particular location following some pre-defined path: my-qt-project / android / libs / armeabi-v7a / so Qt Creator finds it and deploys to the Android decive without any issue.
@Pablo-J.-Rogina I used CMake on Windows to compile the library. I used android.toolchain.cmake from here. The first result were 3 identical files as I already wrote. Those were real files, since I tried that on Windows.
Then I modified CMakeLists.txt in taglib directory to remove any mentions of it's version like set(TAGLIB_LIB_MAJOR_VERSION "1"). After these modifications I only got one .so file.
Unfortunately when I linked to this dynamic library from QtCreator, the result was the same. QtCreator linked to libtag.so.1. I don't understand why. How does the login in QtCreator work? In Windows it links to libtag.dll and doesn't add any version to the filename. Why it doesn't work equally for Android which also doesn't support library versions?
What else should I try? I'm not using ndk-build directly but through CMake. I'll try it once again on Linux. Maybe I get different results.
I thought I might chime in about the third party libraries. If you compiled them with the android toolchain when building the apk it won't include them automatically. You have to use
ANDROID_EXTRA_LIBS. What I did since the libraries I use aren't huge codebases was to create a
.profile for each of them and with
vimI would do
read !ls src/*.cpp(this is an example) for sources/headers thus including the sources in the
profile. I also read the cmakelist to exclude certain source code files that aren't needed (mostly for linux/unix systems, do beware that you may need to do conditional includes if you want to support windows, all depends on how the source is laid out in the third party). Certainly it takes time to do but I prefer it this way because then I don't have to do manual compilations or verifying if all the processes have been successful, it's all within qmake.
ANDROID_EXTRA_LIBS += \ /SOME/ABSOLUTE/PATH/libtag.so \ /absolute/path/libpotato.so \
When building the apk androiddeploy will take hint at those extra libraries and copy them along with your app's .so file as well.
@David I'm glad you mentioned it. I forgot completely. I indeed have such variable in my .pro file.
Anyway, I still think @vadla's problem is related to the way he's building the external library for Android.
@Pablo-J.-Rogina Yes, this is correct. Android does not support versioned shared libraries, so you have to change the build scripts for that library so that it produces a library name with the form libFOO.so.
@vlada would you mind sharing the CMake-related files you changed (i.e. CMakeLists.txt and any others you may have modified) to build the library? Even when working on Windows and using that android.toolchain.cmake as you mentioned, I expected that you're compiling TagLib using Android NDK, right?
I'm sorry for my very late reply. I finally found some time to try a couple things out. As I already mentioned I succeeded to compile the taglib library without any version number. But it didn't help.
Las week I updated to the latest QtCreator and Qt5.6 a tried to compile my player again. It didn't work. QtCreator was complaining that I try to package a taglib.so.1 file and it will only accept .so files. I didn't remember all the changes I did to project files so I decided to start from the scratch. And suddenly my application runs!
If anyone's interested in the modified scripts for CMake I used, I uploaded everything to SourceForge. The source code is a mess. It is my first C++ creation so expect a lot of nasty things. But it works. :-)
Now I need to tune the program to work on Android correctly. I have two major problems:
The player works as expected if it is in foreground. In background in continues to play but the next song won't start. I probably need to create a thread that will run in background. I use signals positionChanged and mediaStateChanged from QMediaPlayer. If the playback of current track is finishing, I look for the next track to play. And once it really finishes, I start playing the next track. How can I react to these signals even if my application is in background?
If Android closes my application, I don't get any kill signal so I can not react on it and save settings, current track, progress etc. Is it normal? How can I find out that Android wants my app to quit and I have to save current state and close correctly?
Thank you very much for your advices.
@vlada thank you for sharing your code. I'll give a try to building taglib for Android.
Regarding those two issues you've just mentioned, I'd suggest please to creat two new post to the forum. I guess stating the problems separately will give them more visibility and increase the chances you got answers from some more people.
As far as I know Android does not support versioned libraries like taglib.so.1
So you have to use instead taglib.so
@jsulm I know this. It has been already said in this thread. Unfortunately it didn't work for me until I updated to latest QtCreator.
@Pablo-J-Rogina OK, I will create a new thread for the problem with running the application in background. I'm afraid it won't be possible until Qt5.7 is released. But there might be another already working solution. I'll ask.
Edit: I marked the thread as solved. The first of my questions has been answered and I hope the source code I published can help other people who would like to use a standard Linux library in their project to port it to Android. I created a new topic for the second question. Many thanks to everybody for your help.