Building Gneisswork as an Android APK
Gneisswork can be packaged as a standalone Android APK using Buildozer and Python for Android.
How It Works
The APK bundles:
- Python 3 runtime
- Flask web server
- Kivy (Android bootstrap only)
- All Gneisswork dependencies
- SQLite database
When launched, the app:
- Starts a local Flask server in a background thread on
127.0.0.1:5000 - Polls until the server is ready
- Replaces the Kivy surface with a native Android
WebView(via pyjnius) displaying the Flask UI - Runs completely offline on the device
Automated Builds (GitHub Actions)
The repository includes a GitHub Action workflow (.github/workflows/build-apk.yml) that automatically builds APKs:
Triggers
- Push to main/master: Builds a debug APK
- Pull requests: Builds for testing
- Version tags (
v*): Builds and creates a GitHub release - Manual dispatch: Build on-demand from Actions tab
Artifacts
- Debug APKs are uploaded as workflow artifacts (30-day retention)
- Release APKs are attached to GitHub releases for tagged versions
Build Time
First build: ~30-45 minutes (downloads Android SDK/NDK) Subsequent builds: ~10-15 minutes (with caching)
Local Build (Linux/macOS)
Prerequisites
# Install system dependencies (Ubuntu/Debian)
sudo apt-get update
sudo apt-get install -y \
python3-pip build-essential git \
libsdl2-dev libsdl2-image-dev libsdl2-mixer-dev libsdl2-ttf-dev \
libportmidi-dev libswscale-dev libavformat-dev libavcodec-dev \
zlib1g-dev autoconf automake libtool pkg-config cmake \
openjdk-17-jdk
# Install Buildozer
pip install buildozer cython==3.0.11
Build Commands
# Debug APK (includes debugging symbols, unsigned)
buildozer android debug
# Release APK (optimized, requires signing)
buildozer android release
# Clean build cache (if issues arise)
buildozer android clean
Output APK location: bin/gneisswork-*.apk
Configuration
All build settings are in buildozer.spec:
- App metadata: Name, version, icon
- Requirements: Python packages to include
- Permissions: Android permissions (INTERNET, ACCESS_FINE_LOCATION, ACCESS_COARSE_LOCATION)
- Architecture: Builds for ARM64 and ARMv7 by default
- API levels: Targets Android 14 (API 35), minimum Android 5.0 (API 21)
Custom python-for-android Recipes
The p4a-recipes/ directory contains local recipe overrides for python-for-android. These are referenced via p4a.local_recipes = ./p4a-recipes in buildozer.spec and take precedence over the recipes bundled with p4a.
Currently overridden:
| Recipe | Bundled Version | Local Version | Reason |
|---|---|---|---|
| Flask | 2.0.3 | 3.1.1 | Gneisswork requires Flask 3.0+ |
| SQLAlchemy | 1.3.3 | 2.0.40 | Flask-SQLAlchemy 3.x requires SQLAlchemy 2.0+ |
| Werkzeug | (p4a default) | 3.1.7 | Pinned for Flask 3.x compatibility |
Each recipe is a Python class in p4a-recipes/<package>/__init__.py that extends PythonRecipe. Flask downloads source from GitHub and uses the default PythonRecipe install. Werkzeug and SQLAlchemy bypass the source-based workflow — they override build_arch to pip-install the wheel directly from PyPI into the target site-packages, because their modern versions use pyproject.toml which PythonRecipe cannot handle. If you need to pin or override another dependency for the APK build, add a new recipe following the same pattern.
Installation
From GitHub Actions
- Go to Actions → Build Android APK workflow
- Download the
gneisswork-debug-apkartifact - Extract the
.apkfile - Transfer to Android device
- Enable “Install from Unknown Sources” in Android settings
- Install the APK
From Release
- Go to Releases page
- Download the APK from the latest release
- Install on device
Troubleshooting
Build Fails with “Command failed”
- Check system dependencies are installed
- Try
buildozer android cleanand rebuild - Check
buildozer.specfor typos
APK Crashes on Launch
- Check logs:
adb logcat | grep python - Verify all requirements are listed in
buildozer.spec - Check file permissions in
source.include_patterns
Large APK Size
- Expected size: 50-80 MB (includes Python runtime)
- To reduce: exclude unused packages from requirements
- Use
buildozer android releasefor optimized builds
Database Issues
- The SQLite database is created in private app storage
- Data persists between app restarts
- To reset: clear app data in Android settings
Development Workflow
- Develop and test using
python run.py(desktop Flask) - Commit changes to repository
- Push to trigger automatic APK build
- Download and test APK on device
- Tag release (
git tag v1.0.0) to create public release
Notes
- First build downloads ~2GB of Android SDK/NDK components
- Build cache is stored in
.buildozer/(git-ignored) - The
main.pyfile is the Android entry point (Kivy bootstrap → Flask thread → native Android WebView via pyjnius) - The regular
run.pyis still used for desktop development - WebView requires Android 5.0+ (API 21)