A tool to create cross-platform apps using only Python and the Qt Framework.
PyQt-CroM demonstrates the capabilities of pyqtdeploy and optimises its use.
PyQt-CroM is mainly aimed at the following groups.
There are various reasons to create yet another cross-platform app generation tool (especially based on Python and the Qt framework):
-
Javascript is the current leading language for cross-platform app development frameworks (e.g. React Native, Nodejs, Ionic). However,
Javascript is harder to pick up and learn for beginners than Python
. Furthermore, Python comes with built-in modules and an extensive list of libraries, whereas Javascript only comes with a few powerful libraries, which makesJavascript still less handy and less flexible for intermediate and expert developers
. -
Flutter is gaining traction in the cross-platform ecosystem, as it is fast, flexible and allows native feature access. Its base language is Dart language, which is easy to learn, fast, performant and documented, but
Dart suffers from a lack of online resources and community support
(as it is fairly recent). On the contrary, Python benefits from countless useful online resources, as well as a large and active community. -
No-code or low-code platforms (e.g. Bubble) are a great option for beginners as they help them prototype quickly, but
no-code platforms are very limited in functionalities sought after by intermediate and expert developers
. Some platforms (e.g. FlutterFlow) enable the use of code to extend existing capabilities, but this increases the the level of access requirements for beginners. Python is a great competitor to low-code platforms as it is accessible to beginners, and is also a great competitor to more advanced platforms, as it boasts a large range of libraries, making it easy to customise features and create advanced functionalities. -
Kivy and BeeWare are the most famous cross-platform app development frameworks based on Python. Even though Kivy is more focused on non-native user interface and BeeWare is more focused on native feel,
Kivy and BeeWare can't provide native and non-native feel in one framework simultaneously. Furthermore, they both lack community support and good documentation
. On the contrary, PyQt relies relies on the Qt framework which is the leader in GUI apps (thanks to an active community) and allows to develop apps with a native feel (QtWidgets) or a more custom and standardised look (QtQuick) according to Qt framework comparison. -
Tkinter relies on Python and the code is stable, however
the user interface in Tkinter is not appealing and the code is hard to debug
. On the contrary, PyQt makes Qt components directly accessible from the Python language, which makes it easy to organise, customise and debug code (thanks to recognised Qt expertise). -
PySide is developed by Qt, but surprisingly requires a lot of setup and various tools to convert from a script to a mobile app for instance, as expressed by Qt itself on Qt website. Even though pyqtdeploy also requires a lot of setup to convert a PyQt script into a cross-platform app, the process is robust and reliable.
✔️ The tool pyqtdeploy is still not perfect, but the limitations are non-critical for the target audience:
- Qt documentation is great for C++, but less for Python
- Pyqtdeploy documentation is almost non-existent
- The size of generated apps is usually bigger than expected, because they need to include a Python interpreter if not available on the OS (e.g. Android apps).
The aforementioned limitations constitute obstacles that can be tackled by PyQt-CroM.
- Overview
- 1. Getting started
- 2. Generating your own app
- 3. Enhancing your app
- 4. Releasing your app
- 5. Troubleshooting
- 6. Roadmap
- 7. Credits
- 8. Support
🔍 This tutorial guides you through the process of generating a cross-platform app from a simple PyQt5 demo app.
🏆 By the end of the tutorial, you will be able to launch the simple PyQt5 demo app from your Android phone:
pyqt5_demo_app_android.mp4
Specs of Linux machine used:
Ubuntu 22.04
(EOL April 2032) with around 40-50GB available (to install the dependencies)Python 3.10.12
(EOL October 2026) pre-installed on Ubuntu 22
💡 Refer to Virtual Machine Setup if you don't have a Linux OS available on your machine.
Specs of target OS:
Android 9.0
as targeted Android features (default)Android 9.0
as minimum Android version to run the app (default)
Use the HTTPS method if you don't have a Github account:
cd $HOME/Documents \
&& git clone https://github.com/achille-martin/pyqt-crom.git
Use the SSH method if you have a Github account (and SSH key setup):
cd $HOME/Documents \
&& git clone [email protected]:achille-martin/pyqt-crom
PYQT_CROM_DIR
as the variable containing the path to the main repo.
Add the variable to your .bashrc
with:
printf "%s\n" \
"" \
"# Environment variable for PyQt-CroM path" \
"export PYQT_CROM_DIR=$HOME/Documents/pyqt-crom" \
"" \
>> $HOME/.bashrc \
&& source $HOME/.bashrc
sudo apt-get update \
&& sudo apt-get install python3-pip \
&& python3 -m pip install --upgrade pip \
&& sudo apt-get install python3-virtualenv \
&& cd $PYQT_CROM_DIR \
&& mkdir -p venv \
&& cd venv \
&& virtualenv pyqt-crom-venv -p python3 \
&& cd ..
source $PYQT_CROM_DIR/venv/pyqt-crom-venv/bin/activate
💡 To exit the virtual environment, type in your terminal deactivate
.
Make sure that pip3 (pip for python3) has been upgraded to v23.3.2 (or later) in the virtual environment with:
pip3 --version
If pip3 needs to be upgraded, run the command:
pip3 install --upgrade pip
Install the pip packages in the virtual environment with:
cd $PYQT_CROM_DIR \
&& pip3 cache purge \
&& pip3 install -r requirements.txt
💡 You can confirm the installed pip packages with pip3 list --local
.
cd $PYQT_CROM_DIR/examples/demo/demo_project/demo_pkg \
&& python3 demo_app.py
The PyQt5 demo app will start and you can confirm that it is displayed properly on your machine:
- Click the button
- An alert message is displayed stating that you have clicked the button
pyqt5_demo_app_linux.mp4
Download the sources with:
cd $PYQT_CROM_DIR/utils/resources \
&& chmod +x download_sources.sh \
&& ./download_sources.sh
💡 You can confirm that the list of packages required matches with the versions from $PYQT_CROM_DIR/examples/demo/demo_project/sysroot.toml
.
Install zlib on Ubuntu with:
sudo apt install zlib1g-dev
Zlib is required by the pyqtdeploy project $PYQT_CROM_DIR/examples/demo/demo_project/config.pdt
to correctly identify the dependencies from the $PYQT_CROM_DIR/examples/demo/demo_project/sysroot.toml
.
💡 Sysroot setup tips can be obtained from Riverbank website.
Install stable java JDK 11 available for your Ubuntu distribution and tested with Gradle:
sudo apt install openjdk-11-jdk openjdk-11-jre
Set the default java and javac version to 11 using:
sudo update-alternatives --config java \
&& sudo update-alternatives --config javac
✋ Confirm the version with java -version && javac -version
which should be v11.0.21
.
Download Android Studio version 2023.1.1.26
with:
sudo apt-get install wget \
&& cd $HOME/Downloads \
&& wget https://redirector.gvt1.com/edgedl/android/studio/ide-zips/2023.1.1.26/android-studio-2023.1.1.26-linux.tar.gz
Move the contents of the downloaded tar.gz
to your $HOME
directory using:
cd $HOME/Downloads \
&& tar -xvf android-studio-2023.1.1.26-linux.tar.gz \
&& mv android-studio $HOME
Start the installation with:
cd $HOME/android-studio/bin \
&& ./studio.sh
💡 Tip: if there is an issue with android studio start, use sudo ./studio.sh
.
The Android Studio installer will start:
- Do not import settings
- Select custom installation if possible
- Pick the default Android SDK
- Deselect Virtual Device if you don't need it for testing
- Keep a note of the Sdk installation path, which should be
$HOME/Android/Sdk
- Start the download (unless you want to install extra features)
- Close Android Studio
✋ Make sure that the default SDK has been installed in $HOME/Android/Sdk
and that $HOME/Android/Sdk/platforms
contains android-28
folder only.
The reason why android-28 (corresponding to Android v9.0) is selected is because there are restrictions depending on the Java version installed and the Qt version installed.
If $HOME/Android/Sdk/platforms
does not contain android-28
folder only, follow the instructions at the next step to set things up correctly.
- Restart Android Studio with
cd $HOME/android-studio/bin && ./studio.sh
(skip / cancel if no SDK found) - On the menu screen, click on
more actions
and thenSDK manager
- Make sure that you are in the Settings -> Languages & Frameworks -> Android SDK
- Make sure that in the
SDK Platforms
tab, the following is installed (Show package details and unhide obsolete packages): (Android 9.0) Android SDK Platform 28 and Sources for Android 28. - Remove any additional unneeded package from the list.
- Apply changes for
SDK Platforms
tab. - Make sure that in the
SDK Tools
tab, the following is installed (Show package details and unhide obsolete packages): (Android SDK Build-Tools 34) v28.0.3, Android Emulator any version, Android SDK Tools (Obsolete) v26.1.1. - Remove any additional unneeded and interfering package from the list.
- Close Android Studio
- Download SDK Platform-Tools v28.0.3 to match the SDK Build-Tools version and add it to your SDK folder using:
cd $HOME/Downloads \
&& wget https://dl.google.com/android/repository/platform-tools_r28.0.3-linux.zip \
&& sudo apt-get install unzip \
&& unzip platform-tools_r28.0.3-linux.zip \
&& rm -r $HOME/Android/Sdk/platform-tools \
&& mv platform-tools $HOME/Android/Sdk
- Restart Android Studio with
cd $HOME/android-studio/bin && ./studio.sh
(skip / cancel if no SDK found) - On the menu screen, click on
more actions
and thenSDK manager
- Make sure that you are in the Settings -> Languages & Frameworks -> Android SDK
- Make sure that in the
SDK Tools
tab, the following is installed: NDK Side-By-Side v21.4.7075529 (equivalent to r21e). According to the Qt Website, this is the one recommended for Qt5.15.2.
- Close Android Studio
✋ Make sure that $HOME/Android/Sdk/ndk/21.4.7075529/platforms
contains the folder android-28
.
💡 The NDK corresponds to the minimum version required to run the app. Technically, you could choose a lower version than Android API 9.0 (android-28).
Download the Qt version which matches the one in $PYQT_CROM_DIR/examples/demo/demo_project/sysroot.toml
from the open source online installer:
sudo apt-get install libxcb-xfixes0-dev libxcb-xinerama0 \
&& cd $HOME/Downloads \
&& wget https://d13lb3tujbc8s0.cloudfront.net/onlineinstallers/qt-unified-linux-x64-4.6.1-online.run \
&& chmod +x qt*.run \
&& ./qt-unified-linux-x64-4.6.1-online.run
A Qt window will appear on which you can sign up:
- Verify your email and register as an individual (no need for location)
- Restart the Qt installer with:
cd $HOME/Downloads && ./qt-unified-linux-x64-4.6.1-online.run
- Log in, state that you are an individual and not a company
- If possible, select "Custom installation" and make sure to only setup
Qt5.15.2
(and other packages you might want) - Setup will start
- Select folder location
$HOME/Qt5.15.2
- Installation will start
✋ Make sure that you can access $HOME/Qt5.15.2/5.15.2
and that the folder android
is located inside of it.
💡 The package libxcb-xinerama0
is installed to prevent an issue inherent to Qt5.15 (but solved in Qt6) with xcb
Qt platform plugin, according to QT DEBUG reports.
Load the environment variables on terminal startup with:
printf "%s\n" \
"" \
"# Load extra environment variables for PyQt-CroM" \
"source $PYQT_CROM_DIR/utils/resources/path_setup.sh" \
"" \
>> $HOME/.bashrc \
&& source $HOME/.bashrc
Start the building process of the .apk with:
cd $PYQT_CROM_DIR/utils \
&& python3 build_app.py --pdt $PYQT_CROM_DIR/examples/demo/demo_project/config.pdt --jobs 1 --target android-64 --qmake $QT_DIR/android/bin/qmake --verbose
⏳ Let the app build (it may take a while). The app is built when you see "BUILD SUCCESSFUL".
💡 The Android Manifest, build.gradle
and gradle.properties
can be checked at debug stage in $PYQT_CROM_DIR/examples/demo/demo_project/build-android-64/android-build
.
The generated DemoCrossPlatformApp.apk
can be found in $PYQT_CROM_DIR/examples/demo/demo_project/releases/<build_date>
.
You can then either:
- Copy, install and run the .apk onto your phone (>=Android v9.0)
- Install BlueStacks on Windows, enable hyper-V, open
my games
and install the .apk, run the app offline - Setup a virtual device in Android Studio, install the app and run it on the virtual device
🏆 Congratulations! You have completed the tutorial. You can view the demo app running on an Android phone.
🔍 This section describes the steps to generate an Android
app (.apk) from a custom PyQt5
app.
💡 Make sure to go through the Getting Started tutorial to correctly setup your machine and environment.
<>
. For instance, <pkg_name>
can be demo_pkg
or test_pkg
.
Start by creating a project folder:
- Create a folder
<project_name>
wherever you want (and remember the absolute path of its parent folder referred to as<absolute_path>
)
Inside of the project folder, create a python package to hold your PyQt5
app:
- Create a folder
<project_name>/<pkg_name>
- Populate
<project_name>/<pkg_name>
with at least__init__.py
file and a<main_file_name>.py
script (you can add more files if required by your package)
Note that the <main_file_name>.py
must contain a unique main()
function (or any similar distinctive entry point).
💡 An example of python package is given in the demo project folder.
Inside of your <project_name>
folder, add the sysroot config to specify application dependencies:
- Create a file called
sysroot.toml
and populate it with all the modules used by your app.
For instance, if you imported QtSql
in your PyQt5
app, then you must include QtSql
in [PyQt.android] installed_modules
.
💡 An example of sysroot config is given in the demo project folder.
Inside of your <project_name>
folder, add the pdt config to specify python dependencies and build requests:
- Create a file called
config.pdt
and configure it
To configure the config.pdt
file, you need to understand and use the various areas shown in the following pictures:
- Open the
config.pdt
file with:cd <absolute_path>/<project_name> && pyqtdeploy config.pdt
. - [AREA 1] In the
Application source tab > Name area
, add the<app_name>
with no spaces. This is the app name shown at export time. - [AREA 2] In the
Application source tab
, click on theScan
button to select your<project_name>/<pkg_name>
folder. - [AREA 3] In the
Application source tab > Application Package Directory area
, tick the files and folders you want to include into your application. - [AREA 4] In the
Application source tab > Entry point area
, add the<pkg_name>.<main_file_name>:main
to tell where the entry point of your application is.
- [AREA 5] In the
Packages tab > Sysroot specification file area
, click on the file icon to the right to select the desiredsysroot.toml
file. - [AREA 6] In the
Packages tab > Standard Library area
, tick all the python libraries you have imported in your python application. You can leave the coloured blocks as they import required libraries to build the python application. - [AREA 7] In the
Packages tab > Core Packages area
, tick all the external packages that you have imported in your python application. You can leave the coloured blocks as they import required libraries to build the python application. - Save the
config.pdt
withCtrl + S
and close it.
💡 An example of pdt config is given in the demo project folder.
💡 For more information about pdt files, read the Riverbank website page.
Generate the <app_name>.apk
file using:
cd $PYQT_CROM_DIR/utils \
&& python3 build_app.py --pdt <absolute_path>/<project_name>/config.pdt --jobs 1 --target android-64 --qmake $QT_DIR/android/bin/qmake --verbose
💡 The <app_name>.apk
can be found in the <absolute_path>/<project_name>/releases/<build_date>
folder.
The most nerve-wracking part of deploying an application is the debugging part.
Therefore, make sure that you have added a logger to your application and that you use an Emulator or a physical device to confirm your expectations.
To setup an Emulator, refer to Android Emulator setup.
🔍 This section offers feature examples to enhance your custom PyQt app.
To discover or analyse PyQt5 features, look at the section dedicated to PyQt5 features.
🔍 This section provides a detailed tutorial on how to release your custom app onto main app stores.
To learn more about releasing your own app on app stores, follow the online tutorial.
🔍 This section offers advice to get unstuck when creating your app.
To find out about common setup and running issues, look at the section dedicated to Common issues.
🔍 This section describes the broad roadmap to deliver a functional repo.
Repository created and maintained by Achille Martin.
👏 Gigantic thanks to Phil Thompson, the creator and maintainer of PyQt and pyqtdeploy.
💗 Sincere thanks to the well-intentioned international developers who create apps benefitting the community.
For more information about licencing details, take a look at the section dedicated to Licencing.
🌟 Do you feel that you can make progress with your own projects by converting your PyQt5 apps into cross-platform apps?
Please support PyQt-CroM by starring, advertising and sponsoring it.
👐 Do you feel stuck with your projects?
Get customised help from me on Fiverr.