Add a background service to your Android app¶
An Android service runs Python code outside your app's user interface, for
example a long download. You declare services in pyproject.toml, and kivyforge
generates a service class and its <service> manifest entry for each one. Each
service runs a Python module of your app in its own process.
Before you begin¶
- Configure your Android app.
- Decide whether the service is a foreground service: long-running work that shows the user a notification while it runs.
Declare a service¶
-
Write the service's code as a module in your app directory, for example
worker.pynext tomain.py. kivyforge runs it the waypython -m workerwould, so__name__is"__main__". -
Add a
[[tool.kivy.android.services]]entry:[[tool.kivy.android.services]] name = "Worker" entry_point = "worker"namemust be a Java identifier; kivyforge generates the classorg.kivy.android.ServiceWorkerfrom it.entry_pointis the Python module name, not a file path. -
For a foreground service, also set a type and the notification it shows:
[[tool.kivy.android.services]] name = "Worker" entry_point = "worker" foreground = true foreground_service_type = "dataSync" notification = { channel_id = "sync", channel_name = "Sync", title = "Syncing", text = "Downloading content" }kivyforge adds the
FOREGROUND_SERVICEpermission and the matching typed permission, hereFOREGROUND_SERVICE_DATA_SYNC. It does not addPOST_NOTIFICATIONS; declare it in[tool.kivy.android.permissions]if your app needs it. For the list of valid types, see the Android overlay reference.The notification uses the app's launcher icon unless you add
icon = "<name>"to thenotificationtable. Android expects a monochrome silhouette there; ship it as a drawable, for exampledrawable/ic_notification.xml, as described in Add Android resources, and seticon = "ic_notification". -
Re-lock, because
pyproject.tomlchanged:kivyforge lock -p android
Start and stop the service from Python¶
Each generated service class has static start and stop methods:
from jnius import autoclass
import android
ServiceWorker = autoclass("org.kivy.android.ServiceWorker")
ServiceWorker.start(android.mActivity, "optional text")
...
ServiceWorker.stop(android.mActivity)
starttakes aContextand an argument string. The service reads the argument from thePYTHON_SERVICE_ARGUMENTenvironment variable.- A foreground service also has a five-argument form,
start(context, small_icon_name, title, text, argument). A non-empty icon name, title or text replaces the notification value frompyproject.tomlfor that run. Pass""to keep the configured value. stopends the service's process, and with it the service's Python code.
Inside the service, PythonService.mService is the running service, which is
the Context to use for Android calls:
from jnius import autoclass
service = autoclass("org.kivy.android.PythonService").mService
print(service.getPackageName())
A service runs in its own process, which has no activity: android.mActivity
is None there.
pyjnius works in a service on every Android version kivyforge supports. The service loads the app's SDL library before Python starts, because that is how pyjnius finds the Java VM. The service creates no window.
Coming from python-for-android¶
start, stop and mService match python-for-android's. Only the class name
changes: python-for-android names the class after your app's package, for
example org.example.myapp.ServiceWorker. kivyforge's class is always
org.kivy.android.Service<name>, with name exactly as written in
pyproject.toml. Change the name in your autoclass call.
setAutoRestartService is not provided.
Verify¶
Run the smoke test on a device or emulator. When a service is declared, the smoke test also starts the first declared service and checks that its Python module imports without error:
kivyforge run -p android --smoke
For a complete app with a background and a foreground service, see
examples/mobile/android-services.
What's next¶
- Call Android APIs with pyjnius from your service code.
- Sign and publish to Google Play.
- Android overlay reference.