What does Chaquopy’s name mean?#

It comes from Jack London’s use of the word “chechaquo” (now usually spelled “cheechako”), a Native American term meaning “newcomer”. We chose it to reflect our goal of opening up new frontiers in how Python can be used.

Does Chaquopy support React Native?#

Yes, it can be used with any framework which lets you do the following:

  • Add content to your app’s build.gradle files.

  • Call Java methods.

Does Chaquopy support iOS?#

Not at the moment. For a list of ways to use Python in iOS apps, see the Python wiki (“iOS” column on the right).

One good option is the BeeWare framework. For example, have a look at the Electron Cash iOS app (source code, App Store), which you can compare with the similar Chaquopy-based Android app (source code, Google Play).

How can I make my app smaller?#

If your app is too large, check the following:

You can also try reducing the number of ABIs in your APK. Because of the way Chaquopy packages its native components, the APK splits and app bundle features won’t help much. Instead, use a product flavor dimension to build separate APKs or app bundles for each ABI. If you plan to release your app on Google Play, each flavor must also have a different version code. For example:

android {
    def versionBase = 123
    flavorDimensions "abi"
    productFlavors {
        arm32 {
            dimension "abi"
            ndk { abiFilters "armeabi-v7a" }
            versionCode 1000000 + versionBase
        arm64 {
            dimension "abi"
            ndk { abiFilters "arm64-v8a" }
            versionCode 2000000 + versionBase

If your app uses TensorFlow, consider replacing it with TensorFlow Lite:

How can I obfuscate my code?#

As described here, your code is automatically compiled to .pyc format if possible. To make the build fail if a compatible Python version isn’t found, you can use the src true setting.

If you want to hide your code further, you can compile it into an .so file using Cython and our package build tool. For more details, see here.

The Maven or pip repository is unreliable from my location#

To make your own mirror of our Maven repository:

  • Download the following directories from Maven Central, and arrange them in the same structure as the server. To find which Python version goes with which Chaquopy version, see this table.

    • com/chaquo/python/com.chaquo.python.gradle.plugin/CHAQUOPY_VERSION

    • com/chaquo/python/gradle/CHAQUOPY_VERSION

    • com/chaquo/python/runtime/*/CHAQUOPY_VERSION

    • com/chaquo/python/target/PYTHON_VERSION

  • Edit the repositories block in your settings.gradle or build.gradle file to declare your repository before or instead of mavenCentral. Use the directory containing “com”: either an HTTP URL or a local path can be used.

To make your own mirror of our pip repository:

  • Download whatever packages your app needs from https://chaquo.com/pypi-7.0, and arrange them in the same directory structure as the server.

  • Add the following lines to the pip block of your build.gradle file:

    options "--index-url", "https://pypi.org/simple/"
    options "--extra-index-url", "YOUR_MIRROR"

    Where YOUR_MIRROR is the directory containing the package directories you downloaded above. Either an HTTP URL or a local path can be used.

How do I …#

Read files in Python#

To read a file from your source code directory, use a path relative to __file__, as described in the “Data files” section.

To upload files to the device while your app is running, use os.environ["HOME"] and the Device File Explorer, as described in the “os” section.

To read photos, downloads, and other files from the external storage directory (“sdcard”), see the question below.

Read files from external storage (“sdcard”)#

Since API level 29, Android has a scoped storage policy which prevents direct access to external storage, even if your app has the READ_EXTERNAL_STORAGE permission. Instead, you can use the system file picker, and pass the file to Python as a byte array:


fun myMethod() {
        Intent(if (Build.VERSION.SDK_INT >= 19) Intent.ACTION_OPEN_DOCUMENT
               else Intent.ACTION_GET_CONTENT).apply {
        }, REQUEST_OPEN)

override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
    if (requestCode == REQUEST_OPEN && resultCode == RESULT_OK) {
        val uri = data!!.data!!
        // For Java, see https://stackoverflow.com/a/10297073
        val content = contentResolver.openInputStream(uri)!!.use { it.readBytes() }
        myPythonModule.callAttr("process", content)

The Python function can then access the file content however you like:

def process(content):
    # `content` is already a bytes-like object, but if you need a standard bytes object:
    content = bytes(content)

    # If you need a file-like object:
    import io
    content_file = io.BytesIO(content)

    # If you need a filename (less efficient):
    import tempfile
    with tempfile.NamedTemporaryFile() as temp_file:
        filename = temp_file.name  # Valid only inside the `with` block.

Write files in Python#

Use os.environ["HOME"], as described in the “os” section.

Pass images to/from Python#

The easiest way is to encode the image as a PNG or JPG file and pass it as a byte array. For an example of this, see the chaquopy-matplotlib app.

You may get better performance by passing the raw image data as an array, but then you’ll be responsible for using the correct image dimensions and pixel format.

Call back from Python#

There are many ways of doing this: here’s one example from the Electron Cash project:

Build errors#

First, make sure you’re seeing the complete build log in Android Studio:

  • In version 3.6 and newer, click the “Build: failed” caption to the left of the message.

  • In version 3.5 and older, click the “Toggle view” button to the left of the message.

Chaquopy cannot compile native code#

You’re trying to install a native package which we haven’t built yet. There may be a different version available, in which case there will be a “pre-built wheels” message in the build log. Otherwise, please visit our issue tracker for help.

No Python interpreter configured for the module#

This message is harmless: see the “Android Studio plugin” section.

No version of NDK matched the requested version#

This can be fixed by installing the NDK version mentioned in the message, or upgrading to Android Gradle plugin version 4.1 or later.

The warning “Compatible side by side NDK version was not found” is harmless, but can be resolved in the same ways.

Runtime errors#

Depending on your Android version, a crashing app may show a message that it “has stopped” or “keeps stopping”, or the app might just disappear. Either way, you can find the stack trace in the Logcat. Some of the most common exceptions are listed below.


See the questions above about reading and writing files.

Read-only file system#

See the question above about writing files.


Make sure you’ve built all required packages into your app using the pip block in your build.gradle file.

No address associated with hostname#

Make sure your app has the INTERNET permission, and the device has Internet access.