Python For Android
Python For Android
Release 0.1
Alexander Taylor
1 Contents 3
1.1 Getting Started . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
1.2 Build options . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
1.3 Commands . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
1.4 Working on Android . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
1.5 Launcher . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
1.6 distutils/setuptools integration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
1.7 Recipes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
1.8 Bootstraps . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
1.9 Services . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
1.10 Troubleshooting . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
1.11 Docker . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
1.12 Development and Contributing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
i
ii
python-for-android Documentation, Release 0.1
python-for-android is an open source build tool to let you package Python code into standalone android APKs. These
can be passed around, installed, or uploaded to marketplaces such as the Play Store just like any other Android
app. This tool was originally developed for the Kivy cross-platform graphical framework, but now supports multiple
bootstraps and can be easily extended to package other types of Python apps for Android.
python-for-android supports two major operations; first, it can compile the Python interpreter, its dependencies, back-
end libraries and python code for Android devices. This stage is fully customisable: you can install as many or few
components as you like. The result is a standalone Android project which can be used to generate any number of
different APKs, even with different names, icons, Python code etc. The second function of python-for-android is to
provide a simple interface to these distributions, to generate from such a project a Python APK with build parameters
and Python code to taste.
Contents 1
python-for-android Documentation, Release 0.1
2 Contents
CHAPTER 1
Contents
Getting up and running on python-for-android (p4a) is a simple process and should only take you a couple of minutes.
We’ll refer to Python for android as p4a in this documentation.
1.1.1 Concepts
• requirements: For p4a, your applications dependencies are requirements similar to the standard requirements.txt,
but with one difference: p4a will search for a recipe first instead of installing requirements with pip.
• recipe: A recipe is a file that defines how to compile a requirement. Any libraries that have a Python extension
must have a recipe in p4a, or compilation will fail. If there is no recipe for a requirement, it will be downloaded
using pip.
• build: A build refers to a compiled recipe.
• distribution: A distribution is the final “build” of all your compiled requirements, as an Android project that can
be turned directly into an APK. p4a can contain multiple distributions with different sets of requirements.
• bootstrap: A bootstrap is the app backend that will start your application. Your application could use SDL2 as
a base, or a web backend like Flask with a WebView bootstrap. Different bootstraps can have different build
options.
1.1.2 Installation
Installing p4a
You can also test the master branch from Github using:
3
python-for-android Documentation, Release 0.1
Installing Dependencies
˓→autoconf libtool
On Arch Linux (64 bit) you should be able to run the following to install most of the dependencies (note: this list
may not be complete). gcc-multilib will conflict with (and replace) gcc if not already installed. If your installation is
already 32-bit, install the same packages but without lib32- or -multilib:
˓→libs-multilib
You need to download and unpack the Android SDK and NDK to a directory (let’s say $HOME/Documents/):
• Android SDK
• Android NDK
For the Android SDK, you can download ‘just the command line tools’. When you have extracted these you’ll see
only a directory named tools, and you will need to run extra commands to install the SDK packages needed.
For Android NDK, note that modern releases will only work on a 64-bit operating system. The minimal, and recom-
mended, NDK version to use is r17c:
4 Chapter 1. Contents
python-for-android Documentation, Release 0.1
First, install an API platform to target. You can replace 27 with a different platform number, but keep in mind other
API versions are less well-tested, and older devices are still supported (down to the specified minimum API/NDK
API level):
$SDK_DIR/tools/bin/sdkmanager “platforms;android-27”
Second, install the build-tools. You can use $SDK_DIR/tools/bin/sdkmanager --list to see all the possi-
bilities, but 26.0.2 is the latest version at the time of writing:
$SDK_DIR/tools/bin/sdkmanager "build-tools;26.0.2"
Then, you can edit your ~/.bashrc or other favorite shell to include new environment variables necessary for
building on android:
You have the possibility to configure on any command the PATH to the SDK, NDK and Android API using:
• --sdk-dir PATH as an equivalent of $ANDROIDSDK
• --ndk-dir PATH as an equivalent of $ANDROIDNDK
• --android-api VERSION as an equivalent of $ANDROIDAPI
• --ndk-api VERSION as an equivalent of $NDKAPI
• --ndk-version VERSION as an equivalent of $ANDROIDNDKVER
1.1.3 Usage
To build your application, you need to specify name, version, a package identifier, the bootstrap you want to use (sdl2
for kivy or sdl2 apps) and the requirements:
Note on ‘–requirements‘: you must add all libraries/dependencies your app needs to run. Example: –require-
ments=python3,kivy,vispy. For an SDL2 app, kivy is not needed, but you need to add any wrappers you might use (e.g.
pysdl2).
This p4a apk . . . command builds a distribution with python3, kivy, and everything else you specified in the require-
ments. It will be packaged using a SDL2 bootstrap, and produce an .apk file.
Compatibility notes:
• While python2 is still supported by python-for-android, it will possibly no longer receive patches by the python
creators themselves in 2020. Migration to Python 3 is recommended!
• You can also use --bootstrap=pygame, but this bootstrap is deprecated and not well-tested.
To build your application, you need to have a name, version, a package identifier, and explicitly use the webview
bootstrap, as well as the requirements:
Please note as with kivy/SDL2, you need to specify all your additional requirements/depenencies.
You can also replace flask with another web framework.
Replace --port=5000 with the port on which your app will serve a website. The default for Flask is 5000.
Other options
You can pass other command line arguments to control app behaviours such as orientation, wakelock and app permis-
sions. See Bootstrap options.
Rebuild everything
If anything goes wrong and you want to clean the downloads and builds to retry everything, run:
p4a clean_all
If you just want to clean the builds to avoid redownloading dependencies, run:
Getting help
If something goes wrong and you don’t know how to fix it, add the --debug option and post the output log to the
kivy-users Google group or the kivy #support Discord channel.
See Troubleshooting for more information.
6 Chapter 1. Contents
python-for-android Documentation, Release 0.1
Recipe management
p4a recipes
If you are contributing to p4a and want to test a recipes again, you need to clean the build and rebuild your distribution:
You can write “private” recipes for your application, just create a p4a-recipes folder in your build directory, and
place a recipe in it (edit the __init__.py):
mkdir -p p4a-recipes/myrecipe
touch p4a-recipes/myrecipe/__init__.py
Distribution management
Every time you start a new project, python-for-android will internally create a new distribution (an Android build
project including Python and your other dependencies compiled for Android), according to the requirements you
added on the command line. You can force the reuse of an existing distribution by adding:
This will ensure your distribution will always be built in the same directory, and avoids using more disk space every
time you adjust a requirement.
You can list the available distributions:
p4a distributions
p4a clean_dists
Configuration file
python-for-android checks in the current directory for a configuration file named .p4a. If found, it adds all the lines
as options to the command line. For example, you can add the options you would always include such as:
--dist_name my_example
--android_api 27
--requirements kivy,openssl
You can override the source of any recipe using the $P4A_recipename_DIR environment variable. For instance,
to test your own Kivy branch you might set:
export P4A_kivy_DIR=/home/username/kivy
The specified directory will be copied into python-for-android instead of downloading from the normal url specified
in the recipe.
If your application is also packaged for desktop using setup.py, you may want to use your setup.py instead of the
--requirements option to avoid specifying things twice. For that purpose, check out distutils/setuptools integra-
tion
Going further
See the other pages of this doc for more information on specific topics:
• Build options
• Commands
• Recipes
• Bootstraps
• Working on Android
• Troubleshooting
• Launcher
• Development and Contributing
python2
python3
Python3 is supported in two ways. The default method uses CPython 3.7+ and works with any recent version of the
Android NDK.
Select Python 3 by adding it to your requirements, e.g. --requirements=python3.
8 Chapter 1. Contents
python-for-android Documentation, Release 0.1
Note: ctypes is not included automatically, if you would like to use it then add libffi to your requirements, e.g.
--requirements=kivy,libffi,python3.
CrystaX python3
Warning: python-for-android originally supported Python 3 using the CrystaX NDK. This support is now being
phased out as CrystaX is no longer actively developed.
Note: You must manually download the CrystaX NDK and tell python-for-android to use it with --ndk-dir
/path/to/NDK.
python-for-android supports multiple app backends with different types of interface. These are called bootstraps.
Currently the following bootstraps are supported, but we hope that it should be easy to add others if your project has
different requirements. Let us know if you’d like help adding a new one.
sdl2
Use this with --bootstrap=sdl2, or just include the sdl2 recipe, e.g. --requirements=sdl2,python2.
SDL2 is a popular cross-platform depelopment library, particularly for games. It has its own Android project support,
which python-for-android uses as a bootstrap, and to which it adds the Python build and JNI code to start it.
From the point of view of a Python program, SDL2 should behave as normal. For instance, you can build apps with
Kivy or PySDL2 and have them work with this bootstrap. It should also be possible to use e.g. pygame_sdl2, but this
would need a build recipe and doesn’t yet have one.
The sdl2 bootstrap supports the following additional command line options (this list may not be exhaustive):
• --private: The directory containing your project files.
• --package: The Java package name for your project. e.g. org.example.yourapp.
• --name: The app name.
• --version: The version number.
• --orientation: Usually one of portait, landscape, sensor to automatically rotate according to the
device orientation, or user to do the same but obeying the user’s settings. The full list of valid options is given
under android:screenOrientation in the Android documentation.
• --icon: A path to the png file to use as the application icon.
• --permission: A permission name for the app, e.g. --permission VIBRATE. For multiple permis-
sions, add multiple --permission arguments.
• --meta-data: Custom key=value pairs to add in the application metadata.
• --presplash: A path to the image file to use as a screen while the application is loading.
• --presplash-color: The presplash screen background color, of the form #RRGGBB or a color name red,
green, blue etc.
• --wakelock: If the argument is included, the application will prevent the device from sleeping.
• --window: If the argument is included, the application will not cover the Android status bar.
• --blacklist: The path to a file containing blacklisted patterns that will be excluded from the final APK.
Defaults to ./blacklist.txt.
• --whitelist: The path to a file containing whitelisted patterns that will be included in the APK even if also
blacklisted.
• --add-jar: The path to a .jar file to include in the APK. To include multiple jar files, pass this argument
multiple times.
• --intent-filters: A file path containing intent filter xml to be included in AndroidManifest.xml.
• --service: A service name and the Python script it should run. See Arbitrary service scripts.
• --add-source: Add a source directory to the app’s Java code.
• --no-compile-pyo: Do not optimise .py files to .pyo.
webview
You can use this with --bootstrap=webview, or include the webviewjni recipe, e.g.
--requirements=webviewjni,python2.
The webview bootstrap gui is, per the name, a WebView displaying a webpage, but this page is hosted on the device
via a Python webserver. For instance, your Python code can start a Flask application, and your app will display and
allow the user to navigate this website.
Note: Your Flask script must start the webserver without :code:debug=True. Debug mode doesn’t seem to work
on Android due to use of a subprocess.
This bootstrap will automatically try to load a website on port 5000 (the default for Flask), or you can specify a
different option with the –port command line option. If the webserver is not immediately present (e.g. during the short
Python loading time when first started), it will instead display a loading screen until the server is ready.
• --private: The directory containing your project files.
• --package: The Java package name for your project. e.g. org.example.yourapp.
• --name: The app name.
• --version: The version number.
• --orientation: Usually one of portait, landscape, sensor to automatically rotate according to the
device orientation, or user to do the same but obeying the user’s settings. The full list of valid options is given
under android:screenOrientation in the Android documentation.
• --icon: A path to the png file to use as the application icon.
10 Chapter 1. Contents
python-for-android Documentation, Release 0.1
• -- permission: A permission name for the app, e.g. --permission VIBRATE. For multiple permis-
sions, add multiple --permission arguments.
• --meta-data: Custom key=value pairs to add in the application metadata.
• --presplash: A path to the image file to use as a screen while the application is loading.
• --presplash-color: The presplash screen background color, of the form #RRGGBB or a color name red,
green, blue etc.
• --wakelock: If the argument is included, the application will prevent the device from sleeping.
• --window: If the argument is included, the application will not cover the Android status bar.
• --blacklist: The path to a file containing blacklisted patterns that will be excluded from the final APK.
Defaults to ./blacklist.txt.
• --whitelist: The path to a file containing whitelisted patterns that will be included in the APK even if also
blacklisted.
• --add-jar: The path to a .jar file to include in the APK. To include multiple jar files, pass this argument
multiple times.
• --intent-filters: A file path containing intent filter xml to be included in AndroidManifest.xml.
• --service: A service name and the Python script it should run. See Arbitrary service scripts.
• add-source: Add a source directory to the app’s Java code.
• --port: The port on localhost that the WebView will access. Defaults to 5000.
The sdl2 bootstrap supports the following additional command line options (this list may not be exhaustive):
• --private: The directory containing your project files.
• --dir: The directory containing your project files if you want them to be unpacked to the external storage
directory rather than the app private directory.
• --package: The Java package name for your project. e.g. org.example.yourapp.
• --name: The app name.
• --version: The version number.
• --orientation: One of portait, landscape or sensor to automatically rotate according to the device
orientation.
• --icon: A path to the png file to use as the application icon.
• --ignore-path: A path to ignore when including the app files. Pass multiple times to ignore multiple paths.
• -- permission: A permission name for the app, e.g. --permission VIBRATE. For multiple permis-
sions, add multiple --permission arguments.
• --meta-data: Custom key=value pairs to add in the application metadata.
• --presplash: A path to the image file to use as a screen while the application is loading.
• --wakelock: If the argument is included, the application will prevent the device from sleeping.
• --window: If the argument is included, the application will not cover the Android status bar.
• --blacklist: The path to a file containing blacklisted patterns that will be excluded from the final APK.
Defaults to ./blacklist.txt.
• --whitelist: The path to a file containing whitelisted patterns that will be included in the APK even if also
blacklisted.
• --add-jar: The path to a .jar file to include in the APK. To include multiple jar files, pass this argument
multiple times.
• --intent-filters: A file path containing intent filter xml to be included in AndroidManifest.xml.
• --service: A service name and the Python script it should run. See Arbitrary service scripts.
• add-source: Add a source directory to the app’s Java code.
• --compile-pyo: Optimise .py files to .pyo.
• --resource: A key=value pair to add in the string.xml resource file.
To optimize the size of the .apk file that p4a builds for you, you can blacklist certain core components. Per default,
p4a will add python with batteries included as would be expected on desktop, including openssl, sqlite3 and other
components you may not use.
To blacklist an item, specify the --blacklist-requirements option:
At the moment, the following core components can be blacklisted (if you don’t want to use them) to decrease APK
size:
• android disables p4a’s android module (see android for Android API access)
• libffi disables ctypes stdlib module
• openssl disables ssl stdlib module
• sqlite3 disables sqlite3 stdlib module
1.3 Commands
This page documents all the commands and options that can be passed to toolchain.py.
The commands available are the methods of the ToolchainCL class, documented below. They may have options of
their own, or you can always pass general arguments or distribution arguments to any command (though if irrelevant
they may not have an effect).
These arguments may be passed to any command in order to modify its behaviour, though not all commands make use
of them.
--debug Print extra debug information about the build, including all compilation output.
--sdk_dir The filepath where the Android SDK is installed. This can alternatively be set in several other ways.
--android_api The Android API level to target; python-for-android will check if the platform tools for this level
are installed.
--ndk_dir The filepath where the Android NDK is installed. This can alternatively be set in several other ways.
12 Chapter 1. Contents
python-for-android Documentation, Release 0.1
--ndk_version The version of the NDK installed, important because the internal filepaths to build tools depend
on this. This can alternatively be set in several other ways, or if your NDK dir contains a RELEASE.TXT
containing the version this is automatically checked so you don’t need to manually set it.
p4a supports several arguments used for specifying which compiled Android distribution you want to use. You may
pass any of these arguments to any command, and if a distribution is required they will be used to load, or compile, or
download this as necessary.
None of these options are essential, and in principle you need only supply those that you need.
--name NAME The name of the distribution. Only one distribution with a given name can be created.
--requirements LIST,OF,REQUIREMENTS The recipes that your distribution must contain, as a comma sep-
arated list. These must be names of recipes or the pypi names of Python modules.
--force-build BOOL Whether the distribution must be compiled from scratch.
--arch The architecture to build for. Currently only one architecture can be targeted at a time, and a given distribu-
tion can only include one architecture.
--bootstrap BOOTSTRAP The Java bootstrap to use for your application. You mostly don’t need to worry about
this or set it manually, as an appropriate bootstrap will be chosen from your --requirements. Current
choices are sdl2 (used with Kivy and most other apps) or webview.
Note: These options are preliminary. Others will include toggles for allowing downloads, and setting additional
directories from which to load user dists.
This page gives details on accessing Android APIs and managing other interactions on Android.
With API level >= 21, you will need to request runtime permissions to access the SD card, the camera, and other
things.
This can be done through the android module which is available per default unless you blacklist it. Use it in your app
like this:
With the SDL2 bootstrap, the app’s splash screen may be visible longer than necessary (with your app already being
loaded) due to a limitation with the way we check if the app has properly started. In this case, the splash screen
overlaps the app gui for a short time.
To dismiss the loading screen explicitely in your code, use the android module:
You can call it e.g. using kivy.clock.Clock.schedule_once to run it in the first active frame of your app, or
use the app build method.
Android phones always have a back button, which users expect to perform an appropriate in-app function. If you do
not handle it, Kivy apps will actually shut down and appear to have crashed.
In SDL2 bootstraps, the back button appears as the escape key (keycode 27, codepoint 270). You can handle this key
to perform actions when it is pressed.
For instance, in your App class in Kivy:
class YourApp(App):
def build(self):
Window.bind(on_keyboard=self.key_input)
return Widget() # your root widget here as normal
When the user leaves an App, it is automatically paused by Android, although it gets a few seconds to store data etc.
if necessary. Once paused, there is no guarantee that your app will run again.
With Kivy, add an on_pause method to your App class, which returns True:
def on_pause(self):
return True
14 Chapter 1. Contents
python-for-android Documentation, Release 0.1
As mentioned above, the android Python module provides a simple wrapper around many native Android APIS,
and it is included by default unless you blacklist it.
The available functionality of this module is not separately documented. You can read the source on Github.
Also please note you can replicate most functionality without it using pyjnius. (see below)
Plyer provides a more thorough wrapper than android for a much larger area of platform-specific APIs, supporting not
only Android but also iOS and desktop operating systems. (Though plyer is a work in progress and not all platforms
support all Plyer calls yet)
Plyer does not support all APIs yet, but you can always use Pyjnius to call anything that is currently missing.
You can include Plyer in your APKs by adding the Plyer recipe to your build requirements, e.g.
--requirements=plyer.
You should check the Plyer documentation for details of all supported facades (platform APIs), but as an example the
following is how you would achieve vibration as described in the Pyjnius section above:
Pyjnius lets you call the Android API directly from Python Pyjnius is works by dynamically wrapping Java classes, so
you don’t have to wait for any particular feature to be pre-supported.
This is particularly useful when android and plyer don’t already provide a convenient access to the API, or you need
more control.
You can include Pyjnius in your APKs by adding pyjnius to your build requirements, e.g.
--requirements=flask,pyjnius. It is automatically included in any APK containing Kivy, in which
case you don’t need to specify it manually.
The basic mechanism of Pyjnius is the autoclass command, which wraps a Java class. For instance, here is the code
to vibrate your device:
activity = PythonActivity.mActivity
Context = autoclass('android.content.Context')
vibrator = activity.getSystemService(Context.VIBRATOR_SERVICE)
1.5 Launcher
The Kivy Launcher is an Android application that can run any Kivy app stored in the kivy folder on the SD Card. You
can download the latest stable version for your android device from the Play Store.
The stable launcher comes with various Python packages and permissions, usually listed in the description in the store.
Those aren’t always enough for an application to run or even launch if you work with other dependencies that are not
packaged.
The Kivy Launcher is intended for quick and simple testing. For anything more advanced we recommend building
your own APK with python-for-android.
1.5.1 Building
The Kivy Launcher is built using python-for-android. To get the most recent versions of packages you need to clean
them first, so that the packager won’t grab an old (cached) package instead of a fresh one.
Note: –minsdk 13 is necessary for the new toolchain, otherwise you’ll be able to run apps only in landscape orienta-
tion.
Warning: Do not use any of –private, –public, –dir or other arguments for adding main.py or main.pyo to the
app. The argument –launcher is above them and tells the p4a to build the launcher version of the APK.
16 Chapter 1. Contents
python-for-android Documentation, Release 0.1
1.5.2 Usage
Once the launcher is installed, you need to create a folder in your external storage directory (e.g. /storage/
emulated/0 or /sdcard) - this is normally your ‘home’ directory in a file browser. Each new folder inside kivy
represents a separate application:
/sdcard/kivy/<yourapplication>
Each application folder must contain an android.txt file. The file has to contain three basic lines:
title=<Application Title>
author=<Your Name>
orientation=<portrait|landscape>
The file is editable so you can change for example orientation or name. These are the only options dynamically
configurable here, although when the app runs you can call the Android API with PyJNIus to change other settings.
After you set your android.txt file, you can now run the launcher and start any available app from the list.
To differentiate between apps in /sdcard/kivy, you can include an icon named icon.png in the folder. The icon
should be a square.
Launcher is released on Google Play with each new Kivy stable branch. The master branch is not suitable for a regular
user because it changes quickly and needs testing.
If you feel confident, feel free to improve the launcher. You can find the source code at |renpy|_ or at |kivy|_.
If your project has a setup.py file, then it can be executed by p4a when your app is packaged such that your app
properly ends up in the packaged site-packages. (Use --use-setup-py to enable this, --ignore-setup-py
to prevent it)
This is functionality to run setup.py INSIDE ‘p4a apk‘, as opposed to the other section below, which is about running
p4a inside setup.py.
This however has these caveats:
• Only your ‘‘main.py‘‘ from your app’s ‘‘–private‘‘ data is copied into the .apk! Everything else needs to
be installed by your setup.py into the site-packages, or it won’t be packaged.
• All dependencies that map to recipes can only be pinned to exact versions, all other constraints will either just
plain not work or even cause build errors. (Sorry, our internal processing is just not smart enough to honor them
properly at this point)
• If you don’t use Python 3 per default, you still need to specify --requirements python2 (without any
additional dependencies)
• The dependency analysis at the start may be quite slow and delay your build
Reasons why you would want to use a setup.py to be processed (and omit specifying --requirements):
• You want to use a more standard mechanism to specify dependencies instead of --requirements
• You already use a setup.py for other platforms
• Your application imports itself in a way that won’t work unless installed to site-packages)
Reasons not to use a setup.py (that is to use the usual --requirements mechanism instead):
• You don’t use a setup.py yet, and prefer the simplicity of just specifying --requirements
• Your setup.py assumes a desktop platform and pulls in Android-incompatible dependencies, and you are not
willing to change this, or you want to keep it separate from Android deployment for other organizational reasons
• You need data files to be around that aren’t installed by your setup.py into the site-packages folder
Instead of running p4a via the command line, you can call it via setup.py instead, by it integrating with distutils and
setup.py.
This is functionality to run p4a INSIDE setup.py, as opposed to the other section above, which is about running
setup.py inside ‘p4a apk‘.
The base command is:
The files included in the APK will be all those specified in the package_data argument to setup. For instance, the
following example will include all .py and .png files in the testapp folder:
setup(
name='testapp_setup',
version='1.1',
description='p4a setup.py example',
author='Your Name',
author_email='youremail@address.com',
packages=find_packages(),
options=options,
package_data={'testapp': ['*.py', '*.png']}
)
The app name and version will also be read automatically from the setup.py.
The Android package name uses org.test.lowercaseappname if not set explicitly.
The --private argument is set automatically using the package_data. You should not set this manually.
The target architecture defaults to --armeabi.
All of these automatic arguments can be overridden by passing them manually on the command line, e.g.:
18 Chapter 1. Contents
python-for-android Documentation, Release 0.1
Instead of providing extra arguments on the command line, you can store them in setup.py by passing the options
parameter to setup. For instance:
options = {'apk': {'debug': None, # use None for arguments that don't pass a value
'requirements': 'sdl2,pyjnius,kivy,python2',
'android-api': 19,
'ndk-dir': '/path/to/ndk',
'dist-name': 'bdisttest',
}}
packages = find_packages()
print('packages are', packages)
setup(
name='testapp_setup',
version='1.1',
description='p4a setup.py example',
author='Your Name',
author_email='youremail@address.com',
packages=find_packages(),
options=options,
package_data={'testapp': ['*.py', '*.png']}
)
These options will be automatically included when you run python setup.py apk. Any options passed on the
command line will override these values.
You can also provide p4a arguments in the setup.cfg file, as normal for distutils. The syntax is:
[apk]
argument=value
requirements=sdl2,kivy
1.7 Recipes
This page describes how python-for-android (p4a) compilation recipes work, and how to build your own. If you just
want to build an APK, ignore this and jump straight to the Getting Started.
Recipes are special scripts for compiling and installing different programs (including Python modules) into a p4a
distribution. They are necessary to take care of compilation for any compiled components, as these must be compiled
for Android with the correct architecture.
python-for-android comes with many recipes for popular modules. No recipe is necessary for Python modules which
have no compiled components; these are installed automatically via pip. If you are new to building recipes, it is
recommended that you first read all of this page, at least up to the Recipe reference documentation. The different
recipe sections include a number of examples of how recipes are built or overridden for specific purposes.
1.7. Recipes 19
python-for-android Documentation, Release 0.1
The formal reference documentation of the Recipe class can be found in the Recipe class section and below.
Check the recipe template section for a template that combines all of these ideas, in which you can replace whichever
components you like.
The basic declaration of a recipe is as follows:
class YourRecipe(Recipe):
url = 'http://example.com/example-{version}.tar.gz'
version = '2.0.3'
md5sum = '4f3dc9a9d857734a488bcbefd9cd64ed'
recipe = YourRecipe()
See the Recipe class documentation for full information about each parameter.
These core options are vital for all recipes, though the url may be omitted if the source is somehow loaded from
elsewhere.
You must include recipe = YourRecipe(). This variable is accessed when the recipe is imported.
Note: The url includes the {version} tag. You should only access the url with the versioned_url property,
which replaces this with the version attribute.
The actual build process takes place via three core methods:
These methods are always run in the listed order; prebuild, then build, then postbuild.
If you defined a url for your recipe, you do not need to manually download it, this is handled automatically.
The recipe will automatically be built in a special isolated build directory, which you can access with self.
get_build_dir(arch.arch). You should only work within this directory. It may be convenient to use the
current_directory context manager defined in toolchain.py:
20 Chapter 1. Contents
python-for-android Documentation, Release 0.1
The argument to each method, arch, is an object relating to the architecture currently being built for. You can mostly
ignore it, though may need to use the arch name arch.arch.
Note: You can also implement arch-specific versions of each method, which are called (if they exist) by the superclass,
e.g. def prebuild_armeabi(self, arch).
This is the core of what’s necessary to write a recipe, but has not covered any of the details of how one actually writes
code to compile for android. This is covered in the next sections, including the standard mechanisms used as part of
the build, and the details of specific recipe classes for Python, Cython, and some generic compiled recipes. If your
module is one of the latter, you should use these later classes rather than reimplementing the functionality from scratch.
You can easily apply patches to your recipes by adding them to the patches declaration, e.g.:
patches = ['some_fix.patch',
'another_fix.patch']
The paths should be relative to the recipe file. Patches are automatically applied just once (i.e. not reapplied the second
time python-for-android is run).
You can also use the helper functions in pythonforandroid.patching to apply patches depending on certain
conditions, e.g.:
from pythonforandroid.patching import will_build, is_arch
...
class YourRecipe(Recipe):
...
You can include your own conditions by passing any function as the second entry of the tuple. It will receive the arch
(e.g. x86, armeabi) and recipe (i.e. the Recipe object) as kwargs. The patch will be applied only if the function
returns True.
Installing libs
Some recipes generate .so files that must be manually copied into the android project. You can use code like the
following to accomplish this, copying to the correct lib cache dir:
def build_arch(self, arch):
do_the_build() # e.g. running ./configure and make
1.7. Recipes 21
python-for-android Documentation, Release 0.1
Any libs copied to this dir will automatically be included in the appropriate libs dir of the generated android project.
When performing any compilation, it is vital to do so with appropriate environment variables set, ensuring that the
Android libraries are properly linked and the compilation target is the correct architecture.
You can get a dictionary of appropriate environment variables with the get_recipe_env method. You should make
sure to set this environment for any processes that you call. It is convenient to do this using the sh module as follows:
You can also use the shprint helper function from the p4a toolchain module, which will print information about the
process and its current status:
You can also override the get_recipe_env method to add new env vars for use in your recipe. For instance, the
Kivy recipe does the following when compiling for SDL2, in order to tell Kivy what backend to use:
env['KIVY_SDL2_PATH'] = ':'.join([
join(self.ctx.bootstrap.build_dir, 'jni', 'SDL', 'include'),
join(self.ctx.bootstrap.build_dir, 'jni', 'SDL2_image'),
join(self.ctx.bootstrap.build_dir, 'jni', 'SDL2_mixer'),
join(self.ctx.bootstrap.build_dir, 'jni', 'SDL2_ttf'),
])
return env
Warning: When using the sh module like this the new env completely replaces the normal environment, so you
must define any env vars you want to access.
The Recipe class has a should_build method, which returns a boolean. This is called for each architecture before
running build_arch, and if it returns False then the build is skipped. This is useful to avoid building a recipe more
than once for different dists.
22 Chapter 1. Contents
python-for-android Documentation, Release 0.1
By default, should_build returns True, but you can override it however you like. For instance, PythonRecipe and its
subclasses all replace it with a check for whether the recipe is already installed in the Python distribution:
If your recipe is to install a Python module without compiled components, you should use a PythonRecipe. This
overrides build_arch to automatically call the normal python setup.py install with an appropriate en-
vironment.
For instance, the following is all that’s necessary to create a recipe for the Vispy module:
site_packages_name = 'vispy'
recipe = VispyRecipe()
The site_packages_name is a new attribute that identifies the folder in which the module will be installed in the
Python package. This is only essential to add if the name is different to the recipe name. It is used to check if the
recipe installation can be skipped, which is the case if the folder is already present in the Python installation.
For reference, the code that accomplishes this is the following:
def install_python_package(self):
'''Automate the installation of a Python package (or a cython
package where the cython components are pre-built).'''
arch = self.filtered_archs[0]
env = self.get_recipe_env(arch)
with current_directory(self.get_build_dir(arch.arch)):
hostpython = sh.Command(self.ctx.hostpython)
This combines techniques and tools from the above documentation to create a generic mechanism for all Python
modules.
1.7. Recipes 23
python-for-android Documentation, Release 0.1
Note: The hostpython is the path to the Python binary that should be used for any kind of installation. You must run
Python in a similar way if you need to do so in any of your own recipes.
If your recipe is to install a Python module that uses Cython, you should use a CythonRecipe. This overrides
build_arch to both build the cython components and to install the Python module just like a normal PythonRecipe.
For instance, the following is all that’s necessary to make a recipe for Kivy:
class KivyRecipe(CythonRecipe):
version = 'stable'
url = 'https://github.com/kivy/kivy/archive/{version}.zip'
name = 'kivy'
recipe = KivyRecipe()
The failing build and manual cythonisation is necessary, firstly to make sure that any .pyx files have been generated by
setup.py, and secondly because cython isn’t installed in the hostpython build.
This may actually fail if the setup.py tries to import cython before making any .pyx files (in which case it crashes too
early), although this is probably not usually an issue. If this happens to you, try patching to remove this import or
24 Chapter 1. Contents
python-for-android Documentation, Release 0.1
This is similar to a CythonRecipe but is intended for modules like numpy which include compiled but non-cython
components. It uses a similar mechanism to compile with the right environment.
This isn’t documented yet because it will probably be changed so that CythonRecipe inherits from it (to avoid code
duplication).
If you are writing a recipe not for a Python module but for something that would normally go in the JNI dir of an
Android project (i.e. it has an Application.mk and Android.mk that the Android build system can use), you
can use an NDKRecipe to automatically set it up. The NDKRecipe overrides the normal get_build_dir method
to place things in the Android project.
Warning: The NDKRecipe does not currently actually call ndk-build, you must add this call (for your module)
by manually making a build_arch method. This may be fixed later.
For instance, the following recipe is all that’s necessary to place SDL2_ttf in the jni dir. This is built later by the SDL2
recipe, which calls ndk-build with this as a dependency:
class LibSDL2TTF(NDKRecipe):
version = '2.0.12'
url = 'https://www.libsdl.org/projects/SDL_ttf/release/SDL2_ttf-{version}.tar.gz'
dir_name = 'SDL2_ttf'
recipe = LibSDL2TTF()
The dir_name argument is a new class attribute that tells the recipe what the jni dir folder name should be. If it is
omitted, the recipe name is used. Be careful here, sometimes the folder name is important, especially if this folder is
a dependency of something else.
The following template includes all the recipe sections you might use. None are compulsory, feel free to delete method
overrides if you do not use them:
class YourRecipe(Recipe):
# This could also inherit from PythonRecipe etc. if you want to
# use their pre-written build processes
1.7. Recipes 25
python-for-android Documentation, Release 0.1
recipe = YourRecipe()
This documentation covers most of what is ever necessary to make a recipe work. For further examples, python-for-
android includes many recipes for popular modules, which are an excellent resource to find out how to add your own.
You can find these in the python-for-android Github page.
The Recipe is the base class for all p4a recipes. The core documentation of this class is given below, followed by
discussion of how to create your own Recipe subclass.
26 Chapter 1. Contents
python-for-android Documentation, Release 0.1
1.8 Bootstraps
This page is about creating new bootstrap backends. For build options of existing bootstraps (i.e. with SDL2, Webview,
etc.), see build options.
python-for-android (p4a) supports multiple bootstraps. These fulfill a similar role to recipes, but instead of describing
how to compile a specific module they describe how a full Android project may be put together from a combination of
individual recipes and other components such as Android source code and various build files.
This page describes the basics of how bootstraps work so that you can create and use your own if you like, making it
easy to build new kinds of Python projects for Android.
A bootstrap class consists of just a few basic components, though one of them must do a lot of work.
For instance, the SDL2 bootstrap looks like the following:
class SDL2Bootstrap(Bootstrap):
name = 'sdl2'
recipe_depends = ['sdl2']
def run_distribute(self):
# much work is done here...
The declaration of the bootstrap name and recipe dependencies should be clear. However, the run_distribute
method must do all the work of creating a build directory, copying recipes etc into it, and adding or removing any extra
components as necessary.
If you’d like to create a bootstrap, the best resource is to check the existing ones in the p4a source code. You can also
contact the developers if you have problems or questions.
1.9 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. You can communicate with the service process from
your app using e.g. osc or (a heavier option) twisted.
1.8. Bootstraps 27
python-for-android Documentation, Release 0.1
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 start_service function from the 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')
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 --service=myservice:/path/
to/myservice.py argument when calling python-for-android. The myservice name before the colon is the
name of the service class, via which you will interact with it later. You can add multiple --service arguments to
include multiple services, 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:
28 Chapter 1. Contents
python-for-android Documentation, Release 0.1
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:
1.10 Troubleshooting
Add the --debug option to any python-for-android command to see full debug output including the output of all the
external tools used in the compilation and packaging steps.
If reporting a problem by email or Discord, it is usually helpful to include this full log, e.g. via a pastebin or Github
gist.
python-for-android is managed by the Kivy Organisation, and you can get help with any problems using the same
channels as Kivy itself:
• by email to the kivy-users Google group
• on #support Discord channel
If you find a bug, you can also post an issue on the python-for-android Github page.
When a python-for-android APK doesn’t work, often the only indication that you get is that it closes. It is important
to be able to find out what went wrong.
python-for-android redirects Python’s stdout and stderr to the Android logcat stream. You can see this by enabling
developer mode on your Android device, enabling adb on the device, connecting it to your PC (you should see a
notification that USB debugging is connected) and running adb logcat. If adb is not in your PATH, you can
find it at /path/to/Android/SDK/platform-tools/adb, or access it through python-for-android with the
shortcut:
python-for-android logcat
or:
1.10. Troubleshooting 29
python-for-android Documentation, Release 0.1
Running logcat command gives a lot of information about what Android is doing. You can usually see important lines
by using logcat’s built in functionality to see only lines with the python tag (or just grepping this).
When your app crashes, you’ll see the normal Python traceback here, as well as the output of any print statements etc.
that your app runs. Use these to diagnose the problem just as normal.
The adb command passes its arguments straight to adb itself, so you can also do other debugging tasks such as
python-for-android adb devices to get the list of connected devices.
For further information, see the Android docs on adb, and on logcat in particular.
It is sometimes useful to unpack a pacakged APK to see what is inside, especially when debugging python-for-android
itself.
APKs are just zip files, so you can extract the contents easily:
unzip YourApk.apk
At the top level, this will always contain the same set of files:
$ ls
AndroidManifest.xml classes.dex META-INF res
assets lib YourApk.apk resources.arsc
$ cd assets
$ ls
private.mp3
private.mp3 is actually a tarball containing all your packaged data, and the Python distribution. Extract it:
$ tar xf private.mp3
$ ls
android_runnable.pyo include interpreter_subprocess main.kv pipinterface.
˓→kv settings.pyo
assets __init__.pyo interpreterwrapper.pyo main.pyo pipinterface.
˓→pyo utils.pyo
editor.kv interpreter.kv lib menu.kv private.mp3
˓→ widgets.pyo
editor.pyo interpreter.pyo libpymodules.so menu.pyo settings.kv
Most of these files have been included by the user (in this case, they come from one of my own apps), the rest relate
to the python distribution.
With Python 2, the Python installation can mostly be found in the lib folder. With Python 3 (using the
python3crystax recipe), the Python installation can be found in a folder named crystax_python.
30 Chapter 1. Contents
python-for-android Documentation, Release 0.1
The following are common problems and resolutions that users have reported.
This occurs if your version of colorama is too low, install version 0.3.3 or higher.
If you install python-for-android with pip or via setup.py, this dependency should be taken care of automatically.
This is a known bug in some releases. To work around it, add your python requirement explicitly, e.g.
--requirements=python2,kivy. This also applies when using buildozer, in which case add python2 to your
buildozer.spec requirements.
This can happen when you try to include a very long filename, which doesn’t normally happen but can occur acci-
dentally if the p4a directory contains a .buildozer directory that is not excluded from the build (e.g. if buildozer was
previously used). Removing this directory should fix the problem, and is desirable anyway since you don’t want it in
the APK.
This occurs due to a java version mismatch, it should be fixed by installing Java 8 (e.g. the openjdk-8-jdk package on
Ubuntu).
java.lang.NoClassDefFoundError: sun/misc/BASE64Encoder
JNI DETECTED ERROR IN APPLICATION: static jfieldID 0x0000000 not valid for class
java.lang.Class<org.renpy.android.PythonActivity>
This error appears in the logcat log if you try to access org.renpy.android.PythonActivity from within
the new toolchain. To fix it, change your code to reference org.kivy.android.PythonActivity instead.
Ensure you have the package backports.ssl-match-hostname in the buildozer requirements, since Kivy targets python
2.7.x
You may also need sslopt={“cert_reqs”: ssl.CERT_NONE} as a parameter to ws.run_forever() if you get an error
relating to host verification
1.10. Troubleshooting 31
python-for-android Documentation, Release 0.1
Requested API target 19 is not available, install it with the SDK android tool
This means that your SDK is missing the required platform tools. You need to install the platforms;android-19
package in your SDK, using the android or sdkmanager tools (depending on SDK version).
If using buildozer this should be done automatically, but as a workaround you can run these from ~/.buildozer/
android/platform/android-sdk-20/tools/android.
1.11 Docker
Currently we use a containerized build for testing Python for Android recipes. Docker supports three big platforms
either directly with the kernel or via using headless VirtualBox and a small distro to run itself on.
While this is not the actively supported way to build applications, if you are willing to play with the approach, you
can use the Dockerfile to build the Docker image we use in .travis.yml for CI builds and create an Android
application with that in a container. This approach allows you to build Android applications on all platforms Docker
engine supports. These steps assume you already have Docker preinstalled and set up.
Warning: This approach is highly space unfriendly! The more layers (commit) or even Docker images (build)
you create the more space it’ll consume. Within the Docker image there is Android + Crystax SDK and NDK +
various dependencies. Within the custom diff made by building the distribution there is another big chunk of space
eaten. The very basic stuff such as a distribution with: CPython 3, setuptools, Python for Android android
module, SDL2 (+ deps), PyJNIus and Kivy takes almost 13 GB. Check your free space first!
Note: You need to be in the python-for-android for the Docker build context and you can optionally
use --file flag to specify the path to the Dockerfile location.
3. Create a container from p4a image with copied testapps folder in the image mounted to the same one in the
cloned repo on the host:
docker run \
--interactive \
--tty \
--volume ".../testapps":/home/user/testapps \
p4a sh -c
'. venv/bin/activate \
&& cd testapps \
&& python setup_testapp_python3.py apk \
--sdk-dir $ANDROID_SDK_HOME \
--ndk-dir $ANDROID_NDK_HOME'
Note: On Windows you might need to use quotes and forward-slash path for volume “/c/Users/. . . /python-for-
android/testapps”:/home/user/testapps
32 Chapter 1. Contents
python-for-android Documentation, Release 0.1
Warning: On Windows gradlew will attempt to use ‘bashr’ command which is a result of Windows line
endings. For that you’ll need to install dos2unix package into the image.
ls -lah testapps
For reference, this is based on a Git flow model, although we don’t follow this religiously.
1.12.2 Versioning
python-for-android releases currently use calendar versioning. Release numbers are of the form YYYY.MM.DD. We
aim to create a new release every four weeks, but more frequent releases are also possible.
We use calendar versioning because in practice, changes in python-for-android are often driven by updates or adjust-
ments in the Android build tools. It’s usually best for users to be working from the latest release. We try to maintain
backwards compatibility even while internals are changing.
Release checklist
34 Chapter 1. Contents
CHAPTER 2
• genindex
• modindex
• search
35