Skip to content

Commit 96cbc7b

Browse files
author
اشکان
committed
Merge branch 'develop' into qt_pyside6-based-android-service
2 parents 58e840c + 6494ac1 commit 96cbc7b

File tree

43 files changed

+1263
-1237
lines changed

Some content is hidden

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

43 files changed

+1263
-1237
lines changed

.github/workflows/push.yml

Lines changed: 44 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,26 @@ jobs:
3030
pip install tox>=2.0
3131
tox -e pep8
3232
33+
spotless:
34+
name: Java Spotless check
35+
runs-on: ubuntu-latest
36+
steps:
37+
- name: Checkout python-for-android
38+
uses: actions/checkout@v5
39+
- name: Set up Java 17
40+
uses: actions/setup-java@v4
41+
with:
42+
distribution: 'temurin'
43+
java-version: '17'
44+
- name: Set up Gradle
45+
uses: gradle/actions/setup-gradle@v4
46+
- name: Run Spotless check
47+
working-directory: pythonforandroid/bootstraps
48+
run: ./common/build/gradlew spotlessCheck
49+
3350
test:
3451
name: Pytest [Python ${{ matrix.python-version }} | ${{ matrix.os }}]
35-
needs: flake8
52+
needs: [flake8, spotless]
3653
runs-on: ${{ matrix.os }}
3754
strategy:
3855
fail-fast: false
@@ -61,9 +78,8 @@ jobs:
6178

6279
ubuntu_build:
6380
name: Build test APP [ ${{ matrix.runs_on }} | ${{ matrix.bootstrap.name }} ]
64-
needs: [flake8]
81+
needs: [flake8, spotless]
6582
runs-on: ${{ matrix.runs_on }}
66-
continue-on-error: true
6783
strategy:
6884
matrix:
6985
runs_on: [ubuntu-latest]
@@ -79,6 +95,16 @@ jobs:
7995
- name: qt
8096
target: testapps-qt
8197
steps:
98+
- name: Maximize build space
99+
uses: easimon/maximize-build-space@v10
100+
with:
101+
root-reserve-mb: 30720
102+
swap-size-mb: 1024
103+
remove-dotnet: 'true'
104+
remove-android: 'true'
105+
remove-haskell: 'true'
106+
remove-codeql: 'true'
107+
remove-docker-images: 'true'
82108
- name: Checkout python-for-android
83109
uses: actions/checkout@v5
84110
- name: Build python-for-android docker image
@@ -111,9 +137,8 @@ jobs:
111137

112138
macos_build:
113139
name: Build test APP [ ${{ matrix.runs_on }} | ${{ matrix.bootstrap.name }} ]
114-
needs: [flake8]
140+
needs: [flake8, spotless]
115141
runs-on: ${{ matrix.runs_on }}
116-
continue-on-error: true
117142
strategy:
118143
matrix:
119144
# macos-latest (ATM macos-15) runs on Apple Silicon,
@@ -186,28 +211,30 @@ jobs:
186211

187212
ubuntu_rebuild_updated_recipes:
188213
name: Test updated recipes for arch ${{ matrix.android_arch }} [ ubuntu-latest ]
189-
needs: [flake8]
214+
needs: [flake8, spotless]
190215
runs-on: ubuntu-latest
216+
# continue on error to see failures across all architectures
191217
continue-on-error: true
192218
strategy:
193219
matrix:
194220
android_arch: ["arm64-v8a", "armeabi-v7a", "x86_64", "x86"]
195221
env:
196222
REBUILD_UPDATED_RECIPES_EXTRA_ARGS: --arch=${{ matrix.android_arch }}
197223
steps:
224+
- name: Maximize build space
225+
uses: easimon/maximize-build-space@v10
226+
with:
227+
root-reserve-mb: 30720
228+
swap-size-mb: 1024
229+
remove-dotnet: 'true'
230+
remove-android: 'true'
231+
remove-haskell: 'true'
232+
remove-codeql: 'true'
233+
remove-docker-images: 'true'
198234
- name: Checkout python-for-android (all-history)
199235
uses: actions/checkout@v5
200236
with:
201237
fetch-depth: 0
202-
# helps with GitHub runner getting out of space
203-
- name: Free disk space
204-
run: |
205-
df -h
206-
sudo swapoff -a
207-
sudo rm -f /swapfile
208-
sudo apt -y clean
209-
docker images -q | xargs -r docker rmi
210-
df -h
211238
- name: Pull docker image
212239
run: |
213240
make docker/pull
@@ -217,8 +244,9 @@ jobs:
217244
218245
macos_rebuild_updated_recipes:
219246
name: Test updated recipes for arch ${{ matrix.android_arch }} [ ${{ matrix.runs_on }} ]
220-
needs: [flake8]
247+
needs: [flake8, spotless]
221248
runs-on: ${{ matrix.runs_on }}
249+
# continue on error to see failures across all architectures
222250
continue-on-error: true
223251
strategy:
224252
matrix:

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,5 +36,9 @@ coverage.xml
3636
# testapp's build folder
3737
testapps/build/
3838

39+
# Gradle build artifacts (Java linting)
40+
pythonforandroid/bootstraps/.gradle/
41+
pythonforandroid/bootstraps/build/
42+
3943
# Dolphin (the KDE file manager autogenerates the file `.directory`)
4044
.directory

CONTRIBUTING.md

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,60 @@ latest python-for-android release that supported building Python 2 was version
6666
On August 2021, we added support for Android App Bundle (aab). As a
6767
collateral benefit, we now support multi-arch apk.
6868

69+
## Code Quality
70+
71+
### Python Linting
72+
73+
Python code is linted using flake8. Run it locally with:
74+
75+
```bash
76+
tox -e pep8
77+
```
78+
79+
### Java Linting
80+
81+
Java source files in the bootstrap directories are linted using
82+
[Spotless](https://github.com/diffplug/spotless) with Google Java Format
83+
(AOSP style). The CI runs this check automatically.
84+
85+
**Local execution** (requires Java 17+):
86+
87+
```bash
88+
# Check for violations
89+
make java-lint
90+
91+
# Auto-fix violations
92+
make java-lint-fix
93+
```
94+
95+
The Makefile uses the Gradle wrapper (`gradlew`), which automatically downloads
96+
the correct Gradle version on first run. No manual Gradle installation is required.
97+
98+
**Using Docker** (if you don't have Java 17):
99+
100+
```bash
101+
# Check for violations
102+
make docker/java-lint
103+
104+
# Auto-fix violations
105+
make docker/java-lint-fix
106+
```
107+
108+
The Docker approach builds the project's Docker image (which includes Java 17)
109+
and runs the linting inside the container.
110+
111+
**What gets linted:**
112+
113+
- All `.java` files in `pythonforandroid/bootstraps/*/build/src/main/java/`
114+
- Excludes third-party code (`org/kamranzafar/jtar/`)
115+
116+
**Formatting rules applied:**
117+
118+
- Google Java Format with AOSP style (Android-friendly indentation)
119+
- Removal of unused imports
120+
- Trailing whitespace trimming
121+
- Files end with newline
122+
69123
## Creating a new release
70124

71125
(These instructions are for core developers, not casual contributors.)

Makefile

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,20 @@ virtualenv: $(VIRTUAL_ENV)
2424
test:
2525
$(TOX) -- tests/ --ignore tests/test_pythonpackage.py
2626

27+
# Java linting using Spotless (requires Java 17+, uses Gradle wrapper)
28+
java-lint:
29+
cd pythonforandroid/bootstraps && ./common/build/gradlew spotlessCheck
30+
31+
java-lint-fix:
32+
cd pythonforandroid/bootstraps && ./common/build/gradlew spotlessApply
33+
34+
# Java linting via Docker (no local Java required)
35+
docker/java-lint: docker/build
36+
docker run --rm -v $(CURDIR):/home/user/app -w /home/user/app/pythonforandroid/bootstraps $(DOCKER_IMAGE) ./common/build/gradlew spotlessCheck
37+
38+
docker/java-lint-fix: docker/build
39+
docker run --rm -v $(CURDIR):/home/user/app -w /home/user/app/pythonforandroid/bootstraps $(DOCKER_IMAGE) ./common/build/gradlew spotlessApply
40+
2741
# Also install and configure rust
2842
rebuild_updated_recipes: virtualenv
2943
. $(ACTIVATE) && \

doc/source/apis.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ With Kivy, add an ``on_pause`` method to your App class, which returns True::
140140

141141
With the webview bootstrap, pausing should work automatically.
142142

143-
Under SDL2, you can handle the `appropriate events <https://wiki.libsdl.org/SDL_EventType>`__ (see SDL_APP_WILLENTERBACKGROUND etc.).
143+
Under SDL2, you can handle the `appropriate events <https://wiki.libsdl.org/SDL3/SDL_EventType>`__ (see SDL_APP_WILLENTERBACKGROUND etc.).
144144

145145

146146
Observing Activity result

doc/source/conf.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -321,3 +321,15 @@ def get_version():
321321
r"https://github.com/kivy/python-for-android/blob.*",
322322
]
323323

324+
# Allow redirects for URLs where we prefer to keep the original form
325+
linkcheck_allowed_redirects = {
326+
# Kivy chat redirects to Discord invite
327+
r"https://chat\.kivy\.org/": r"https://discord\.com/.*",
328+
# GitHub archive URLs redirect to codeload
329+
r"https://github\.com/kivy/python-for-android/archive/.*": r"https://codeload\.github\.com/.*",
330+
# GitHub gist homepage redirects to starred
331+
r"https://gist\.github\.com/$": r"https://gist\.github\.com/.*",
332+
# Google Play Store redirects
333+
r"https://play\.google\.com/store/$": r"https://play\.google\.com/store/.*",
334+
}
335+

doc/source/index.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ It can generate:
1818

1919
It supports multiple CPU architectures.
2020

21-
It supports apps developed with `Kivy framework <http://kivy.org>`_, but was
21+
It supports apps developed with `Kivy framework <https://kivy.org/>`_, but was
2222
built to be flexible about the backend libraries (through "bootstraps"), and
2323
also supports `PySDL2 <https://pypi.org/project/PySDL2/>`_, and a
2424
`WebView <https://developer.android.com/reference/android/webkit/WebView>`_ with
@@ -34,7 +34,7 @@ dependencies for Android devices, and bundling it with the app's python code
3434
and dependencies. The Python code is then interpreted on the Android device.
3535

3636
It is recommended that python-for-android be used via
37-
`Buildozer <https://buildozer.readthedocs.io/>`_, which ensures the correct
37+
`Buildozer <https://buildozer.readthedocs.io/en/latest/>`_, which ensures the correct
3838
dependencies are pre-installed, and centralizes the configuration. However,
3939
python-for-android is not limited to being used with Buildozer.
4040

doc/source/services.rst

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,9 +64,15 @@ The ``PATH_TO_SERVICE_PY`` is the relative path to the service entry point (like
6464
You can optionally specify the following parameters:
6565
- :code:`:foreground` for launching a service as an Android foreground service
6666
- :code:`:sticky` for launching a service that gets restarted by the Android OS on exit/error
67+
- :code:`:foregroundServiceType=TYPE` to specify the type of foreground service,
68+
where TYPE is one of the valid Android foreground service types
69+
(see `Android documentation <https://developer.android.com/develop/background-work/services/fgs/service-types>`__
70+
for more details). You can specify multiple types separated by a pipe
71+
character "|", e.g. :code:`:foregroundServiceType=location|mediaPlayback`. Mandatory
72+
if :code:`:foreground` is used on Android 14+.
6773
6874
Full command with all the optional parameters included would be:
69-
:code:`--service=myservice:services/myservice.py:foreground:sticky`
75+
:code:`--service=myservice:services/myservice.py:foreground:sticky:foregroundServiceType=location`
7076

7177
You can add multiple
7278
:code:`--service` arguments to include multiple services, or separate

pythonforandroid/bootstrap.py

Lines changed: 46 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
import shlex
99
import shutil
1010

11-
from pythonforandroid.logger import (shprint, info, logger, debug)
11+
from pythonforandroid.logger import (shprint, info, info_main, logger, debug)
1212
from pythonforandroid.util import (
1313
current_directory, ensure_dir, temp_directory, BuildInterruptingException,
1414
rmdir, move)
@@ -184,11 +184,52 @@ def prepare_build_dir(self):
184184
def prepare_dist_dir(self):
185185
ensure_dir(self.dist_dir)
186186

187+
def _assemble_distribution_for_arch(self, arch):
188+
"""Per-architecture distribution assembly.
189+
190+
Override this method to customize per-arch behavior.
191+
Called once for each architecture in self.ctx.archs.
192+
"""
193+
self.distribute_libs(arch, [self.ctx.get_libs_dir(arch.arch)])
194+
self.distribute_aars(arch)
195+
196+
python_bundle_dir = join(f'_python_bundle__{arch.arch}', '_python_bundle')
197+
ensure_dir(python_bundle_dir)
198+
site_packages_dir = self.ctx.python_recipe.create_python_bundle(
199+
join(self.dist_dir, python_bundle_dir), arch)
200+
if not self.ctx.with_debug_symbols:
201+
self.strip_libraries(arch)
202+
self.fry_eggs(site_packages_dir)
203+
187204
def assemble_distribution(self):
188-
''' Copies all the files into the distribution (this function is
189-
overridden by the specific bootstrap classes to do this)
190-
and add in the distribution info.
191-
'''
205+
"""Assemble the distribution by copying files and creating Python bundle.
206+
207+
This default implementation works for most bootstraps. Override
208+
_assemble_distribution_for_arch() for per-arch customization, or
209+
override this entire method for fundamentally different behavior.
210+
"""
211+
info_main(f'# Creating Android project ({self.name})')
212+
213+
rmdir(self.dist_dir)
214+
shprint(sh.cp, '-r', self.build_dir, self.dist_dir)
215+
216+
with current_directory(self.dist_dir):
217+
with open('local.properties', 'w') as fileh:
218+
fileh.write('sdk.dir={}'.format(self.ctx.sdk_dir))
219+
220+
with current_directory(self.dist_dir):
221+
info('Copying Python distribution')
222+
223+
self.distribute_javaclasses(self.ctx.javaclass_dir,
224+
dest_dir=join("src", "main", "java"))
225+
226+
for arch in self.ctx.archs:
227+
self._assemble_distribution_for_arch(arch)
228+
229+
if 'sqlite3' not in self.ctx.recipe_build_order:
230+
with open('blacklist.txt', 'a') as fileh:
231+
fileh.write('\nsqlite3/*\nlib-dynload/_sqlite3.so\n')
232+
192233
self._copy_in_final_files()
193234
self.distribution.save_info(self.dist_dir)
194235

0 commit comments

Comments
 (0)