132 lines
5.4 KiB
ReStructuredText
132 lines
5.4 KiB
ReStructuredText
Services
|
|
========
|
|
|
|
python-for-android supports the use of Android Services, background
|
|
tasks running in separate processes. These are the closest Android
|
|
equivalent to multiprocessing on e.g. desktop platforms, and it is not
|
|
possible to use normal multiprocessing on Android. Services are also
|
|
the only way to run code when your app is not currently opened by the user.
|
|
|
|
Services must be declared when building your APK. Each one
|
|
will have its own main.py file with the Python script to be run.
|
|
Please note that python-for-android explicitly runs services as separated
|
|
processes by having a colon ":" in the beginning of the name assigned to
|
|
the ``android:process`` attribute of the ``AndroidManifest.xml`` file.
|
|
This is not the default behavior, see `Android service documentation
|
|
<https://developer.android.com/guide/topics/manifest/service-element>`__.
|
|
You can communicate with the service process from your app using e.g.
|
|
`osc <https://pypi.python.org/pypi/python-osc>`__ or (a heavier option)
|
|
`twisted <https://twistedmatrix.com/trac/>`__.
|
|
|
|
Service creation
|
|
----------------
|
|
|
|
There are two ways to have services included in your APK.
|
|
|
|
Service folder
|
|
~~~~~~~~~~~~~~
|
|
|
|
This is the older method of handling services. It is
|
|
recommended to use the second method (below) where possible.
|
|
|
|
Create a folder named ``service`` in your app directory, and add a
|
|
file ``service/main.py``. This file should contain the Python code
|
|
that you want the service to run.
|
|
|
|
To start the service, use the :code:`start_service` function from the
|
|
:code:`android` module (you may need to add ``android`` to your app
|
|
requirements)::
|
|
|
|
import android
|
|
android.start_service(title='service name',
|
|
description='service description',
|
|
arg='argument to service')
|
|
|
|
.. _arbitrary_scripts_services:
|
|
|
|
Arbitrary service scripts
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
This method is recommended for non-trivial use of services as it is
|
|
more flexible, supporting multiple services and a wider range of
|
|
options.
|
|
|
|
To create the service, create a python script with your service code
|
|
and add a :code:`--service=myservice:PATH_TO_SERVICE_PY` argument
|
|
when calling python-for-android, or in buildozer.spec, a
|
|
:code:`services = myservice:PATH_TO_SERVICE_PY` [app] setting.
|
|
|
|
The ``myservice`` name before the colon is the name of the service
|
|
class, via which you will interact with it later.
|
|
|
|
The ``PATH_TO_SERVICE_PY`` is the relative path to the service entry point (like ``services/myservice.py``)
|
|
|
|
You can optionally specify the following parameters:
|
|
- :code:`:foreground` for launching a service as an Android foreground service
|
|
- :code:`:sticky` for launching a service that gets restarted by the Android OS on exit/error
|
|
|
|
Full command with all the optional parameters included would be:
|
|
:code:`--service=myservice:services/myservice.py:foreground:sticky`
|
|
|
|
You can add multiple
|
|
:code:`--service` arguments to include multiple services, or separate
|
|
them with a comma in buildozer.spec, all of which you will later be
|
|
able to stop and start from your app.
|
|
|
|
To run the services (i.e. starting them from within your main app
|
|
code), you must use PyJNIus to interact with the java class
|
|
python-for-android creates for each one, as follows::
|
|
|
|
from jnius import autoclass
|
|
service = autoclass('your.package.domain.package.name.ServiceMyservice')
|
|
mActivity = autoclass('org.kivy.android.PythonActivity').mActivity
|
|
argument = ''
|
|
service.start(mActivity, argument)
|
|
|
|
Here, ``your.package.domain.package.name`` refers to the package identifier
|
|
of your APK.
|
|
|
|
If you are using buildozer, the identifier is set by the ``package.name``
|
|
and ``package.domain`` values in your buildozer.spec file.
|
|
The name of the service is ``ServiceMyservice``, where ``Myservice``
|
|
is the name specied by one of the ``services`` values, but with the first
|
|
letter upper case.
|
|
|
|
If you are using python-for-android directly, the identifier is set by the ``--package``
|
|
argument to python-for-android. The name of the service is ``ServiceMyservice``,
|
|
where ``Myservice`` is the identifier that was previously passed to the ``--service``
|
|
argument, but with the first letter upper case. You must also pass the
|
|
``argument`` parameter even if (as here) it is an empty string. If you
|
|
do pass it, the service can make use of this argument.
|
|
|
|
The service argument is made available to your service via the
|
|
'PYTHON_SERVICE_ARGUMENT' environment variable. It is exposed as a simple
|
|
string, so if you want to pass in multiple values, we would recommend using
|
|
the json module to encode and decode more complex data.
|
|
::
|
|
|
|
from os import environ
|
|
argument = environ.get('PYTHON_SERVICE_ARGUMENT', '')
|
|
|
|
Services support a range of options and interactions not yet
|
|
documented here but all accessible via calling other methods of the
|
|
``service`` reference.
|
|
|
|
.. note::
|
|
|
|
The app root directory for Python imports will be in the app
|
|
root folder even if the service file is in a subfolder. To import from
|
|
your service folder you must use e.g. ``import service.module``
|
|
instead of ``import module``, if the service file is in the
|
|
``service/`` folder.
|
|
|
|
Service auto-restart
|
|
~~~~~~~~~~~~~~~~~~~~
|
|
|
|
It is possible to make services restart automatically when they exit by
|
|
calling ``setAutoRestartService(True)`` on the service object.
|
|
The call to this method should be done within the service code::
|
|
|
|
from jnius import autoclass
|
|
PythonService = autoclass('org.kivy.android.PythonService')
|
|
PythonService.mService.setAutoRestartService(True)
|