PEP 738 – 将 Android 添加为支持的平台
- 作者:
- Malcolm Smith <smith at chaquo.com>
- 赞助商:
- Petr Viktorin <encukou at gmail.com>
- 讨论列表:
- Discourse 帖子
- 状态:
- 已接受
- 类型:
- 标准跟踪
- 创建日期:
- 2023年12月12日
- Python 版本:
- 3.13
- 决议:
- Discourse 消息
摘要
本 PEP 提案在 CPython 中添加 Android 作为支持的平台。初始目标是在 Python 3.13 中为 Android 实现 3 级支持。
本 PEP 基于 PEP 730 – “将 iOS 添加为支持的平台”,作者为 Russell Keith-Magee,涵盖了许多相同的问题。可以通过搜索“iOS”一词来查找这两个平台之间的显著差异。
动机
在过去的 15 年里,移动平台已成为计算领域中越来越重要的组成部分。Android 是运行在约 70% 的这些设备 上的操作系统。但是,CPython 中没有对 Android 的官方支持。
Chaquopy、BeeWare 和 Kivy 项目多年来一直支持 Android,并且它们都被用来生成已获准在 Google Play 商店发布的应用程序。这证明了 Android 支持的技术可行性。
对于 Python 作为一门语言的未来,它能够在任何得到广泛采用的平台上使用非常重要。否则,潜在用户将选择确实提供对这些平台支持的其他语言。这在教育领域尤其如此,下一代开发人员在很多情况下已经花费更多时间使用移动平台而不是桌面平台。
基本原理
常规
Android 从广义上来说是一个 POSIX 平台,基于 Linux 内核和 ELF 二进制格式。它不使用 glibc,而是提供了自己的 C 库实现,称为 Bionic。因此,它通常与任何其他 Linux 发行版不兼容,即使架构匹配也是如此。它还有自己的文件系统布局,与其他任何 Unix 不相似。
但是,Android 与 Linux 的源代码兼容性非常好。在其早期,C 库非常不完整,但到 2014 年左右,大多数差距都得到了填补。从那时起,任何为 Linux 编译的 C 代码通常都可以编译为 Android,除非它涉及对硬件设备或操作系统服务的直接访问。
CPython 也是如此。尽管它从未正式支持 Android,但最近的版本(从 3.6 开始)已经可以通过最少的补丁编译到 Android 上。
操作系统版本
每个 Android 版本都可以通过三种方式识别
- 传统的点分版本号(尽管最近的版本都使用了整数)
- 一个连续的整数“API 级别”(在开发者文档中最常见的形式)
- 一个字母的糖果主题代号(不再用于营销,但仍出现在开发者文档中)
将其中一个与另一个链接起来没有一致的模式;它们必须在 表格 中查找。
每年都会发布一个新的主要 Android 版本,但每个设备可用的更新完全由其制造商控制。不幸的是,许多制造商在用户准备好处理设备之前很久就停止向设备发送更新。例如,截至 2023 年 10 月,仍在接收安全更新的最旧 Android 版本是 API 级别 30,但根据 Google 自身统计数据,只有 60% 的设备处于该版本或更新版本。
因此,对于 Python 3.13,我们建议最低 Android 版本为 5.0(API 级别 21),该版本于 2014 年发布。根据上述统计数据,这将覆盖 99% 的活动设备。
开发工具
Android 开发工具在 Linux(x86_64)、Windows(x86_64)和 macOS(x86_64 和 ARM64)上得到同等支持。对于 CPython,最重要的工具是
- NDK(原生开发工具包)包含 C 和 C++ 编译器(clang)、链接器(lld)以及所有系统库的头文件。
使用不同版本的 NDK 编译的库之间的二进制兼容性通常非常好,但为了可重复性,最好每个 Python 版本在其整个生命周期中都坚持使用一个 NDK 版本。对于 Python 3.13,这将是当前的 NDK 长期支持版本 r26。
每个 NDK 版本都可以设置为针对各种 Android 版本。例如,NDK r26 支持 API 级别 21 到 34。但是,为旧版 Android 版本编译的二进制文件通常会在较新版本上无限期地工作;仅出于安全原因才会对此规则进行例外。
- Gradle 是用于构建完整、可部署应用程序的工具。
- 模拟器基于 QEMU,是运行在开发机器上的模拟 Android 设备。与 iOS 不同,模拟器使用与相同架构的真实设备相同的 ABI,并且可以运行相同的二进制文件。
这些工具都可以从命令行使用,也可以通过基于 IntelliJ IDEA 的 Android Studio IDE 使用。
架构
Android 目前支持 4 种架构。Android 工具使用的名称为
armeabi-v7a
arm64-v8a
x86
x86_64
几乎所有当前的物理设备都使用 ARM 架构之一。x86
和 x86_64
支持在模拟器中使用。
对于 Python 3.13,我们建议 3 级支持仅涵盖 64 位平台(arm64-v8a
和 x86_64
)
x86
自 2020 年以来一直未作为开发平台支持,并且从那时起就没有发布新的模拟器镜像。armeabi-v7a
的活动设备比例现在 低于 10% 并且稳步下降。使用可靠的构建机器人覆盖它也会更加困难,因为模拟器没有可用的原生主机(ARM64 Mac 没有对 ARM32 代码的硬件支持)。尽管跨架构模拟是可能的,但它的性能和稳定性要差得多,这就是为什么
armeabi-v7a
模拟器镜像自 2016 年以来没有更新的原因。但是,它仍然用于手表和超低成本手机。如果这种情况持续存在,我们可能需要考虑在未来的 Python 版本中添加它。
即使 32 位架构未得到官方支持,也不应进行任何会妨碍仍然希望构建它们的任何下游项目的更改。
应用生命周期
Android 应用程序中的主要编程语言是 Java 或其现代后继者 Kotlin。因此,应用程序不提供自己的可执行文件。相反,所有应用程序都从运行操作系统提供的可执行文件的 Java 虚拟机开始。然后,应用程序的 Java 代码可以通过加载动态库并通过 JNI 调用它们来向进程添加本机代码。
与 iOS 不同,Android 支持创建子进程。但是,应用程序只能在 某些位置 运行可执行文件,这些位置在运行时都不能写入。长期运行的子进程 正式不鼓励,并且不保证在未来的 Android 版本中得到支持。
Android 确实提供了一个命令行 shell,但它仅供开发人员使用,普通最终用户无法使用。
由于这些原因,在 Android 上运行 Python 的推荐方法是将 libpython3.x.so
加载到主应用程序进程中。python3.x
可执行文件将不会在此平台上获得官方支持。
规范
工作范围
这项工作的重点是生成与现有 Windows 可嵌入包 等效的 Android 版本,即一组编译后的库,开发人员可以将其添加到他们的应用程序中。不需要安装程序。
将 Android 添加为 3 级平台只需要支持从未经修补的 CPython 源代码编译兼容 Android 的构建。它不一定需要在 python.org 上有任何官方分发的 Android 工件,尽管这些可以在将来添加。
Android 将使用与其他 POSIX 平台相同的配置和 Makefile 系统进行构建,因此必须在 POSIX 平台上构建。Linux 和 macOS 都将得到支持。
将提供一个 Gradle 项目用于运行 CPython 测试套件。将提供工具来自动执行构建测试套件应用程序、启动模拟器、安装测试套件和执行测试套件的过程。
链接
由于 应用程序生命周期 中讨论的原因,Python 将作为可以加载到应用程序中的动态 libpython3.x.so
库包含在应用程序中,使用 dlopen
。
与 Linux 不同,Android 不会隐式地使用打开的库来解析随后加载的库中的重定位, 即使使用 RTLD_GLOBAL 也是如此。因此,所有 Python 扩展模块在为 Android 构建时都必须显式链接到 libpython3.x.so
。
链接到 libpython3.x.so
的扩展模块不能由已静态链接到 libpython3.x.a
的可执行文件加载。因此,静态 libpython3.x.a
库在 Android 上不受支持。这与 CPython 在 Windows 上使用的模式相同。
此方法还允许使用 -Wl,--no-undefined
选项在构建时检测缺少的符号,这可以节省大量时间。
与 iOS 不同,Android 允许从任何位置加载动态库,因此包含共同位置的 .py、.pyc 和 .so 文件的目录树可以由 Python 的标准导入器处理。
标准库
不支持的模块
一些标准库模块在 Android 上不受支持,因为底层 C API 不可用
curses
和readline
dbm.gnu
和dbm.ndbm
grp
multiprocessing
– 尽管通常允许使用子进程(请参阅 应用程序生命周期),但 Android 不支持 System V IPC API 的任何部分。tkinter
和turtle
– 这些需要 Tk 本身的 Android 版本,而这并非官方支持。
sys
sys.platform
将返回 "android"
。尽管 Android 基于 Linux,但它在许多重要方面有所不同,因此有必要使用一个单独的名称。
当嵌入到 Android 应用中时,C 级的 stdio 流未连接到任何内容。因此,在此模式下,sys.stdout
和 sys.stderr
将重定向到系统 Logcat,可以使用 Android 开发工具查看。 sys.stdin
将始终返回 EOF。
platform
platform
模块返回的大多数值都将与 os.uname()
返回的值匹配,但以下情况除外:
platform.system()
-"Android"
,而不是默认的"Linux"
platform.release()
- Android 版本号,以字符串形式表示(例如"14"
),而不是 Linux 内核版本
此外,将添加一个 platform.android_ver()
方法,它返回一个命名元组,其中包含以下内容:
release
- 设备的 Android 版本,以字符串形式表示(例如"14"
)api_level
- 设备的 API 级别,以整数形式表示(例如34
)min_api_level
- 此 Python 版本构建可以运行的最低 API 级别,以整数形式表示(例如23
)。这与sys.getandroidapilevel
相同。manufacturer
- 设备的 制造商,以字符串形式表示(例如"Google"
)model
- 设备的 型号名称,以字符串形式表示(例如"Pixel 7"
)device
- 设备的 设备名称,以字符串形式表示(例如"panther"
)
model
和 device
中哪个更可能唯一,哪个更可能类似于市场名称,这在不同的制造商之间有所不同。
os
os.uname()
将返回 POSIX uname()
调用的原始结果。这将导致以下值:
sysname
-"Linux"
release
- Linux 内核版本(例如"5.10.157-android13-4-00003-gdfb1120f912b-ab10994928"
)
这种方法将 os
模块视为系统 API 的“原始”接口,并将 platform
视为提供更普遍有用值的更高级别的 API。
CI 资源
由于 Android 模拟器和物理设备使用相同的 ABI,并且带有相同或非常相似的操作系统二进制文件,因此在模拟器上进行测试就足够了。x86_64 模拟器可以在 Linux、macOS 或 Windows 上运行,但 ARM64 模拟器仅在 ARM64 Mac 上受支持。
Anaconda 已提供 提供物理硬件来运行 Android 构建机器人。这些将包括 Linux x86_64 和 macOS ARM64 机器,这将涵盖两种受支持的运行时架构和两种受支持的构建平台。
CPython 目前没有在 GitHub Actions 上测试 3 级平台,但如果这种情况发生变化,它们的 Linux 和 macOS 运行器也能够托管 Android 模拟器。macOS ARM64 运行器已 自 2024 年 1 月起 对所有公共存储库免费开放。
打包
Android 轮子将使用格式为 android_<api-level>_<abi>
的标签。例如:
android_21_arm64_v8a
android_21_x86_64
有关 <api-level>
的含义,请参见 操作系统版本。在轮子标签的上下文中,它表示编译轮子时选择的最低 Android 版本。pip 等安装工具应以类似于现有 macOS 标签的方式解释此内容,即,最小 API 级别为 N 的应用可以包含标记为 API 级别 N 或更旧的轮子。
此格式源自 Chaquopy 项目,该项目目前维护着一个 轮子存储库,其标签在 API 级别 16 和 21 之间变化。
但是,依靠一小部分 Android 爱好者来构建整个 Python 生态系统不是一个可扩展的解决方案。在知名库例行发布自己的 Android 轮子之前,社区在 Android 上采用 Python 的能力将受到限制。
因此,有必要清楚地记录项目如何将其 CI 和发布工具中添加 Android 构建。将 Android 支持添加到 crossenv 和 cibuildwheel 等工具可能是实现此目标的一种方式。
Android 轮子标签格式也应添加到 PyPI 接受的标签列表中。
PEP 11 更新
PEP 11 将更新为包含两个受支持的 Android ABI。Autoconf 已经使用以下三元组识别它们:
aarch64-linux-android
x86_64-linux-android
Petr Viktorin 将担任这些 ABI 的初始核心团队联系人。
向后兼容性
添加新平台不会对 CPython 本身引入任何向后兼容性问题。但是,如果任何 CPython 修补程序的最终形式与他们历来使用的修补程序不一致,则可能会对历来提供 CPython 支持的项目(即 BeeWare 和 Kivy)产生一些向后兼容性影响。
安全影响
添加新平台不会增加任何新的安全隐患。
如何教授
与本 PEP 相关的教育需求涉及两组开发人员。
首先,应用开发人员需要了解如何将 Python 构建到 Android 应用中,以及他们自己的 Python 代码和任何支持包,以及如何在运行时使用它们。文档将以类似于现有 Windows 可嵌入包 的形式介绍这一点。但是,它将建议大多数开发人员使用更高级别的工具,例如 Briefcase、Chaquopy 和 Buildozer,所有这些工具都已经有全面的文档。
其次,具有二进制组件的包的开发人员需要了解如何为 Android 构建和发布它们(请参见 打包)。
参考实现
Chaquopy 存储库 包含参考补丁和构建脚本。在将它们上游之前,必须将它们与 Chaquopy 的其他组件分离。
Briefcase 提供了在 Android 设备和模拟器上执行测试套件的代码的参考实现。 Toga 测试平台 是一个使用 GitHub Actions 在 Android 模拟器上执行的测试套件的示例。
版权
本文档置于公共领域或根据 CC0-1.0-Universal 许可证,以更宽松者为准。
来源:https://github.com/python/peps/blob/main/peps/pep-0738.rst