Search code examples
pythonandroidc++java-native-interfacecpython

Run Python from C++ on Android using NDK


I want to run some Python code from Android through JNI using NDK like this:

#include <jni.h>
#include <string>
#include <stdio.h>

#include <Python.h>

extern "C" JNIEXPORT jstring JNICALL
Java_com_example_mypythonapplication_MainActivity_stringFromJNI(
        JNIEnv* env,
        jobject /* this */)
{
    std::string command = "print('Hello World from Python!!!')";

    PyObject* pInt;

    Py_Initialize();

    PyRun_SimpleString(command.c_str());

    Py_Finalize();

    std::string message = "Command ";
    message.append(command);
    message.append(" was executed successfully!")

    return env->NewStringUTF(message.c_str());
}

Are there prebuilt libpython available for Android or is there any way to cross compile it in order to be able to achieve that?


Solution

    1. Compile Python for Android with:
    ┌─[19:20:55]─[jacob@jacob-pc]─[~]
    └──> export ANDROID_NDK_ROOT=/path/to/android-ndk
    
    ┌─[19:20:55]─[jacob@jacob-pc]─[~]
    └──> ./configure CC=$ANDROID_NDK_ROOT/toolchains/llvm/prebuilt/linux-x86_64/bin/aarch64-linux-android21-clang  CXX=$ANDROID_NDK_ROOT/toolchains/llvm/prebuilt/linux-x86_64/bin/aarch64-linux-android21-clang++ AR=aarch64-linux-android-ar LD=aarch64-linux-android-ld RANLIB=aarch64-linux-android-ranlib --target=arm-linux-androideabi -prefix=/path/to/install/dir --enable-shared --without-sqlite3 --without-pdo-sqlite --without-pear --enable-simplexml --disable-mbregex --enable-sockets --enable-fpm --disable-opcache --enable-libxml --without-zlib --build=x86_64-linux-gnu --disable-all --disable-ipv6 ac_cv_have_long_long_format=yes ac_cv_file__dev_ptmx=no ac_cv_file__dev_ptc=no
    
    ┌─[19:20:55]─[jacob@jacob-pc]─[~]
    └──> make
    
    ┌─[19:20:55]─[jacob@jacob-pc]─[~]
    └──> make install
    

    Or, easier, using docker:

    ┌─[19:20:55]─[jacob@jacob-pc]─[~]
    └──> docker run --rm -it -v $(pwd):/python3-android -v /path/to/android-ndk:/android-ndk:ro --env ARCH=arm --env ANDROID_API=21 python:3.9.0-slim /python3-android/docker-build.sh
    

    replacing /path/to/android-ndk with the path to the Android NDK.

    1. Deploy the resulted folder inside an readable folder on your Android system then call Py_SetPythonHome providing that path.

    2. Be aware that it is probably necessary to run:

    Py_Initialize();
    std::string command = "print('hello world')";
    PyRun_SimpleString(command.c_str());
    Py_Finalize();
    

    on a thread other than the Java thread.

    Tested with 21.1.6352462, Python 3.8.6 and Python 3.9.0.