Android¶
Chaquopy is distributed as a plugin for Android’s Gradle-based build system.
Prerequisites:
- Android Gradle plugin version should be between 2.3.x and 3.1.x. 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.
minSdkVersion
must be 15 or higher.
Some features require Python to be available on the build machine. Supported versions are 2.7, 3.3 and later.
By default, Chaquopy will build with the same Python major version as the app itself, i.e.
python2
/python3
on Linux and Mac, orpy -2
/py -3
on Windows. To change this, use thebuildPython
setting. For example, on Windows you might use one of the following:python { buildPython "py -3.5" buildPython "C:/Python36/python.exe" }
Basic setup¶
Gradle plugin¶
In the project’s top-level build.gradle
file, add the Chaquopy 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:3.1.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
Python version¶
With the plugin applied, you can now add a python
block within android.defaultConfig
. The
only required setting in this block is the Python version, and the currently available versions
are:
- 2.7.15
- 3.6.5 (recommended)
For example:
defaultConfig {
python {
version "3.6.5"
}
}
Note
The following obsolete Python versions are also available, but they do not contain all current features and bug fixes either for Chaquopy or for Python itself. Projects using these versions should upgrade as soon as possible.
- 2.7.10
- 2.7.14
- 3.6.3
ABI selection¶
The Python interpreter is a native component, so you must specify which native ABIs you want the app to support. The currently available ABIs are:
armeabi-v7a
, for the vast majority of Android hardware.x86
, for the Android emulator.
During development you will probably want to enable them both:
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. It will also make the app take longer to build. Because some of the native components are stored as assets, the split APK feature cannot be used to mitigate this. If you want to build separate APKs for each ABI, this can instead be done using a product flavor dimension:
android {
flavorDimensions "abi"
productFlavors {
arm {
dimension "abi"
ndk { abiFilters "armeabi-v7a" }
}
x86 {
dimension "abi"
ndk { abiFilters "x86" }
}
}
}
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 only provide syntax highlighting, and limited code completion and navigation features. It does not support Python debugging, and it will show numerous “unresolved reference” warnings. 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.
Development¶
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. If you configure this with the buildPython setting, the buildPython must have the same Python major version as the app itself.
External Python packages may be built into the app by adding a python.pip
block to
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:
python {
pip {
install "six==1.10.0"
install "scipy==1.0.1"
install "LocalPackage-1.2.3-py2.py3-none-any.whl"
install "-r", "requirements.txt"
}
}
Chaquopy can install 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:
python {
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:
python {
staticProxy "module.one", "module.two"
}
The app’s source tree and its 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 found.
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¶
Bytecode compilation¶
Your app will start up faster if its Python code is compiled to .pyc
format. This is
currently only supported for the Python standard library, but may be extended to app code and
pip-installed packages in a future version.
Compilation prevents source code text from appearing in Python stack traces, so you may wish to disable it during development. The default settings are as follows:
python {
pyc {
stdlib true
}
}
Resource files¶
By default, Python modules are loaded directly from the APK assets at runtime and don’t exist
as separate files. Because of this, any code which depends upon __file__
to locate
resource files will fail. There are two ways of dealing with this.
The most efficient way is to change the code to use pkgutil.get_data
instead. For
example, to load some/package/subdir/README.txt
from within some/package/module.py
:
readme = pkgutil.get_data(__name__, "subdir/README.txt")
# To read it like a file, use io.StringIO(readme.decode())
If this is not feasible (e.g. if the code is installed using pip), then you can specify certain Python packages to extract at runtime
using the extractPackages
setting. For example:
python {
extractPackages "somepackage", "some.subpackage"
}
Extracted packages will load slower and use more storage space, so you should specify the
deepest possible package which contains both the module on which __file__
is looked up, and
the files being loaded.
extractPackages
is used by default for certain PyPI packages which are known to require it.
If you discover any more, please let us know.
Python standard library¶
ssl¶
Because of inconsistencies in the system certificate authority store formats of different Android
versions, the ssl
module is configured to use a copy of the CA bundle from certifi. The current version is from certifi 2018.01.18.
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.
Licensing¶
Evaluation¶
You can try out Chaquopy right now by cloning one of the example apps, or following the setup instructions above in an app of your own.
An unlicensed SDK is fully-functional, but apps built with it will display a notification on startup, and are limited to a run-time of 5 minutes. To remove these restrictions, a license is required. All licenses are perpetual and include upgrades to all future versions.
Once you have a license key, activate it by adding the following line to the project’s
local.properties
file:
chaquopy.license=<license key>
Standard license¶
A standard license allows unlimited use of Chaquopy in any number of apps. Please contact us to request a license key, giving the following information:
- A summary of what your app is, and how Chaquopy will be used in it.
- How many developers on your project will be using Chaquopy.
Open-source license¶
For open-source apps, Chaquopy will always be free of charge. Please contact us with details of your app, including:
- The app ID (package name)
- Where the app is distributed (e.g. Google Play)
- Where the app’s source code is available