Taking Qt for Python to Android

Deploying Python applications to Android is a big talking point these days among the Python community, and a frequently asked question by people developing their first GUI applications. There are already a couple of Python frameworks that offer the ability to deploy your applications to Android devices, and Qt for Android has existed for a decade now. With QML and Qt Quick, one can use Qt to develop native Android applications. It was high time we bridged the gap and brought PySide applications to Android. 

With the new 6.5 release, we give you a new CLI tool, pyside6-android-deploy, that provides an easy interface to deploy your PySide6 application 🎉. 

Technical Details 

Currently, this tool is only available on Linux-based environments, and only a subset of the Qt modules are supported (see Considerations).  

This tool uses a custom fork of the python-for-android project with a custom Qt bootstrap and recipes for PySide6 and shiboken6. The reason for using python-for-android instead of androiddeployqt is that python-for-android already provides a way to package the Python interpreter, which is by default not pre-installed on Android platforms. It can also be easily extended to include new Python packages, even those with a C/C++ backend. python-for-android already supports many popular Python packages like numpy, pandas, etc. 

The entire deployment process is a 3-step process, where the first two steps need to be done only once per Android platform. The first two steps are setting up and cross-compiling Qt for Python wheels required for pyside6-android-deploy to work.  

Steps to deploy your PySide application to Android 

As mentioned above, Steps 1 and 2 need to be done only once for a specific Android architecture. Each PySide6 application that you deploy will use the same Qt for Python wheels. 

Step 1: Setting up prerequisites 

The Android dependencies for PySide6 are the same dependencies as those for Qt for Android. This step involves downloading the JDK, Android NDK, and Android SDK. You may skip this step if you already have them downloaded and set up. The recommended NDK version for PySide6 version 6.5 is r25. You can either use Qt Creator to install all the dependencies or install the dependencies manually, as shown below.  

1. Install JDK 11 or above. See instructions here.
2. Download the latest version of `Android Command Line Tools Only ` for Linux. This will download a .zip file. 
3. You can use the following script to help you download and setup Android SDK and NDK(r25c) into your current working directory. 

#!/bin/bash 
shopt -s extglob 
if [ -z "$1" ] 
  then 
    echo "Supply path to  commandlinetools-linux-*_latest.zip" 
    exitfi 
android_sdk=$(pwd)/android_sdk 
mkdir -p $android_sdk 
unzip $1 -d $android_sdk 
latest=$android_sdk/cmdline-tools/latest 
mkdir -p $latest 
mv $android_sdk/cmdline-tools/!(latest) $latest 
$latest/bin/sdkmanager "ndk;25.2.9519653" "build-tools;33.0.2" "platforms;android-31" "platform-tools" 
cp -avr $android_sdk/cmdline-tools/latest $android_sdk/tools

Simply run the script by giving it execution permission (chmod +x) and passing the path to the downloaded .zip file as a cli argument. 

4. Add the Android SDK and NDK paths into the following environment   variables: 

export ANDROID_SDK_ROOT=“/android_sdk” 
export ANDROID_NDK_ROOT=“/android_sdk/ndk/25.2.9519653” 

Step 2: Cross-compile Qt for Python wheels for Android 

Python-for-android requires shiboken6 and PySide6 to be cross-compiled during the deployment process to produce Qt for Python binaries that are compatible with the specific Android platform. Cross-compiling Qt for Python every time for each of your applications can be a cumbersome, time-consuming task 😫. Hence, it is better to use cross-compilation once to create Qt for Python wheels for an Android platform, which can be reused for each of the applications that you deploy. We have made creating these wheels easier for you with a Python script which is available in the Qt for Python source repository.

Make sure to install all the project requirements up to and including “Getting the source”, then install the cross-compilation requirements like this: 

pip install –r tools/cross_compile_android/requirements.txt 

And run the following script:  

python tools/cross_compile_android/main.py --plat-name=aarch64 --ndk-path=$ANDROID_NDK_ROOT --qt-install-path=/opt/Qt/6.5.0 --sdk-path=$ANDROID_SDK_ROOT

In the above command, --plat-name refers to one of aarch64, armv7a, i686, x86_64 depending on the target architecture. --qt-install-path refers to the path where Qt 6.5.0 or later is installed. Use  --help  to see all the other available options.   

After the successful completion of this command, you will have the Qt for Python wheels in `pyside-setup/dist` folder. 

Note: We recommend using venv or virtuanenv

Step 3: Deploy your application - pyside6-android-deploy

For this tutorial, we take a simple QtQuick example Scene Graph Painted Item example.  You can download this example directly from the link. One main requirement of pyside6-android-deploy tool is that the main Python entry point file should be named main.py. Change the name of painteditem.py to main.py and adjust correspondingly in painteditem.pyproject. The requirement of having the main Python entry point named main.py comes from python-for-android. Having the .pyproject file is not a strict requirement, but it enables pyside6-android-deploy to find the files associated with the project more easily and not include any unnecessary files. 

Run the following command: 

pyside6-android-deploy --wheel-pyside=pyside-setup/dist/PySide6-6.5.0a1-6.5.0-cp37-abi3-android_aarch64.whl --wheel-shiboken=pyside-setup/dist/shiboken6-6.5.0a1-6.5.0-cp37-abi3-android_aarch64.whl --name=painteditem  

In the above command --name refers to the application’s name, as shown in your Android device. Use --help to see the other available options. 

At the end of this command, you will have a .apk file created within the application directory, which you can install on your aarch64 based Android device. Hurray, you have successfully taken your Qt for Python application to Android🎉.

Considerations🤔 

1. Presently, the tool `pyside6-android-deploy` only works from Linux.  

     This limitation comes from our cross-compilation infrastructure that we are actively looking to improve and allow macOS and Windows users to also deploy Android applications. 

2. Qt modules supported: QtCore, QtGui, QtWidgets, QtNetwork, QtOpenGL, QtQml,     QtQuick, QtQuickControls2.

3. The main Python entry point of the application should be named main.py 
     This requirement comes from python-for-android. 

What can you expect in the future?🤖

1. More tutorials and examples
     You can expect all the Qt for Android examples to also work and be available for PySide6 Android deployment.

2. Simplifying the current deployment process

3. There are some manual steps that we are aiming to remove, to allow the deployment of applications to be more straightforward.

4.Additional Qt modules compatibility

   There are many examples and real use-case that our Qt for Android offering has, and we want to aim to be compatible with them. That’s why we see value in adding support for QtConcurrent, QtPositioning, QtLocation, QtBluetooth, QtSensors, etc. 


Thank you for reading this tutorial😀. Have fun trying out PySide6 Android deployment. Feel free to drop us a message or open a suggestion/bug in JIRA. Your feedback fuels us in making Qt for Python better. Also, feel open to connecting to the Qt for Python community through our community platforms. 

Stay tuned for further updates on Android deployment 👍. 


Blog Topics:

Comments

Commenting for this post has ended.

S
Shyamnath Premnadh
1 point
24 months ago

Just a quick mention that the source repo link in Step 2 is wrong. The correct link is https://code.qt.io/cgit/pyside/pyside-setup.git/tree/

Nevetheless, this is not required since you will anyway clone the repo in the next step.

K
Kelteseth
0 points
24 months ago

Nice! Are there any plans for iOS support now that apple is forced to allow sideloading?

S
Shyamnath Premnadh
0 points
24 months ago

Well, as of now the immediate plan is to make the Android Deployment tool more easier to use and more mature. Presently we have nothing planned for iOS but you never know, if the Android deployment tool gets enough traction we might make a new tool for iOS.

Marcos Ramírez
0 points
23 months ago

(shiboken) [158ms] Generating class model (0)... OK [158ms] Generating enum model (0)... OK [158ms] Generating namespace model (0)... OK [158ms] Resolving typedefs (0)... OK [158ms] Fixing class inheritance... OK [158ms] Detecting inconsistencies in class model... OK [158ms] Detecting inconsistencies in typesystem (61)... OK [158ms] Checking inconsistencies in function modifications... OK [158ms] Writing log files... [OK] qt.shiboken: (shiboken) No C++ classes found! (shiboken) [158ms] Running Source generator... WARNING [159ms] Running Header generator... [OK] Done, (shiboken) 159ms, 1 warnings [89/90] Building CXX object shibokenmodule/CMakeFiles/shibokenmodule.dir/Shiboken/shibokenmodulewrapper.cpp.o FAILED: shibokenmodule/CMakeFiles/shibokenmodule.dir/Shiboken/shibokenmodulewrapper.cpp.o /usr/bin/c++ -DNDEBUG -DPyLIMITEDAPI=0x03060000 -Dshibokenmodule_EXPORTS -I/home/user/pyside-setup/sources/shiboken6/shibokenmodule -I/home/user/pyside-setup/sources/shiboken6 -I/home/user/pyside-setup/sources/shib oken6/libshiboken -I/home/user/pyside-setup/build/qfpa-py3.10-qt6.5.1-64bit-release/build/shiboken6/libshiboken -I/home/user/miniconda3/envs/pyside-setup/include/python3.10 -Wall -Wextra -Wno-strict-aliasing -Wno-cast-fu

I got up to this point and get this error. What is happening?

Had two days trying to make this works with no successful results.

barigou simou
0 points
22 months ago

dear mr Shyamnath Premnadh thank you very much for Taking Qt for Python to Android is it possible to create a youtube video demonstrating in details the Steps to deploy your PySide application to Android please run the app in an emulator as a prof of work thanks in advance

garawaa
0 points
21 months ago

When can we deploy to android in windows?

David García
0 points
18 months ago

Some problems i ran into on step 2. First there is a missing dependency on 'packaging' Then I get to an error:

  • ./configure --host=aarch64-linux-android --target=aarch64-linux-android --build=x8664-pc-linux-gnu --enable-shared --enable-ipv6 accv_filedevptmx=yes accv_filedevptc=no --without-ensurepip accvlittleendiandouble=yes checking for git... found checking build system type... x8664-pc-linux-gnu checking host system type... aarch64-unknown-linux-android configure: error: Cross compiling requires --with-build-python

Some differences on my setup: trying to use Ubuntu 23.04 off-the-shell, so using python 3.11 and ubuntu android packages: google-android-platform-tools-installer google-android-ndk-r25c-installer ANDROIDSDKROOT=/usr/lib/android-sdk ANDROIDNDKROOT=/usr/lib/android-sdk/ndk/25.2.9519653/

every skills
0 points
18 months ago

Performing C SOURCE FILE Test CMAKEHAVELIBCPTHREAD failed with the following output: Change Dir: /home/User/Workspace/Apps/crosscompileandroid/pyside-setup/build/qfpa-py3.10-qt6.5.0-androidarmv7-a-release/build/shiboken6/CMakeFiles/CMakeTmp

Run Build Command(s):/usr/bin/ninja cmTCda414 && [1/2] Building C object CMakeFiles/cmTCda414.dir/src.c.o /home/User/Workspace/Apps/crosscompileandroid/pyside-setup/build/qfpa-py3.10-qt6.5.0-androidarmv7-a-release/build/shiboken6/CMakeFiles/CMakeTmp/src.c:13:3: warning: implicit declaration of function 'pthreadcancel' is invalid in C99 [-Wimplicit-function-declaration] pthreadcancel(thread); ^ 1 warning generated. [2/2] Linking C executable cmTCda414 FAILED: cmTCda414 : && /home/User/Working/Android/Sdk/ndk/25.2.9519653/toolchains/llvm/prebuilt/linux-x8664/bin/clang --target=armv7-none-linux-androideabi31 --target=armv7a-linux-androideabi31 -fomit-frame-pointer -march=armv7 -msse4.2 -mpopcnt -pthread -m32 -fPIC -I/home/User/Workspace/Apps/crosscompileandroid/pyside-setup/tools/crosscompileandroid/Python-armv7a-linux-android/install/include/python3.10 -Wno-unused-command-line-argument -O2 -g -DNDEBUG -Wl,-O1 -Wl,--hash-style=gnu -Wl,--as-needed -L/home/User/Working/Android/Qt/6.5.0/androidarmv7/lib -L/home/User/Working/Android/Qt/6.5.0/androidarmv7/plugins/platforms -L/home/User/Workspace/Apps/crosscompileandroid/pyside-setup/tools/crosscompileandroid/Python-armv7a-linux-android/install/lib -lpython3.10 CMakeFiles/cmTCda414.dir/src.c.o -o cmTCda414 -latomic -lm && : ld: error: undefined symbol: pthreadcancel >>> referenced by src.c:13 >>> CMakeFiles/cmTCda414.dir/src.c.o:(main) clang-14: error: linker command failed with exit code 1 (use -v to see invocation) ninja: build stopped: subcommand failed.

Source file was:

include

static void* test_func(void* data) { return data; }

int main(void) { pthreadt thread; pthreadcreate(&thread, NULL, testfunc, NULL); pthreaddetach(thread); pthreadcancel(thread); pthreadjoin(thread, NULL); pthreadatfork(NULL, NULL, NULL); pthreadexit(NULL);

return 0; }

Dietmar Schwertberger
0 points
17 months ago

This is not the first Android packaging solution for Python and Qt. These do not help much during development and bug fixing and therefore this will not result in masses of Python Qt programs for Android. Instead of yet another packaging solution, I would find it more useful to have a proper runtime for Android. I.e. an interpreter for interactive use and to run Python command line and GUI programs and also for installation of extension modules. This would allow to develop and test on the device and especially also allow (remote) debugging using the usual IDEs on the PC.

Currently the only viable option on Android seems to be PyDroid, but that's an IDE instead of a runtime environment. (E.g. you have to load and run a program and you can't run two programs at the same time.)

As of now, the only mobile platforms that allow desktop-like Python GUI software development seem to be Maemo and Sailfish OS. On Sailfish OS I'm still running my Python GUI programs that I once developed on my N900. With Android, I would not have started at all.

Алексей Иванов
0 points
17 months ago

RuntimeError: You are including a lot of QML files from a local virtual env. This can lead to errors in deployment.

--extra-ignore-dirs=venv has no effect.

Premanand Patro
0 points
14 months ago

i'm getting this error as CMake Error at cmake/ShibokenHelpers.cmake:194 (message): Call Stack (most recent call first): /usr/lib/llvm-14/lib/cmake/clang/ClangTargets.cmake:750 (message) /usr/lib/cmake/clang-14/ClangConfig.cmake:19 (include) cmake/ShibokenHelpers.cmake:170 (findpackage) cmake/ShibokenSetup.cmake:37 (setup_clang) CMakeLists.txt:13 (include)