android: update for rebase p4a, update qt to 6.10, ndk to 28
What changed, and why it matters
This commit is a routine Android build-system maintenance update for the Electrum Bitcoin wallet. It upgrades the Android NDK, SDK tools, build tools, API level, Qt framework, Python packaging tools, and cryptographic library (OpenSSL) used to build the Android app. There is no indication in the commit message or diff of a security bug, vulnerability fix, or malicious change. It appears to be a dependency refresh to keep the build current.
No security action required. Treat as normal dependency/maintenance update. Verify build reproducibility and run usual Android release tests after the toolchain bump.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The commit updates the Android build environment and pinned Python-for-Android recipes. Key changes: NDK from a 23d-canary CI build to stable 28c; SDK command-line tools to 14742923; build tools to 35.0.0; compileSdk/api to 35; P4A checkout to 375a05de21b5 on branch electrum_202602; Qt6 6.4.3→6.10.1; PyQt6 6.4.2→6.10.1; PyQt6-sip 13.5.1→13.10.3; sip 6.7.9→6.15.1; PyQt-builder 1.15.1→1.19.1; setuptools 51.3.3→80.9.0; cffi 1.15.1→2.0.0; OpenSSL 3.0.18→3.3.1; pyjnius 1.5.0→1.7.0; hostpython3/python3 hashes updated. The Dockerfile switches from a CI-downloaded NDK back to the official Google download with SHA-256 verification. No application code, wallet logic, or network/crypto handling code is modified.
Changed components
contrib/android/Dockerfilecontrib/android/buildozer_qml.speccontrib/android/p4a_recipes/cffi/__init__.pycontrib/android/p4a_recipes/hostpython3/__init__.pycontrib/android/p4a_recipes/openssl/__init__.pycontrib/android/p4a_recipes/pyjnius/__init__.pycontrib/android/p4a_recipes/pyqt6/__init__.pycontrib/android/p4a_recipes/pyqt6sip/__init__.pycontrib/android/p4a_recipes/pyqt_builder/__init__.pycontrib/android/p4a_recipes/python3/__init__.pycontrib/android/p4a_recipes/qt6/__init__.pycontrib/android/p4a_recipes/setuptools/__init__.pycontrib/android/p4a_recipes/sip/__init__.pyInspect captured patch +42 / −63
diff --git a/contrib/android/Dockerfile b/contrib/android/Dockerfile
index d462bd4..3520ffe 100644
--- a/contrib/android/Dockerfile
+++ b/contrib/android/Dockerfile
@@ -33,12 +33,8 @@ RUN apt -y update -qq \
ENV ANDROID_NDK_HOME="${ANDROID_HOME}/android-ndk"
-#ENV ANDROID_NDK_VERSION="23b"
-#ENV ANDROID_NDK_HASH="c6e97f9c8cfe5b7be0a9e6c15af8e7a179475b7ded23e2d1c1fa0945d6fb4382"
-#ENV ANDROID_NDK_VERSION="27d"
-#ENV ANDROID_NDK_HASH="601246087a682d1944e1e16dd85bc6e49560fe8b6d61255be2829178c8ed15d9"
-ENV ANDROID_NDK_VERSION="23d-canary"
-ENV ANDROID_NDK_HASH="6944ffc20ab018ff4ef6a403048d0a99d50a0630c3eae690c8f803c452f46f3e"
+ENV ANDROID_NDK_VERSION="28c"
+ENV ANDROID_NDK_HASH="dfb20d396df28ca02a8c708314b814a4d961dc9074f9a161932746f815aa552f"
ENV ANDROID_NDK_HOME_V="${ANDROID_NDK_HOME}-r${ANDROID_NDK_VERSION}"
# get the latest version from https://developer.android.com/ndk/downloads/index.html
@@ -48,31 +44,21 @@ ENV ANDROID_NDK_DL_URL="https://dl.google.com/android/repository/${ANDROID_NDK_A
# below disabled in favor of CI build download
# download and install Android NDK
-#RUN curl --location --progress-bar \
-# "${ANDROID_NDK_DL_URL}" \
-# --output "${ANDROID_NDK_ARCHIVE}" \
-# && echo "${ANDROID_NDK_HASH} ${ANDROID_NDK_ARCHIVE}" | sha256sum -c - \
-# && mkdir --parents "${ANDROID_NDK_HOME_V}" \
-# && unzip -q "${ANDROID_NDK_ARCHIVE}" -d "${ANDROID_HOME}" \
-# && ln -sfn "${ANDROID_NDK_HOME_V}" "${ANDROID_NDK_HOME}" \
-# && rm -rf "${ANDROID_NDK_ARCHIVE}"
-
-# temporary build using NDK from CI
-ENV CI_REV="12186248"
-ENV CI_NDK_FILE="android-ndk-${CI_REV}-linux-x86_64.zip"
-COPY contrib/android/dl-ndk-ci.sh /tmp/
-RUN /tmp/dl-ndk-ci.sh https://ci.android.com/builds/submitted/${CI_REV}/linux/latest/${CI_NDK_FILE} \
- && echo "${ANDROID_NDK_HASH} android-ndk-ci-linux-x86_64.zip" | sha256sum -c - \
+RUN curl --location --progress-bar \
+ "${ANDROID_NDK_DL_URL}" \
+ --output "${ANDROID_NDK_ARCHIVE}" \
+ && echo "${ANDROID_NDK_HASH} ${ANDROID_NDK_ARCHIVE}" | sha256sum -c - \
&& mkdir --parents "${ANDROID_NDK_HOME_V}" \
- && unzip -q "android-ndk-ci-linux-x86_64.zip" -d "${ANDROID_HOME}" \
+ && unzip -q "${ANDROID_NDK_ARCHIVE}" -d "${ANDROID_HOME}" \
&& ln -sfn "${ANDROID_NDK_HOME_V}" "${ANDROID_NDK_HOME}" \
- && rm -rf "android-ndk-ci-linux-x86_64.zip"
+ && rm -rf "${ANDROID_NDK_ARCHIVE}"
ENV ANDROID_SDK_HOME="${ANDROID_HOME}/android-sdk"
# get the latest version from https://developer.android.com/studio/index.html
-ENV ANDROID_SDK_TOOLS_VERSION="9477386"
-ENV ANDROID_SDK_HASH="bd1aa17c7ef10066949c88dc6c9c8d536be27f992a1f3b5a584f9bd2ba5646a0"
+ENV ANDROID_SDK_TOOLS_VERSION="14742923"
+ENV ANDROID_SDK_HASH="04453066b540409d975c676d781da1477479dde3761310f1a7eb92a1dfb15af7"
+
ENV ANDROID_SDK_TOOLS_ARCHIVE="commandlinetools-linux-${ANDROID_SDK_TOOLS_VERSION}_latest.zip"
ENV ANDROID_SDK_TOOLS_DL_URL="https://dl.google.com/android/repository/${ANDROID_SDK_TOOLS_ARCHIVE}"
ENV ANDROID_SDK_MANAGER="${ANDROID_SDK_HOME}/cmdline-tools/bin/sdkmanager --sdk_root=${ANDROID_SDK_HOME}"
@@ -130,8 +116,8 @@ RUN apt -y update -qq \
RUN yes | ${ANDROID_SDK_MANAGER} --licenses > /dev/null
-ENV ANDROID_SDK_BUILD_TOOLS_MAJOR_V="31"
-ENV ANDROID_SDK_BUILD_TOOLS_VERSION="31.0.0"
+ENV ANDROID_SDK_BUILD_TOOLS_MAJOR_V="35"
+ENV ANDROID_SDK_BUILD_TOOLS_VERSION="35.0.0"
# download platforms, API, build tools
RUN ${ANDROID_SDK_MANAGER} "platforms;android-${ANDROID_SDK_BUILD_TOOLS_MAJOR_V}" > /dev/null && \
@@ -190,7 +176,6 @@ RUN apt -y update -qq \
&& apt -y install -qq --no-install-recommends --allow-downgrades \
libopengl-dev \
libegl-dev \
- dos2unix \
&& apt -y autoremove \
&& apt -y clean
@@ -250,8 +235,8 @@ RUN cd /opt \
&& /opt/venv/bin/python3 -m pip install --no-build-isolation --no-dependencies -e .
# install python-for-android
-ENV P4A_CHECKOUT_COMMIT="a01269f7799587ad74ee40e0b642d917b8db7d4e"
-# ^ from branch electrum_20251211 (note: careful with force-pushing! see #8162)
+ENV P4A_CHECKOUT_COMMIT="375a05de21b538d704174b1efeb3fc85d151f94e"
+# ^ from branch electrum_202602 (note: careful with force-pushing! see #8162)
RUN cd /opt \
&& git clone https://github.com/spesmilo/python-for-android \
&& cd python-for-android \
diff --git a/contrib/android/buildozer_qml.spec b/contrib/android/buildozer_qml.spec
index 4546181..2c6120a 100644
--- a/contrib/android/buildozer_qml.spec
+++ b/contrib/android/buildozer_qml.spec
@@ -105,7 +105,7 @@ android.permissions = INTERNET, CAMERA, WRITE_EXTERNAL_STORAGE, POST_NOTIFICATIO
# (int) Android API to use (compileSdkVersion)
# note: when changing, Dockerfile also needs to be changed to install corresponding build tools
-android.api = 31
+android.api = 35
# (int) Android targetSdkVersion
android.target_sdk_version = 35
@@ -114,7 +114,7 @@ android.target_sdk_version = 35
android.minapi = 23
# (str) Android NDK version to use
-android.ndk = 23b
+android.ndk = 28c
# (int) Android NDK API to use (optional). This is the minimum API your app will support.
android.ndk_api = 23
diff --git a/contrib/android/p4a_recipes/cffi/__init__.py b/contrib/android/p4a_recipes/cffi/__init__.py
index c96c7ac..a5bbf2b 100644
--- a/contrib/android/p4a_recipes/cffi/__init__.py
+++ b/contrib/android/p4a_recipes/cffi/__init__.py
@@ -6,14 +6,13 @@ from pythonforandroid.util import load_source
util = load_source('util', os.path.join(os.path.dirname(os.path.dirname(__file__)), 'util.py'))
-assert CffiRecipe._version == "1.15.1"
-assert CffiRecipe.depends == ['setuptools', 'pycparser', 'libffi', 'python3']
+assert CffiRecipe._version == "2.0.0"
+assert CffiRecipe.depends == ['pycparser', 'libffi', 'python3'], CffiRecipe.depends
assert CffiRecipe.python_depends == []
class CffiRecipePinned(util.InheritedRecipeMixin, CffiRecipe):
- version = "1.17.1"
- sha512sum = "907129891d56351ca5cb885aae62334ad432321826d6eddfaa32195b4c7b7689a80333e6d14d0aab479a646aba148b9852c0815b80344dfffa4f183a5e74372c"
+ sha512sum = "a71b74e642e11eb50e9bb4ae0e7116bdb3c4a7c9622a3766d84506fa7994c02e09644b41b439b95ca99b0303e91891897cff38018d498eb087e0961f0ad4fb8b"
recipe = CffiRecipePinned()
diff --git a/contrib/android/p4a_recipes/hostpython3/__init__.py b/contrib/android/p4a_recipes/hostpython3/__init__.py
index a9a1be3..9d1dcb8 100644
--- a/contrib/android/p4a_recipes/hostpython3/__init__.py
+++ b/contrib/android/p4a_recipes/hostpython3/__init__.py
@@ -13,7 +13,7 @@ assert HostPython3Recipe.python_depends == []
class HostPython3RecipePinned(util.InheritedRecipeMixin, HostPython3Recipe):
# PYTHON_VERSION= # < line here so that I can grep the codebase and teleport here
version = "3.11.14"
- sha512sum = "41fb3ae22ce4ac0e8bb6b9ae8db88a810af1001d944e3f1abc9e86824ae4be31347e3e3a70425ab12271c6b7eeef552f00164ef23cfffa2551c3c9d1fe5ab91f"
+ sha512sum = "4642f6d59c76c6e5dbd827fdb28694376a9cc76e513146d092b49afb41513b3c9dff2339cfcebfb5b260f5cdc49a59a69906e284e5d478b2189d3374e9e24fd5"
recipe = HostPython3RecipePinned()
diff --git a/contrib/android/p4a_recipes/openssl/__init__.py b/contrib/android/p4a_recipes/openssl/__init__.py
index fdbb7d6..501d0bc 100644
--- a/contrib/android/p4a_recipes/openssl/__init__.py
+++ b/contrib/android/p4a_recipes/openssl/__init__.py
@@ -6,14 +6,13 @@ from pythonforandroid.util import load_source
util = load_source('util', os.path.join(os.path.dirname(os.path.dirname(__file__)), 'util.py'))
-assert OpenSSLRecipe._version == "3.0.18"
+assert OpenSSLRecipe._version == "3.3.1"
assert OpenSSLRecipe.depends == []
assert OpenSSLRecipe.python_depends == []
class OpenSSLRecipePinned(util.InheritedRecipeMixin, OpenSSLRecipe):
- version = "3.0.18"
- sha512sum = "6bdd16f33b83ae2a12777230c4ff00d0595bbc00253ac8c3ac31e1375e818fc74d7f491bd2e507ff33cab9f0498cfb28fa8690f75a98663568d40901523cdf3c"
+ sha512sum = "d3682a5ae0721748c6b9ec2f1b74d2b1ba61ee6e4c0d42387b5037a56ef34312833b6abb522d19400b45d807dd65cc834156f5e891cb07fbaf69fcf67e1c595d"
recipe = OpenSSLRecipePinned()
diff --git a/contrib/android/p4a_recipes/pyjnius/__init__.py b/contrib/android/p4a_recipes/pyjnius/__init__.py
index 16a052e..7e850c9 100644
--- a/contrib/android/p4a_recipes/pyjnius/__init__.py
+++ b/contrib/android/p4a_recipes/pyjnius/__init__.py
@@ -6,14 +6,13 @@ from pythonforandroid.util import load_source
util = load_source('util', os.path.join(os.path.dirname(os.path.dirname(__file__)), 'util.py'))
-assert PyjniusRecipe._version == "1.5.0"
-assert PyjniusRecipe.depends == [('genericndkbuild', 'sdl2', 'qt6'), 'six', 'python3']
+assert PyjniusRecipe._version == "1.7.0"
+assert PyjniusRecipe.depends == [('genericndkbuild', 'sdl2', 'sdl3', 'qt6'), 'six', 'python3'], PyjniusRecipe.depends
assert PyjniusRecipe.python_depends == []
class PyjniusRecipePinned(util.InheritedRecipeMixin, PyjniusRecipe):
- version = "1.6.1"
- sha512sum = "deb5ac566479111c6f4c6adb895821b263d72bf88414fb093bdfd5ad5d0b7aea56b53d5ef0967e28db360f4fb6fb1c2264123f15c747884799df55848191c424"
+ sha512sum = "a192c30ef87ca9601455976feb49f03dfdb8e1bf2545744a7b771a6d0930a56b334c7a2a39d30fb8855c070f16e4673dc5ff6920b04a6155ab5f9247b271df76"
recipe = PyjniusRecipePinned()
diff --git a/contrib/android/p4a_recipes/pyqt6/__init__.py b/contrib/android/p4a_recipes/pyqt6/__init__.py
index 37b2a21..2ca6380 100644
--- a/contrib/android/p4a_recipes/pyqt6/__init__.py
+++ b/contrib/android/p4a_recipes/pyqt6/__init__.py
@@ -6,13 +6,13 @@ from pythonforandroid.util import load_source
util = load_source('util', os.path.join(os.path.dirname(os.path.dirname(__file__)), 'util.py'))
-assert PyQt6Recipe._version == "6.4.2"
-assert PyQt6Recipe.depends == ['qt6', 'pyjnius', 'setuptools', 'pyqt6sip', 'hostpython3', 'pyqt_builder']
+assert PyQt6Recipe._version == "6.10.1"
+assert PyQt6Recipe.depends == ['qt6', 'pyjnius', 'setuptools', 'pyqt6sip', 'hostpython3', 'python3'], PyQt6Recipe.depends
assert PyQt6Recipe.python_depends == []
class PyQt6RecipePinned(util.InheritedRecipeMixin, PyQt6Recipe):
- sha512sum = "51e5f0d028ee7984876da1653cb135d61e2c402f18b939a92477888cc7c86d3bc2889477403dee6b3d9f66519ee3236d344323493b4c2c2e658e1637b10e53bf"
+ sha512sum = "af9bb54b20fd177cf1dac5fe8fb0ff289e1e7e42716d09093d49dd99a7d8065c6b6f34784ed19e21e7e07ba0d550b270cb6be7273f7180e2bf886160fc773d01"
recipe = PyQt6RecipePinned()
diff --git a/contrib/android/p4a_recipes/pyqt6sip/__init__.py b/contrib/android/p4a_recipes/pyqt6sip/__init__.py
index 301c157..6c35425 100644
--- a/contrib/android/p4a_recipes/pyqt6sip/__init__.py
+++ b/contrib/android/p4a_recipes/pyqt6sip/__init__.py
@@ -6,13 +6,13 @@ from pythonforandroid.util import load_source
util = load_source('util', os.path.join(os.path.dirname(os.path.dirname(__file__)), 'util.py'))
-assert PyQt6SipRecipe._version == "13.5.1"
+assert PyQt6SipRecipe._version == "13.10.3"
assert PyQt6SipRecipe.depends == ['setuptools', 'python3']
assert PyQt6SipRecipe.python_depends == []
class PyQt6SipRecipePinned(util.InheritedRecipeMixin, PyQt6SipRecipe):
- sha512sum = "1e4170d167a326afe6df86e4a35e209299548054981cb2e5d56da234ef9db4d8594bcb05b6be363c3bc6252776ae9de63d589a3d9f33fba8250d39cdb5e9061a"
+ sha512sum = "555b061eec3db6a66388fae07de21f58d756f6f12b13e4ede729c3348d2c8997ac5a59d3006ee45c3a09b5cde673f579265fa254bc583a4ba721748cf8f3a617"
recipe = PyQt6SipRecipePinned()
diff --git a/contrib/android/p4a_recipes/pyqt_builder/__init__.py b/contrib/android/p4a_recipes/pyqt_builder/__init__.py
index 6b6a674..516dc99 100644
--- a/contrib/android/p4a_recipes/pyqt_builder/__init__.py
+++ b/contrib/android/p4a_recipes/pyqt_builder/__init__.py
@@ -1,13 +1,12 @@
from pythonforandroid.recipes.pyqt_builder import PyQtBuilderRecipe
-assert PyQtBuilderRecipe._version == "1.15.1"
+assert PyQtBuilderRecipe._version == "1.19.1"
assert PyQtBuilderRecipe.depends == ["sip", "packaging", "python3"]
assert PyQtBuilderRecipe.python_depends == []
class PyQtBuilderRecipePinned(PyQtBuilderRecipe):
- sha512sum = "61ee73b6bb922c04739da60025ab50d35d345d2e298943305fcbd3926cda31d732cc5e5b0dbfc39f5eb85c0f0b091b8c3f5fee00dcc240d7849c5c4191c1368a"
-
+ sha512sum = "2308c51f93c37b1d13f312e4f2475d26b22d374ef284925fead9eab4aa89b994770431aca45170ac2154b4813fff151798f113f56d4cbf6c6e544fb463104a6d"
recipe = PyQtBuilderRecipePinned()
diff --git a/contrib/android/p4a_recipes/python3/__init__.py b/contrib/android/p4a_recipes/python3/__init__.py
index 6fc9d51..11cf395 100644
--- a/contrib/android/p4a_recipes/python3/__init__.py
+++ b/contrib/android/p4a_recipes/python3/__init__.py
@@ -13,7 +13,7 @@ assert Python3Recipe.python_depends == []
class Python3RecipePinned(util.InheritedRecipeMixin, Python3Recipe):
# PYTHON_VERSION= # < line here so that I can grep the codebase and teleport here
version = "3.11.14"
- sha512sum = "41fb3ae22ce4ac0e8bb6b9ae8db88a810af1001d944e3f1abc9e86824ae4be31347e3e3a70425ab12271c6b7eeef552f00164ef23cfffa2551c3c9d1fe5ab91f"
+ sha512sum = "4642f6d59c76c6e5dbd827fdb28694376a9cc76e513146d092b49afb41513b3c9dff2339cfcebfb5b260f5cdc49a59a69906e284e5d478b2189d3374e9e24fd5"
recipe = Python3RecipePinned()
diff --git a/contrib/android/p4a_recipes/qt6/__init__.py b/contrib/android/p4a_recipes/qt6/__init__.py
index 1a91e0b..741826e 100644
--- a/contrib/android/p4a_recipes/qt6/__init__.py
+++ b/contrib/android/p4a_recipes/qt6/__init__.py
@@ -1,19 +1,17 @@
import os
from pythonforandroid.recipes.qt6 import Qt6Recipe
-
from pythonforandroid.util import load_source
util = load_source('util', os.path.join(os.path.dirname(os.path.dirname(__file__)), 'util.py'))
-assert Qt6Recipe._version == "6.4.3"
-# assert Qt6Recipe._version == "6.5.3"
+assert Qt6Recipe._version == "6.10.1"
assert Qt6Recipe.depends == ['python3', 'hostqt6']
assert Qt6Recipe.python_depends == []
+
class Qt6RecipePinned(util.InheritedRecipeMixin, Qt6Recipe):
- sha512sum = "0bdbe8b9a43390c98cf19e851ec5394bc78438d227cf9d0d7a3748aee9a32a7f14fc46f52d4fa283819f21413567080aee7225c566af5278557f5e1992674da3"
- # sha512sum = "ca8ea3b81c121886636988275f7fa8ae6d19f7be02669e63ab19b4285b611057a41279db9532c25ae87baa3904b010e1db68b899cd0eda17a5a8d3d87098b4d5"
+ sha512sum = "62e8a8fcdef84187bff43e6185a1ba983e3db4d927ec01cd0ff5247d12eb7fd116a8f67323b3e44ba23f2e1792ade8c54e033cf28f34ec42a776ec204b9c2d8d"
recipe = Qt6RecipePinned()
diff --git a/contrib/android/p4a_recipes/setuptools/__init__.py b/contrib/android/p4a_recipes/setuptools/__init__.py
index 10a26f3..23c3596 100644
--- a/contrib/android/p4a_recipes/setuptools/__init__.py
+++ b/contrib/android/p4a_recipes/setuptools/__init__.py
@@ -1,13 +1,13 @@
from pythonforandroid.recipes.setuptools import SetuptoolsRecipe
-assert SetuptoolsRecipe._version == "51.3.3"
+assert SetuptoolsRecipe._version == "80.9.0"
assert SetuptoolsRecipe.depends == ['python3']
assert SetuptoolsRecipe.python_depends == []
class SetuptoolsRecipePinned(SetuptoolsRecipe):
- sha512sum = "5a3572466a68c6f650111448ce3343f64c62044650bb8635edbff97e2bc7b216b8bbe3b4e3bccf34e6887f3bedc911b27ca5f9a515201cae49cf44fbacf03345"
+ sha512sum = "36eb1f219d29c6b9e135936bde2001ad70a971c8069cd0175d3a5325b450e6843a903d3f70043c9f534768ebeab8ab0c544b8f44456555d333f1ed72daa5c18b"
recipe = SetuptoolsRecipePinned()
diff --git a/contrib/android/p4a_recipes/sip/__init__.py b/contrib/android/p4a_recipes/sip/__init__.py
index d1aea65..417c9be 100644
--- a/contrib/android/p4a_recipes/sip/__init__.py
+++ b/contrib/android/p4a_recipes/sip/__init__.py
@@ -1,13 +1,13 @@
from pythonforandroid.recipes.sip import SipRecipe
-assert SipRecipe._version == "6.7.9"
-assert SipRecipe.depends == ["setuptools", "packaging", "tomli", "ply", "python3"], SipRecipe.depends
+assert SipRecipe._version == "6.15.1"
+assert SipRecipe.depends == ["setuptools", "packaging", "tomli", "python3"], SipRecipe.depends
assert SipRecipe.python_depends == []
class SipRecipePinned(SipRecipe):
- sha512sum = "bb9d0d0d92002b6fd33f7e8ebe8cd62456dacc16b5734b73760b1ba14fb9b1f2b9b6640b40196c6cf5f345e1afde48bdef39675c4d3480041771325d4cf3c233"
+ sha512sum = "30a312419ba82c0221c0cf03c3fb3ad7d45bb8fe633d1d7477025a7986b0a7f7b7b781a8d9cd6bcdb78f3b872231fd1eed123a761b497861822f2e35093f574d"
recipe = SipRecipePinned()
Why this scored 15/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.