Following system colour scheme Selected dark colour scheme Selected light colour scheme

Python 개선 제안 한국어 번역

PEP 738 – Android를 지원 플랫폼으로 추가하기

Author:
Malcolm Smith <smith at chaquo.com>
Sponsor:
Petr Viktorin <encukou at gmail.com>
Discussions-To:
Discourse thread
Status:
Final
Type:
Standards Track
Created:
12-Dec-2023
Python-Version:
3.13
Resolution:
Discourse message

Table of Contents

번역·라이선스 안내

이 비공식 한국어 번역은 원문 Copyright 절의 Public Domain or CC0-1.0, whichever is more permissive 조건에 따라 제공합니다. 원저자와 공식 원문은 그대로 표시합니다. 수정되지 않은 기준 원문 · 공식 최신판

Important

This PEP is a historical document. The up-to-date, canonical documentation can now be found at Using Python on Android.

×

See PEP 1 for how to propose changes.

초록

이 PEP는 Android를 CPython의 지원 플랫폼으로 추가할 것을 제안합니다. 초기 목표는 Python 3.13에서 Android가 Tier 3 지원을 달성하는 것입니다.

이 PEP는 Russell Keith-Magee가 작성한 PEP 730 – “iOS를 지원 플랫폼으로 추가하기”를 기반으로 하며, 그와 같은 문제를 많이 다룹니다. 두 플랫폼 간의 주목할 만한 차이점은 “iOS”라는 단어를 검색하면 찾을 수 있습니다.

동기

지난 15년 동안 모바일 플랫폼은 컴퓨팅 환경에서 점점 더 중요한 부분이 되었습니다. Android는 이러한 기기의 약 70%에서 실행되는 운영 체제입니다. 그러나 CPython은 Android를 공식적으로 지원하지 않습니다.

Chaquopy, BeeWare, Kivy 프로젝트는 모두 수년간 Android를 지원해 왔으며, 모두 Google Play 스토어 게시 승인을 받은 애플리케이션을 만드는 데 사용되었습니다. 이는 Android 지원이 기술적으로 가능함을 보여 줍니다.

언어로서 Python의 미래를 위해서는 널리 보급된 모든 플랫폼에서 Python을 사용할 수 있는 것이 중요합니다. 그렇지 않으면 잠재적 사용자들은 이러한 플랫폼을 실제로 지원하는 다른 언어를 선택할 것입니다. 이는 특히 교육 분야에서 그러한데, 다음 세대 개발자들은 많은 경우 이미 데스크톱 플랫폼보다 모바일 플랫폼을 사용하는 데 더 많은 시간을 보내고 있기 때문입니다.

근거

일반 사항

Android는 대체로 Linux 커널과 ELF 바이너리 형식을 기반으로 하는 POSIX 플랫폼입니다. Android는 glibc를 사용하지 않고, 대신 Bionic이라는 자체 C 라이브러리 구현을 제공합니다. 그 결과, 아키텍처가 일치하더라도 일반적으로 다른 어떤 Linux 배포판과도 바이너리 호환되지 않습니다. 또한 다른 어떤 Unix와도 닮지 않은 자체 파일 시스템 구조를 가지고 있습니다.

하지만 Android는 Linux와의 소스 호환성이 상당히 좋습니다. 초기에는 C 라이브러리가 매우 불완전했지만, 2014년 무렵까지 빠진 부분이 대부분 채워졌습니다. 그 이후로는 하드웨어 장치나 운영 체제 서비스에 직접 접근하는 경우가 아니라면, Linux용으로 컴파일되는 C 코드는 대개 Android용으로도 컴파일할 수 있습니다.

이는 CPython에도 마찬가지입니다. CPython은 Android를 공식적으로 지원한 적이 없지만, 최근 버전(3.6 이후)은 최소한의 패치만으로 이미 Android용으로 컴파일할 수 있습니다.

OS 버전

각 Android 버전은 세 가지 방식으로 식별할 수 있습니다:

  • 점으로 구분된 일반적인 버전 번호(다만 최근 버전은 모두 정수를 사용했습니다)
  • 순차적인 정수인 “API 레벨”(개발자 문서에서 가장 흔히 쓰이는 형태입니다)
  • 과자를 주제로 한 알파벳순 코드명(더 이상 마케팅에는 사용되지 않지만, 개발자 문서에는 여전히 나타납니다)

이들을 서로 연결하는 일관된 패턴이 없으므로, 표에서 찾아보아야 합니다.

매년 새로운 Android 메이저 버전이 출시되지만, 각 기기에 제공되는 업데이트는 전적으로 해당 기기 제조사가 결정합니다. 안타깝게도 많은 제조사가 사용자가 기기를 처분할 준비가 되기 훨씬 전에 기기에 업데이트를 제공하는 것을 중단합니다. 예를 들어 2023년 10월 기준으로 여전히 보안 업데이트를 받는 가장 오래된 Android 버전은 API 레벨 30이었지만, Google 자체 통계에 따르면 해당 버전 이상을 사용하는 기기는 60%에 불과했습니다.

따라서 Python 3.13에서는 최소 Android 버전을 2014년에 출시된 5.0(API 레벨 21)으로 정할 것을 제안합니다. 위 통계에 따르면 이는 활성 기기의 99%를 포괄할 것입니다.

개발 도구

Android 개발 도구는 Linux(x86_64), Windows(x86_64), macOS(x86_64 및 ARM64)에서 똑같이 지원됩니다. CPython에 가장 중요한 도구는 다음과 같습니다:

  • NDK(native development kit)에는 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에서는 Tier 3 지원이 64비트 플랫폼(arm64-v8a와 x86_64)만 포괄하도록 할 것을 제안합니다:

  • x86은 2020년부터 개발 플랫폼으로 지원되지 않았으며, 그 이후로 새로운 에뮬레이터 이미지도 출시되지 않았습니다.
  • armeabi-v7a가 활성 기기에서 차지하는 비율은 현재 10% 미만이며 꾸준히 감소하고 있습니다.

    또한 에뮬레이터를 네이티브로 실행할 수 있는 호스트가 없기 때문에(ARM64 Mac은 ARM32 코드에 대한 하드웨어 지원이 없습니다) 신뢰할 수 있는 빌드봇으로 지원하기도 더 어려울 것입니다. 아키텍처 간 에뮬레이션이 가능하기는 하지만 성능과 안정성이 훨씬 떨어지며, 이 때문에 armeabi-v7a 에뮬레이터 이미지는 2016년 이후로 업데이트되지 않았습니다.

    하지만 이 아키텍처는 시계와 초저가 휴대폰에서 계속 사용되고 있습니다. 이런 상황이 계속된다면 향후 Python 버전에서 이를 추가하는 것을 검토해야 할 수도 있습니다.

32비트 아키텍처가 공식적으로 지원되지 않더라도, 여전히 이를 빌드하려는 다운스트림 프로젝트에 방해가 될 수 있는 변경은 하지 않아야 합니다.

앱 수명 주기

Android 앱의 주된 프로그래밍 언어는 Java이거나, Java의 현대적 후계 언어인 Kotlin입니다. 따라서 앱은 자체 실행 파일을 제공하지 않습니다. 그 대신 모든 앱은 운영 체제가 제공하는 실행 파일을 실행하는 Java 가상 머신으로 시작합니다. 그런 다음 앱의 Java 코드는 동적 라이브러리를 로드하고 JNI를 통해 이를 호출하여 프로세스에 네이티브 코드를 추가할 수 있습니다.

iOS와 달리 Android에서는 하위 프로세스 생성이 실제로 지원됩니다. 하지만 앱은 특정 위치에 있는 실행 파일만 실행할 수 있으며, 그중 어느 위치도 런타임에 쓸 수 없습니다. 오래 실행되는 하위 프로세스는 공식적으로 권장되지 않으며, 향후 Android 버전에서 지원된다는 보장도 없습니다.

Android는 명령줄 셸을 제공하기는 하지만, 이는 개발자만 사용하도록 의도된 것이며 일반 최종 사용자는 사용할 수 없습니다.

이러한 이유로 Android에서 Python을 실행하는 권장 방식은 libpython3.x.so를 메인 앱 프로세스에 로드하는 것이 될 것입니다. 이 플랫폼에서 python3.x 실행 파일은 공식적으로 지원되지 않습니다.

명세

작업 범위

이 작업의 초점은 기존 Windows 임베드 가능 패키지에 해당하는 Android용 결과물, 즉 개발자가 자신의 앱에 추가할 수 있는 컴파일된 라이브러리 모음을 만드는 것입니다. 설치 프로그램은 필요하지 않습니다.

Android를 Tier 3 플랫폼으로 추가하려면 패치되지 않은 CPython 소스 코드로부터 Android 호환 빌드를 컴파일하는 기능만 추가하면 됩니다. python.org에서 공식적으로 배포되는 Android 결과물이 반드시 있어야 하는 것은 아니지만, 향후 추가될 수는 있습니다.

Android는 다른 POSIX 플랫폼과 동일한 configure 및 Makefile 시스템을 사용하여 빌드되므로, 반드시 POSIX 플랫폼 위에서 빌드해야 합니다. Linux와 macOS가 모두 지원됩니다.

CPython 테스트 스위트를 실행하기 위한 Gradle 프로젝트가 제공됩니다. 테스트 스위트 앱 빌드, 에뮬레이터 시작, 테스트 스위트 설치 및 실행 과정을 자동화하는 도구가 제공됩니다.

링크

App lifecycle에서 설명한 이유로, Python은 dlopen을 사용하여 앱에 로드할 수 있는 동적 libpython3.x.so 라이브러리로 앱에 포함됩니다.

Linux와 달리 Android는 RTLD_GLOBAL을 사용하더라도 이후에 로드되는 라이브러리의 재배치를 해결하는 데 dlopen으로 연 라이브러리를 암묵적으로 사용하지 않습니다. 따라서 Android용으로 빌드할 때는 모든 Python 확장 모듈을 libpython3.x.so에 명시적으로 링크해야 합니다.

libpython3.x.so에 링크된 확장 모듈은 libpython3.x.a에 정적으로 링크된 실행 파일에서 로드할 수 없습니다. 따라서 정적 libpython3.x.a 라이브러리는 Android에서 지원되지 않습니다. 이는 Windows에서 CPython이 사용하는 것과 같은 방식입니다.

또한 이 방식을 사용하면 -Wl,--no-undefined 옵션으로 빌드 시점에 누락된 심볼을 감지할 수 있어, 시간을 크게 절약할 수 있습니다.

iOS와 달리 Android에서는 동적 라이브러리를 어느 위치에서든 로드할 수 있으므로, .py, .pyc, .so 파일이 함께 있는 디렉터리 트리를 Python의 표준 임포터로 처리할 수 있습니다.

표준 라이브러리

지원되지 않는 모듈

기반이 되는 C API를 사용할 수 없으므로, 여러 표준 라이브러리 모듈이 Android에서 지원되지 않습니다:

  • curses 및 readline
  • dbm.gnu 및 dbm.ndbm
  • grp
  • multiprocessing – 서브프로세스 자체는 일반적으로 허용되지만(App lifecycle 참조), 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() - 기본값인 "Linux" 대신 "Android"
  • platform.release() - Linux 커널 버전 대신 문자열 형태의 Android 버전 번호(예: "14")

또한 platform.android_ver() 메서드가 추가되며, 이 메서드는 다음 항목을 담은 namedtuple을 반환합니다:

  • release - 문자열 형태의 기기 Android 버전(예: "14")
  • api_level - 정수 형태의 기기 API 레벨(예: 34)
  • manufacturer - 문자열 형태의 기기 제조사(예: "Google")
  • model - 문자열 형태의 기기 모델명(예: "Pixel 7")
  • device - 문자열 형태의 기기 기기명(예: "panther")
  • is_emulator - 기기가 에뮬레이터이면 True이고, 실제 기기이면 False입니다.

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에서 Tier 3 플랫폼을 테스트하지 않지만, 향후 이 상황이 바뀐다면 GitHub Actions의 Linux 및 macOS 러너에서도 Android 에뮬레이터를 호스팅할 수 있습니다. macOS ARM64 러너는 2024년 1월부터 모든 공개 저장소에 무료로 제공되고 있습니다.

패키징

Android 휠은 android_<api-level>_<abi> 형식의 태그를 사용합니다. 예를 들면 다음과 같습니다.

  • android_21_arm64_v8a
  • android_21_x86_64

<api-level>의 의미는 OS versions 절을 참조하십시오. 휠 태그에서 이 값은 휠을 컴파일할 때 선택한 최소 Android 버전을 나타냅니다. pip와 같은 설치 도구는 이 값을 기존 macOS 태그와 비슷한 방식으로 해석해야 합니다. 즉, 최소 API 레벨이 N인 앱은 API 레벨 N 이하로 태그된 휠을 포함할 수 있습니다.

이 형식은 Chaquopy 프로젝트에서 유래했으며, 이 프로젝트는 현재 API 레벨 16부터 21까지의 태그를 가진 휠 저장소를 관리하고 있습니다.

그러나 소수의 Android 애호가 집단에 의존해 Python 생태계 전체를 빌드하는 것은 확장 가능한 해결책이 아닙니다. 주요 라이브러리들이 자체 Android 휠을 일상적으로 릴리스하기 전까지는 커뮤니티가 Android에서 Python을 채택하는 데 한계가 있을 것입니다.

따라서 프로젝트가 자신의 CI 및 릴리스 도구에 Android 빌드를 추가하는 방법을 명확하게 문서화해야 합니다. crossenv와 cibuildwheel 같은 도구에 Android 지원을 추가하는 것이 이를 달성하는 한 가지 방법이 될 수 있습니다.

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 코드와 필요한 지원 패키지를 포함해 Python을 Android 앱에 빌드해 넣는 방법과, 런타임에 이를 모두 사용하는 방법을 알아야 합니다. 문서에서는 기존의 Windows 임베드 가능 패키지와 비슷한 형태로 이 내용을 다룰 것입니다. 그러나 대부분의 개발자에게는 Briefcase, Chaquopy, Buildozer 같은 더 높은 수준의 도구를 사용하도록 권장할 것이며, 이 도구들은 모두 이미 포괄적인 문서를 갖추고 있습니다.

둘째, 바이너리 구성 요소가 있는 패키지 개발자는 이를 Android용으로 빌드하고 릴리스하는 방법을 알아야 합니다(Packaging 참조).

참조 구현

Chaquopy 저장소에는 참조 패치와 빌드 스크립트가 들어 있습니다. 이를 업스트림에 반영하려면 먼저 Chaquopy의 다른 구성 요소와 분리해야 합니다.

Briefcase는 Android 기기와 에뮬레이터에서 테스트 스위트를 실행하는 코드의 참조 구현을 제공합니다. Toga Testbed는 GitHub Actions를 사용하여 Android 에뮬레이터에서 실행되는 테스트 스위트의 한 예입니다.

기각된 아이디어

platform.android_ver()의 원래 명세에서 다음 사항이 변경되었습니다:

  • min_api_level 필드는 다른 모든 필드와 달리 현재 기기의 속성이 아니므로 제거되었습니다. 이 정보는 기존 함수인 sys.getandroidapilevel()에서 여전히 얻을 수 있습니다.
  • 테스트 과정에서 일부 문제가 에뮬레이터에서만 발생한다는 것이 확인되었으므로 is_emulator 필드가 추가되었습니다.