Skip to content

Commit 41c6cc0

Browse files
authored
AAB support related changes (#2467)
* Added support for aab * Move to build:gradle:3.5.4 (adds support for API 30), fix some tests * Github actions test apps (apk + aab) * Add missing bdistaab * Fix automated tests * ndk lib folder (or ndk platform) now is ABI specific * Fixes dist lookup + some tests * Added .aab and .apks to blacklist * Interrupt build and alert the user if tried to build an aab in debug mode * Updates troubleshooting instructions to reflect current structure. * Exclude gdbserver and gdb.setup from release builds * Add a paragraph in history + fixes --arch docs * Fix versioning * Minor fixes to docs * Some code cleanup * Removes unusued versioning logic in unpackPyBundle and add a FIXME
1 parent 54139ea commit 41c6cc0

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

67 files changed

+486
-313
lines changed

.github/workflows/push.yml

+32-8
Original file line numberDiff line numberDiff line change
@@ -41,14 +41,10 @@ jobs:
4141
pip install tox>=2.0
4242
make test
4343
44-
build:
44+
build_apk:
4545
name: Unit test apk
4646
needs: [flake8]
4747
runs-on: ubuntu-latest
48-
strategy:
49-
fail-fast: false
50-
matrix:
51-
build-arch: ['arm64-v8a', 'armeabi-v7a', 'x86_64', 'x86']
5248
steps:
5349
- name: Checkout python-for-android
5450
uses: actions/checkout@v2
@@ -64,15 +60,43 @@ jobs:
6460
- name: Pull docker image
6561
run: |
6662
make docker/pull
67-
- name: Build apk Python 3 ${{ matrix.build-arch }}
63+
- name: Build multi-arch apk Python 3 (armeabi-v7a, arm64-v8a, x86_64, x86)
6864
run: |
6965
mkdir -p apks
70-
make docker/run/make/with-artifact/testapps-with-numpy/${{ matrix.build-arch }}
66+
make docker/run/make/with-artifact/apk/testapps-with-numpy
7167
- uses: actions/upload-artifact@v1
7268
with:
73-
name: bdist_test_app_unittests__${{ matrix.build-arch }}-debug-1.1.apk
69+
name: bdist_unit_tests_app-debug-1.1-.apk
7470
path: apks
7571

72+
build_aab:
73+
name: Unit test aab
74+
needs: [flake8]
75+
runs-on: ubuntu-latest
76+
steps:
77+
- name: Checkout python-for-android
78+
uses: actions/checkout@v2
79+
# helps with GitHub runner getting out of space
80+
- name: Free disk space
81+
run: |
82+
df -h
83+
sudo swapoff -a
84+
sudo rm -f /swapfile
85+
sudo apt -y clean
86+
docker rmi $(docker image ls -aq)
87+
df -h
88+
- name: Pull docker image
89+
run: |
90+
make docker/pull
91+
- name: Build Android App Bundle Python 3 (armeabi-v7a, arm64-v8a, x86_64, x86)
92+
run: |
93+
mkdir -p aabs
94+
make docker/run/make/with-artifact/aab/testapps-with-numpy-aab
95+
- uses: actions/upload-artifact@v1
96+
with:
97+
name: bdist_unit_tests_app-release-1.1-.aab
98+
path: aabs
99+
76100
rebuild_updated_recipes:
77101
name: Test updated recipes
78102
needs: [flake8]

Makefile

+17-8
Original file line numberDiff line numberDiff line change
@@ -34,12 +34,17 @@ rebuild_updated_recipes: virtualenv
3434
ANDROID_SDK_HOME=$(ANDROID_SDK_HOME) ANDROID_NDK_HOME=$(ANDROID_NDK_HOME) \
3535
$(PYTHON) ci/rebuild_updated_recipes.py
3636

37-
testapps-with-numpy/%: virtualenv
38-
$(eval $@_APP_ARCH := $(shell basename $*))
37+
testapps-with-numpy: virtualenv
3938
. $(ACTIVATE) && cd testapps/on_device_unit_tests/ && \
4039
python setup.py apk --sdk-dir $(ANDROID_SDK_HOME) --ndk-dir $(ANDROID_NDK_HOME) \
4140
--requirements libffi,sdl2,pyjnius,kivy,python3,openssl,requests,urllib3,chardet,idna,sqlite3,setuptools,numpy \
42-
--arch=$($@_APP_ARCH)
41+
--arch=armeabi-v7a --arch=arm64-v8a --arch=x86_64 --arch=x86
42+
43+
testapps-with-numpy-aab: virtualenv
44+
. $(ACTIVATE) && cd testapps/on_device_unit_tests/ && \
45+
python setup.py aab --sdk-dir $(ANDROID_SDK_HOME) --ndk-dir $(ANDROID_NDK_HOME) \
46+
--requirements libffi,sdl2,pyjnius,kivy,python3,openssl,requests,urllib3,chardet,idna,sqlite3,setuptools,numpy \
47+
--arch=armeabi-v7a --arch=arm64-v8a --arch=x86_64 --arch=x86 --release
4348

4449
testapps/%: virtualenv
4550
$(eval $@_APP_ARCH := $(shell basename $*))
@@ -69,14 +74,18 @@ docker/run/test: docker/build
6974
docker/run/command: docker/build
7075
docker run --rm --env-file=.env $(DOCKER_IMAGE) /bin/sh -c "$(COMMAND)"
7176

72-
docker/run/make/%: docker/build
73-
docker run --rm --env-file=.env $(DOCKER_IMAGE) make $*
77+
docker/run/make/with-artifact/apk/%: docker/build
78+
docker run --name p4a-latest --env-file=.env $(DOCKER_IMAGE) make $*
79+
docker cp p4a-latest:/home/user/app/testapps/on_device_unit_tests/bdist_unit_tests_app-debug-1.1-.apk ./apks
80+
docker rm -fv p4a-latest
7481

75-
docker/run/make/with-artifact/%: docker/build
76-
$(eval $@_APP_ARCH := $(shell basename $*))
82+
docker/run/make/with-artifact/aab/%: docker/build
7783
docker run --name p4a-latest --env-file=.env $(DOCKER_IMAGE) make $*
78-
docker cp p4a-latest:/home/user/app/testapps/on_device_unit_tests/bdist_unit_tests_app__$($@_APP_ARCH)-debug-1.1-.apk ./apks
84+
docker cp p4a-latest:/home/user/app/testapps/on_device_unit_tests/bdist_unit_tests_app-release-1.1-.aab ./aabs
7985
docker rm -fv p4a-latest
8086

87+
docker/run/make/%: docker/build
88+
docker run --rm --env-file=.env $(DOCKER_IMAGE) make $*
89+
8190
docker/run/shell: docker/build
8291
docker run --rm --env-file=.env -it $(DOCKER_IMAGE)

README.md

+8-2
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ python-for-android
88

99
python-for-android is a packaging tool for Python apps on Android. You can
1010
create your own Python distribution including the modules and
11-
dependencies you want, and bundle it in an APK along with your own code.
11+
dependencies you want, and bundle it in an APK or AAB along with your own code.
1212

1313
Features include:
1414

@@ -19,6 +19,7 @@ Features include:
1919
sqlalchemy.
2020
- Multiple architecture targets, for APKs optimised on any given
2121
device.
22+
- AAB: Android App Bundle support.
2223

2324
For documentation and support, see:
2425

@@ -30,7 +31,7 @@ For documentation and support, see:
3031

3132
Follow the [quickstart
3233
instructions](<https://python-for-android.readthedocs.org/en/latest/quickstart/>)
33-
to install and begin creating APKs.
34+
to install and begin creating APKs and AABs.
3435

3536
**Quick instructions**: install python-for-android with:
3637

@@ -52,6 +53,8 @@ With everything installed, build an APK with SDL2 with e.g.:
5253

5354
p4a apk --requirements=kivy --private /home/username/devel/planewave_frozen/ --package=net.inclem.planewavessdl2 --name="planewavessdl2" --version=0.5 --bootstrap=sdl2
5455

56+
**If you need to deploy your app on Google Play, Android App Bundle (aab) is required since 1 August 2021:**
57+
5558
**For full instructions and parameter options,** see [the
5659
documentation](https://python-for-android.readthedocs.io/en/latest/quickstart/#usage).
5760

@@ -109,6 +112,9 @@ api level below 21, you should use an older version of python-for-android
109112
On March of 2020 we dropped support for creating apps that use Python 2. The latest
110113
python-for-android release that supported building Python 2 was version 2019.10.6.
111114

115+
On August of 2021, we added support for Android App Bundle (aab). As a collateral,
116+
now We support multi-arch apk.
117+
112118
## Contributors
113119

114120
This project exists thanks to all the people who contribute. [[Contribute](CONTRIBUTING.md)].

doc/source/commands.rst

+3-2
Original file line numberDiff line numberDiff line change
@@ -71,8 +71,9 @@ supply those that you need.
7171
Whether the distribution must be compiled from scratch.
7272

7373
``--arch``
74-
The architecture to build for. Currently only one architecture can be
75-
targeted at a time, and a given distribution can only include one architecture.
74+
The architecture to build for. You can specify multiple architectures to build for
75+
at the same time. As an example ``p4a ... --arch arm64-v8a --arch armeabi-v7a ...``
76+
will build a distribution for both ``arm64-v8a`` and ``armeabi-v7a``.
7677

7778
``--bootstrap BOOTSTRAP``
7879
The Java bootstrap to use for your application. You mostly don't

doc/source/quickstart.rst

+18
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,24 @@ You can also replace flask with another web framework.
213213
Replace ``--port=5000`` with the port on which your app will serve a
214214
website. The default for Flask is 5000.
215215

216+
Exporting the Android App Bundle (aab) for distributing it on Google Play
217+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
218+
219+
Starting from August 2021 for new apps and from November 2021 for updates to existings apps,
220+
Google Play Console will require the Android App Bundle instead of the long lived apk.
221+
222+
python-for-android handles by itself the needed work to accomplish the new requirements:
223+
224+
p4a aab --private $HOME/code/myapp --package=org.example.myapp --name="My App" --version 0.1 --bootstrap=sdl2 --requirements=python3,kivy --arch=arm64-v8a --arch=armeabi-v7a --release
225+
226+
This `p4a aab ...` command builds a distribution with `python3`,
227+
`kivy`, and everything else you specified in the requirements.
228+
It will be packaged using a SDL2 bootstrap, and produce
229+
an `.aab` file that contains binaries for both `armeabi-v7a` and `arm64-v8a` ABIs.
230+
231+
The Android App Bundle, is supposed to be used for distributing your app.
232+
If you need to test it locally, on your device, you can use `bundletool <https://developer.android.com/studio/command-line/bundletool>`
233+
216234
Other options
217235
~~~~~~~~~~~~~
218236

doc/source/troubleshooting.rst

+19-15
Original file line numberDiff line numberDiff line change
@@ -85,31 +85,35 @@ At the top level, this will always contain the same set of files::
8585
AndroidManifest.xml classes.dex META-INF res
8686
assets lib YourApk.apk resources.arsc
8787

88-
The Python distribution is in the assets folder::
88+
The user app data (code, images, fonts ..) is packaged into a single tarball contained in the assets folder::
8989

9090
$ cd assets
9191
$ ls
92-
private.mp3
92+
private.tar
9393

94-
``private.mp3`` is actually a tarball containing all your packaged
95-
data, and the Python distribution. Extract it::
94+
``private.tar`` is a tarball containing all your packaged
95+
data. Extract it::
9696

97-
$ tar xf private.mp3
97+
$ tar xf private.tar
9898

99-
This will reveal all the Python-related files::
99+
This will reveal all the user app data (the files shown below are from the touchtracer demo)::
100100

101101
$ ls
102-
android_runnable.pyo include interpreter_subprocess main.kv pipinterface.kv settings.pyo
103-
assets __init__.pyo interpreterwrapper.pyo main.pyo pipinterface.pyo utils.pyo
104-
editor.kv interpreter.kv _python_bundle menu.kv private.mp3 widgets.pyo
105-
editor.pyo interpreter.pyo libpymodules.so menu.pyo settings.kv
102+
README.txt android.txt icon.png main.pyc p4a_env_vars.txt particle.png
103+
private.tar touchtracer.kv
106104

107-
Most of these files have been included by the user (in this case, they
108-
come from one of my own apps), the rest relate to the python
109-
distribution.
105+
Due to how We're required to ship ABI-specific things in Android App Bundle,
106+
the Python installation is packaged separately, as (most of it) is ABI-specific.
107+
108+
For example, the Python installation for ``arm64-v8a`` is available in ``lib/arm64-v8a/libpybundle.so``
109+
110+
``libpybundle.so`` is a tarball (but named like a library for packaging requirements), that contains our ``_python_bundle``::
111+
112+
$ tar xf libpybundle.so
113+
$ cd _python_bundle
114+
$ ls
115+
modules site-packages stdlib.zip
110116

111-
The python installation, along with all side-packages, is mostly contained
112-
inside the `_python_bundle` folder.
113117

114118

115119
Common errors

pythonforandroid/archs.py

+23-4
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
from distutils.spawn import find_executable
22
from os import environ
3-
from os.path import join, split
3+
from os.path import join, split, exists
44
from multiprocessing import cpu_count
55
from glob import glob
66

7+
from pythonforandroid.logger import warning
78
from pythonforandroid.recipe import Recipe
89
from pythonforandroid.util import BuildInterruptingException, build_platform
910

@@ -30,7 +31,7 @@ class Arch:
3031
common_cppflags = [
3132
'-DANDROID',
3233
'-D__ANDROID_API__={ctx.ndk_api}',
33-
'-I{ctx.ndk_dir}/sysroot/usr/include/{command_prefix}',
34+
'-I{ctx.ndk_sysroot}/usr/include/{command_prefix}',
3435
'-I{python_includes}',
3536
]
3637

@@ -57,6 +58,24 @@ def __init__(self, ctx):
5758
def __str__(self):
5859
return self.arch
5960

61+
@property
62+
def ndk_lib_dir(self):
63+
return join(self.ctx.ndk_sysroot, 'usr', 'lib', self.command_prefix, str(self.ctx.ndk_api))
64+
65+
@property
66+
def ndk_platform(self):
67+
warning("ndk_platform is deprecated and should be avoided in new recipes")
68+
ndk_platform = join(
69+
self.ctx.ndk_dir,
70+
'platforms',
71+
'android-{}'.format(self.ctx.ndk_api),
72+
self.platform_dir)
73+
if not exists(ndk_platform):
74+
BuildInterruptingException(
75+
"The requested platform folder doesn't exist. If you're building on ndk >= r22, and seeing this error, one of the required recipe is using a removed feature."
76+
)
77+
return ndk_platform
78+
6079
@property
6180
def include_dirs(self):
6281
return [
@@ -133,7 +152,7 @@ def get_env(self, with_flags_in_cc=True):
133152
ctx=self.ctx,
134153
command_prefix=self.command_prefix,
135154
python_includes=join(
136-
self.ctx.get_python_install_dir(),
155+
self.ctx.get_python_install_dir(self.arch),
137156
'include/python{}'.format(self.ctx.python_recipe.version[0:3]),
138157
),
139158
)
@@ -213,7 +232,7 @@ def get_env(self, with_flags_in_cc=True):
213232
# Android's arch/toolchain
214233
env['ARCH'] = self.arch
215234
env['NDK_API'] = 'android-{}'.format(str(self.ctx.ndk_api))
216-
env['TOOLCHAIN_PREFIX'] = self.ctx.toolchain_prefix
235+
env['TOOLCHAIN_PREFIX'] = self.toolchain_prefix
217236
env['TOOLCHAIN_VERSION'] = self.ctx.toolchain_version
218237

219238
# Custom linker options

pythonforandroid/bdistapk.py

+9-6
Original file line numberDiff line numberDiff line change
@@ -128,21 +128,23 @@ def prepare_build_dir(self):
128128

129129

130130
class BdistAPK(Bdist):
131-
"""
132-
distutil command handler for 'apk'
133-
"""
131+
"""distutil command handler for 'apk'."""
134132
description = 'Create an APK with python-for-android'
135133
package_type = 'apk'
136134

137135

138136
class BdistAAR(Bdist):
139-
"""
140-
distutil command handler for 'aar'
141-
"""
137+
"""distutil command handler for 'aar'."""
142138
description = 'Create an AAR with python-for-android'
143139
package_type = 'aar'
144140

145141

142+
class BdistAAB(Bdist):
143+
"""distutil command handler for 'aab'."""
144+
description = 'Create an AAB with python-for-android'
145+
package_type = 'aab'
146+
147+
146148
def _set_user_options():
147149
# This seems like a silly way to do things, but not sure if there's a
148150
# better way to pass arbitrary options onwards to p4a
@@ -156,6 +158,7 @@ def _set_user_options():
156158
user_options.append((arg[2:], None, None))
157159

158160
BdistAPK.user_options = user_options
161+
BdistAAB.user_options = user_options
159162

160163

161164
_set_user_options()

pythonforandroid/bootstrap.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -374,7 +374,7 @@ def strip_libraries(self, arch):
374374
if len(tokens) > 1:
375375
strip = strip.bake(tokens[1:])
376376

377-
libs_dir = join(self.dist_dir, '_python_bundle',
377+
libs_dir = join(self.dist_dir, f'_python_bundle__{arch.arch}',
378378
'_python_bundle', 'modules')
379379
filens = shprint(sh.find, libs_dir, join(self.dist_dir, 'libs'),
380380
'-iname', '*.so', _env=env).stdout.decode('utf-8')

0 commit comments

Comments
 (0)