Android¶
Chaquopy is distributed as a plugin for Android’s Gradle-based build system.
Prerequisites:
Android Gradle plugin version should be between 3.1 and 3.5. This is specified as
com.android.tools.build:gradle
in your project’s top-levelbuild.gradle
file, and will usually be the same as your Android Studio version. Newer versions may also work, but have not been tested with this version of Chaquopy.Older versions as far back as 2.2 are supported by older versions of Chaquopy: see this page.
- minSdkVersion must be at least 16.
Basic setup¶
Note
Previous versions of Chaquopy required you to specify a Python version to build into your app. From Chaquopy 5.x onwards, this is no longer necessary because each Chaquopy version comes with only one Python version. For the mapping between versions, see this page.
Gradle plugin¶
In the project’s top-level build.gradle
file, add the Chaquopy Maven repository and
dependency to the end of the existing repositories
and dependencies
blocks:
buildscript { repositories { ... maven { url "https://chaquo.com/maven" } } dependencies { ... classpath "com.chaquo.python:gradle:6.3.0" } }
Then, in the module-level build.gradle
file (usually in the app
directory), apply the
Chaquopy plugin at the top of the file, but after the Android plugin:
apply plugin: 'com.android.application'
apply plugin: 'com.chaquo.python' // Add this line
All other configuration will be done in this module-level build.gradle
. The examples below
will show the configuration within defaultConfig
, but it can also be done within a product
flavor.
ABI selection¶
The Python interpreter is a native component, so you must use the abiFilters setting to specify which ABIs you want the app to support. The currently available ABIs are:
armeabi-v7a
, supported by virtually all Android devices.arm64-v8a
, supported by most recent Android devices.x86
, for the Android emulator.x86_64
, for the Android emulator.
During development you will probably want to enable ABIs for both the emulator and your devices, e.g.:
defaultConfig {
ndk {
abiFilters "armeabi-v7a", "x86"
}
}
There’s no need to actually install the Android native development kit (NDK), as Chaquopy will download pre-compiled CPython binaries for the selected ABIs.
Note
Each ABI will add several MB to the size of the app, plus the size of any native requirements. Because of the way the native components are packaged, the split APK and app bundle features cannot currently mitigate this. Instead, if your multi-ABI APKs are too large, try using a product flavor dimension:
android {
flavorDimensions "abi"
productFlavors {
arm {
dimension "abi"
ndk { abiFilters "armeabi-v7a" }
}
x86 {
dimension "abi"
ndk { abiFilters "x86" }
}
}
}
Development¶
Some features require Python 3.4 or later to be available on the build machine. Chaquopy will try to find it with the standard command for your operating system, first with a matching minor version, and then with a matching major version.
For example, if Chaquopy’s own Python version is 3.6.5, then on Linux and
Mac it will first try python3.6
, then python3
. On Windows, it will first try py -3.6
,
then py -3
.
To use a different copy of Python, set its command using the buildPython
setting. For
example, on Windows you might use one of the following:
defaultConfig {
python {
buildPython "C:/Python36/python.exe"
buildPython "py -3.7"
}
}
Source code¶
By default, Chaquopy will look for Python source code in the python
subdirectory of each
source set. For example,
the Python code for the main
source set should go in src/main/python
.
To add or change source directories, use the android.sourceSets block. For example:
android {
sourceSets {
main {
python {
srcDirs = ["replacement/dir"]
srcDir "additional/dir"
}
}
}
}
Note
The setRoot method only takes effect on the standard Android directories. If you want to set the Python directory as well, you must do so explicitly, e.g.:
main {
setRoot "some/other/main"
python.srcDirs = ["some/other/main/python"]
}
As with Java, it is
usually an error if the source directories for a given build variant include multiple copies of
the same filename. This is only permitted if the duplicate files are all empty, such as may
happen with __init__.py
.
Startup¶
It’s important to structure the app so that Python.start() is always called with an AndroidPlatform before attempting to run Python code. There are two basic ways to achieve this:
If the app always uses Python, then call Python.start() from a location which is guaranteed to run exactly once per process, such as Application.onCreate(). A PyApplication subclass is provided to make this easy: simply add the following attribute to the
<application>
element inAndroidManifest.xml
:android:name="com.chaquo.python.android.PyApplication"
You can also use your own subclass of
PyApplication
here.Alternatively, if the app only sometimes uses Python, then call Python.start() after first checking whether it’s already been started:
// "context" must be an Activity, Service or Application object from your app. if (! Python.isStarted()) { Python.start(new AndroidPlatform(context)); }
Requirements¶
Note
This feature requires Python on the build machine, which can be configured with the buildPython setting.
External Python packages may be built into the app using the pip
block in build.gradle
.
Within this block, add install
lines, each specifying a package in one of the following
forms:
- A pip requirement specifier.
- A local sdist or wheel filename (relative to the project directory).
"-r"
followed by a local requirements filename (relative to the project directory).
Examples:
defaultConfig {
python {
pip {
install "six"
install "scipy==1.0.1"
install "LocalPackage-1.2.3-py2.py3-none-any.whl"
install "-r", "requirements.txt"
}
}
}
In our most recent tests, Chaquopy could install about 90% of the top 1000 packages on PyPI. This includes almost all pure-Python packages, plus a constantly-growing selection of packages with native components. To see which native packages and versions are currently available, you can browse the repository here. To request a package to be added or updated, or for any other problem with installing requirements, please visit our issue tracker.
To pass options to pip install
, give them as a comma-separated list to the options
setting.
For example:
pip {
options "--extra-index-url", "https://example.com/private/repository"
install "PrivatePackage==1.2.3"
}
Any options in the pip documentation may be used, except for those
which relate to the target environment, such as --target
, --user
or -e
. If there are
multiple options
lines, they will be combined in the order given.
Static proxy generator¶
Note
This feature requires Python on the build machine, which can be configured with the buildPython setting.
In order for a Python class to extend a Java class, or to be referenced by name in Java code or
in AndroidManifest.xml
, a Java proxy class must be generated for it. The staticProxy
setting specifies which Python modules to search for these classes:
defaultConfig {
python {
staticProxy "module.one", "module.two"
}
}
The app’s source code and requirements
will be searched, in that order, for the specified modules. Either simple modules (e.g.
module/one.py
) or packages (e.g. module/one/__init__.py
) may be used.
Within the modules, static proxy classes must be declared using the syntax described in the static proxy section. For all declarations found, Java proxy classes will be generated and built into the app.
Packaging¶
Data files¶
To save time and space, your app’s Python modules are loaded directly from the APK assets at
runtime and don’t exist as separate .py
files. However, each module’s __file__
and
__path__
attributes can be used in the normal way to find any data files which are packaged
along with the code. Data files in the root directory will be extracted from the APK the first
time the app is started, while files within a top-level package will be extracted the first
time that package is imported.
Bytecode compilation¶
Your app will start up faster if its Python code is compiled to .pyc
format, so this is
enabled by default.
Compilation prevents source code text from appearing in stack traces, so during development you may wish to disable it. There are individual settings for:
src
: local source codepip
: requirementsstdlib
: the Python standard library
For example, to disable compilation of your local source code:
defaultConfig {
python {
pyc {
src false
}
}
}
In the case of src
and pip
, your buildPython must use the same
bytecode format as Chaquopy’s own Python version. Usually this means it
must have the same minor version, e,g. if Chaquopy is using Python 3.6.5, then buildPython
can be any version of Python 3.6.
If the bytecode formats do not match, the build will continue with a warning, unless you’ve
explicitly set one of the pyc
settings to true
. Your app will still work, but its code will
have to be compiled on the target device, which means it will start up slower and use more
storage space.
Python standard library¶
ssl¶
For consistency across different devices, the ssl
module is configured to use a copy of the CA
bundle from certifi. The current version is
from certifi 2019.9.11.
sys¶
stdout
and stderr
are redirected to Logcat with the tags python.stdout
and
python.stderr
respectively. The streams will produce one log line for each call to write()
,
which may result in lines being split up in the log. Lines may also be split if they exceed the
Logcat message length limit of approximately 4000 bytes.
stdin
always returns EOF. If you want to run some code which takes interactive text input, you
may find the console app template useful.
Android Studio plugin¶
To add Python suppport to the Android Studio user interface, you may optionally install the JetBrains Python plugin.
Note
Chaquopy is not fully integrated with this plugin. It will show numerous “unresolved reference” warnings, and it will not support Python debugging. We hope to improve this in a future version.
- In Android Studio, select File > Settings.
- Go to the Plugins page, and click “Install JetBrains plugin”.
- Select “Python Community Edition”, and click “Install”.
- Restart Android Studio when prompted.