LOADING
1876 字
9 分钟
在 Android 设备上部署 PySide6 程序

引言

Qt 一直把 Code less. Create more. Deploy everywhere 当做其宣传语. 笔者一直都在维护一个基于 Qt for Python 的项目, 很早之前就听说了 PySide6 项目可以部署到 Android 平台上1, 但是对系统环境要求十分苛刻, 互联网上也缺少相关文档, 就一直没有尝试此技术. 好在现在微软的 WSL 技术成熟, PySide6 也在 6.8.0 版本之后提供了预编译的轮子2, 遂开始了今天的探索.

Tip

PySide6 6.7.3 之后2, pyside6-android-deploy 可以在 macOS 上运行.3

搭建 WSL 环境

笔者使用的系统是 Windows 11, Qt for Python 的交叉编译要求的系统平台是 Linux1 或者 macOS2, 所以需要搭建 WSL 环境, 这里笔者推荐的是 Ubuntu 24.04 LTS, 理由如下:

  • PySide6-Android-Deploy 底层依赖 Buildozer, 而 Buildozer 的官方文档重点给的是 Ubuntu 平台的教程, 使用 Ubuntu 可以避免不必要的麻烦.
  • 笔者原来常用的是 WSL Arch, WSL 本来安装多个子系统又极其方便, 安装新的 Ubuntu 系统还避免了环境问题.
Important

使用 WSL 2 而非 WSL 1 以避免不必要的麻烦 务必将程序源码放置在 WSL 分区 中, 不要在 Windows 分区上进行编译 Notes for WSL users

运行以下命令以安装 Ubuntu 24.04 LTS.

Terminal window
wsl --install -d Ubuntu

运行失败可以先尝试运行以下两个命令4

Terminal window
dism.exe /online /enable-feature /featurename:Microsoft-Windows-Subsystem-Linux /all /norestart
dism.exe /online /enable-feature /featurename:VirtualMachinePlatform /all /norestart

配置基础编译环境

换源并更新软件源

将镜像源切换到国内镜像源, 这里推荐 北京外国语大学开源软件镜像站
, 请选用 DEB822 格式.

Terminal window
sudo apt update
sudo apt full-upgrade -y
sudo apt autoremove -y

安装系统依赖5 6

笔者这里使用了 Buildozer 的官方文档5 中推荐的 OpenJDK 17

Terminal window
sudo apt install -y \
git zip unzip openjdk-17-jdk python3-pip python3-virtualenv \
autoconf automake libtool pkg-config zlib1g-dev \
libncurses5-dev libncursesw5-dev libtinfo6 \
cmake libffi-dev libssl-dev autopoint gettext

安装 Python 环境

笔者自己项目推荐的 Python 版本是 3.11, Qt 官方预编译的 PySide6 for Android 也仅支持 cp3.11Ubuntu 24.04 LTS 官方仓库默认没有 3.11, 遂使用 pyenv 安装 Python.

Terminal window
curl -fsSL https://pyenv.run | bash
cat >> ~/.bashrc <<'EOF'
export PYENV_ROOT="$HOME/.pyenv"
[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"
eval "$(pyenv init - bash)"
EOF
source ~/.bashrc
Terminal window
pyenv install 3.11
pyenv global 3.11
python --version

切换系统 Java 版本

Ubuntu 24.04 LTS 似乎自带了较新版本的 JDK, 需要手动切换

Terminal window
sudo update-alternatives --config java
sudo update-alternatives --config javac

然后选带 java-17-openjdk / javac-17-openjdk 的那一项

环境自检

Terminal window
python3 --version
pip3 --version
java -version
git --version
cmake --version

新建 Python 虚拟环境

Important

建议将虚拟环境放在项目文件夹之外.3

Terminal window
mkdir ~/venv
python -m venv ~/venv
source ~/venv/bin/activate
python -m pip install -U pip setuptools wheel

配置 Python 虚拟环境5

Terminal window
source ~/venv/bin/activate
pip install buildozer setuptools cython==0.29.34

下载 Android NDK 和 SDK

下载 Android NDK 和 SDK 最简单的方法是通过 Qt for Python 仓库中的一个脚本3

Terminal window
cd ~
git clone https://code.qt.io/pyside/pyside-setup
cd pyside-setup
pip install -r tools/cross_compile_android/requirements.txt
python tools/cross_compile_android/main.py --download-only --skip-update --auto-accept-license

Android NDK 和 SDK 会被下载到 ~/.pyside6_android_deploy/

获取适用于 Android 平台的 PySide6 / Shiboken6 轮子

有三种方式可以获取适用于 Python 的 Qt Android 轮子文件3

  1. Qt for Python downloads pageQt for Python CI Snapshot
  2. qtpip download PySide6 --android --arch aarch64 (可用的架构包括 aarch64x86_64, 仅适用于 Qt Commercial 用户)
  3. 为 Android 交叉编译适用于 Python 的 Qt 轮子

笔者这里下载了 PySide6-6.10.3-6.10.3-cp311-cp311-android_aarch64.whlshiboken6-6.10.3-6.10.3-cp311-cp311-android_aarch64.whl

Terminal window
mkdir ~/android-wheels
cd ~/android-wheels
wget https://download.qt.io/official_releases/QtForPython/pyside6/PySide6-6.10.3-6.10.3-cp311-cp311-android_aarch64.whl
wget https://download.qt.io/official_releases/QtForPython/shiboken6/shiboken6-6.10.3-6.10.3-cp311-cp311-android_aarch64.whl

至此, 编译环境配置完毕~

最小 Qt for Android Bootstrap

最小启动脚本

笔者在 ~/project 目录创建了 main.py 脚本

import sys
from PySide6.QtWidgets import QApplication, QLabel
if __name__ == "__main__":
app = QApplication(sys.argv)
label = QLabel("Qt for Android bootstrap")
label.show()
sys.exit(app.exec())

初始化 PySide6-Android-Deploy Spec 文件

Terminal window
cd ~/project
source ~/venv/bin/activate
pyside6-android-deploy \
--init \
--name "FirstQtBootstrap" \
--wheel-pyside=/home/xiaoyouchr/android-wheels/PySide6-6.10.3-6.10.3-cp311-cp311-android_aarch64.whl \
--wheel-shiboken=/home/xiaoyouchr/android-wheels/shiboken6-6.10.3-6.10.3-cp311-cp311-android_aarch64.whl \
--sdk-path=/home/xiaoyouchr/.pyside6_android_deploy/android-sdk \
--ndk-path=/home/xiaoyouchr/.pyside6_android_deploy/android-ndk/android-ndk-r27c
Tip

由于不能使用 ~, 请将 /home/xiaoyouchr/ 改成你的家目录.

Important

应用名此时不应带有空格, 笔者在后文会提供 PATCH pyside6-android-deploy 脚本从而使应用名可以带有空格.

Terminal window
cd ~/project
source ~/venv/bin/activate
pyside6-android-deploy \
--config-file /home/xiaoyouchr/project/pysidedeploy.spec \
--wheel-pyside=/home/xiaoyouchr/android-wheels/PySide6-6.10.3-6.10.3-cp311-cp311-android_aarch64.whl \
--wheel-shiboken=/home/xiaoyouchr/android-wheels/shiboken6-6.10.3-6.10.3-cp311-cp311-android_aarch64.whl \
--sdk-path=/home/xiaoyouchr/.pyside6_android_deploy/android-sdk \
--ndk-path=/home/xiaoyouchr/.pyside6_android_deploy/android-ndk/android-ndk-r27c \
--keep-deployment-files \
-v
Terminal window
cd ~/project
ls

发现 APK 已经生成到项目中啦! 插入手机, 安装部署产物~

Terminal window
cd ~/project
~/.pyside6_android_deploy/android-sdk/platform-tools/adb install ./FirstQtBootstrap-0.1-arm64-v8a-debug.apk

排查问题

哈哈, 如果你是一步一步按着教程走的, 那么不出意外地应该运行闪退咯~
插入手机, 老实抓日志.

Terminal window
~/.pyside6_android_deploy/android-sdk/platform-tools/adb logcat | grep -i -E "FATAL EXCEPTION|AndroidRuntime|Qt|libc|python|shiboken|PySide|dlopen|UnsatisfiedLinkError|crash"

注意力惊人, 你在日志中敏锐的观察到:

04-14 16:38:55.135 5948 5976 E AndroidRuntime: java.lang.UnsatisfiedLinkError: dlopen failed: library "libpython3.11.so" not found: needed by /data/app/~~J1G-gyOzPqX3lOSadYNICQ==/org.firstqtbootstrap.firstqtbootstrap-d25iVR_yhfWeWlvi7dSXHg==/lib/arm64/libshiboken6.abi3.so in namespace clns-9

之后你运行了

Terminal window
unzip -l FirstQtBootstrap-0.1-arm64-v8a-debug.apk | grep -i "libpython3"

发现

-rwxr-xr-x 1 xiaoyouchr xiaoyouchr 5764168 Apr 14 16:22 libpython3.14.so

怎么回事呢, 为什么有 libpython3.14.so, 但没有 libpython3.11.so 呢?

PATCH pyside6-android-deploy 脚本

每次调用 pyside6-android-deploy 都会覆写 buildozer.spec 文件, 而修改 buildozer.spec 后直接手动调用 python -m buildozer android debug 又要自己手动处理复杂的依赖问题, 于是~
修改 ~/venv/lib/python3.11/site-packages/PySide6/scripts/deploy_lib/android/buildozer.py 的奇技淫巧的想法油然而生.

使用你常用的编辑器打开 ~/venv/lib/python3.11/site-packages/PySide6/scripts/deploy_lib/android/buildozer.py

之后找到这行

self.set_value("app", "requirements", "python3,shiboken6,PySide6")

将其改成

self.set_value("app", "requirements", "python3==3.11.15,hostpython3==3.11.15,shiboken6,PySide6")
Tip

增加上 hostpython==3.11.15 的原因是如果不加就会

[ERROR]: Build failed: python3 should have same version as hostpython3, 3.11.14 != 3.14.2

还注意到 buildozer.py 中有如下代码

# add p4a branch
# by default the master branch is used
# https://github.com/kivy/python-for-android/commit/b92522fab879dbfc0028966ca3c59ef46ab7767d
# has not been merged to master yet. So, we use the develop branch for now
# TODO: remove this once the above commit is merged to master
self.set_value("app", "p4a.branch", "develop")

显然此 Commit 已经被合并到了主分支, 为了避免不必要的风险, 建议将这行代码也注释掉.
笔者还发现了这段代码上次被维护是两年前, 最后维护者是 adrianghc, 这位大佬曾为 QtAsyncIO 的推近付出过巨大的精力. 可惜最后还是从 Qt 公司离职了. 这段代码的维护工作最终也不了了之~

重新运行部署脚本并在 Android 设备上安装

Terminal window
cd ~/project
source ~/venv/bin/activate
pyside6-android-deploy \
--init \
--name "FirstQtBootstrap" \
--wheel-pyside=/home/xiaoyouchr/android-wheels/PySide6-6.10.3-6.10.3-cp311-cp311-android_aarch64.whl \
--wheel-shiboken=/home/xiaoyouchr/android-wheels/shiboken6-6.10.3-6.10.3-cp311-cp311-android_aarch64.whl \
--sdk-path=/home/xiaoyouchr/.pyside6_android_deploy/android-sdk \
--ndk-path=/home/xiaoyouchr/.pyside6_android_deploy/android-ndk/android-ndk-r27c
pyside6-android-deploy \
--config-file /home/xiaoyouchr/project/pysidedeploy.spec \
--wheel-pyside=/home/xiaoyouchr/android-wheels/PySide6-6.10.3-6.10.3-cp311-cp311-android_aarch64.whl \
--wheel-shiboken=/home/xiaoyouchr/android-wheels/shiboken6-6.10.3-6.10.3-cp311-cp311-android_aarch64.whl \
--sdk-path=/home/xiaoyouchr/.pyside6_android_deploy/android-sdk \
--ndk-path=/home/xiaoyouchr/.pyside6_android_deploy/android-ndk/android-ndk-r27c \
--keep-deployment-files \
-v
~/.pyside6_android_deploy/android-sdk/platform-tools/adb install ./FirstQtBootstrap-0.1-arm64-v8a-debug.apk

看到以下画面, 最小 Bootstrap 运行成功了~

First_Bootstrap.jpg

迁移你的 PySide6 应用到 Android 平台

压缩包体

注意到我们的最小 Bootstrap 在安装后占用存储空间高达 381MB, 这显然是不可接受的.

Terminal window
cd ~/project
unzip -l FirstQtBootstrap-0.1-arm64-v8a-debug.apk

发现很多没有用到的依赖也被打包进去了

...
201504 1981-01-01 01:01 lib/arm64-v8a/libQt6Nfc_arm64-v8a.so
51360 1981-01-01 01:01 lib/arm64-v8a/libQt6OpenGLWidgets_arm64-v8a.so
518176 1981-01-01 01:01 lib/arm64-v8a/libQt6OpenGL_arm64-v8a.so
603040 1981-01-01 01:01 lib/arm64-v8a/libQt6PdfQuick_arm64-v8a.so
98296 1981-01-01 01:01 lib/arm64-v8a/libQt6PdfWidgets_arm64-v8a.so
4382256 1981-01-01 01:01 lib/arm64-v8a/libQt6Pdf_arm64-v8a.so
...

需要手动修改 ~/venv/lib/python3.11/site-packages/PySide6/scripts/deploy_lib/android/recipes/PySide6/__init__.tmpl.py, 让其仅复制必要的依赖即可.

使应用名支持空格

找到 buildozer.py 中的

self.set_value("app", "title", pysidedeploy_config.title)
self.set_value("app", "package.name", pysidedeploy_config.title)

title 改成你的应用名称, 比如

self.set_value("app", "title", "Ghost Downloader 3")
self.set_value("app", "package.name", pysidedeploy_config.title)

调试指南

在进行迁移工作的过程中, 闪退是常有的事情, 我们可以在启动程序前运行

Terminal window
adb logcat -c
adb logcat | rg -i "FATAL EXCEPTION|AndroidRuntime|Qt|libc|python|shiboken|PySide|dlopen|UnsatisfiedLinkError|Permission|SecurityException|EACCES|denied|storage|crash > crash.log"

打开你的 PySide6 on Android 程序, 在崩溃后立即按下 Ctrl + C 结束 adb logcat.
之后使用你常用的编辑器打开 crash.log, 搜索字符串 python :, 就能看到 Python 在 stdoutstderr 输出的日志, 之后一步一步解决即可~

导入必要依赖

你的 PySide6 肯定使用了其他的依赖, 请你使用你常用的编辑器打开 ~/venv/lib/python3.11/site-packages/PySide6/scripts/deploy_lib/android/buildozer.py
之后找到这行

self.set_value("app", "requirements", "python3==3.11.15,hostpython3==3.11.15,shiboken6,PySide6")

在里面加上你需要安装的依赖

结语

到此为止, 你已经成功地将你的 PySide6 程序部署到了 Android 设备上了.
感谢阅读~

Footnotes#

  1. Taking Qt for Python to Android 2

  2. PYSIDE6 2766 2 3

  3. pyside6-android-deploy: the Android deployment tool for Qt for Python 2 3 4

  4. Manual installation steps for older versions of WSL

  5. Buildozer documentation 2 3

  6. P4A documentation

在 Android 设备上部署 PySide6 程序
/posts/pyside6_on_android/pyside6_on_android/
作者
晓游
发布于
2026-04-18
许可协议
CC BY-NC-SA 4.0

部分信息可能已经过时