Skip to main content

How to run python on android

There's a very popular question on SO "How to run python on android" but nobody actually explains what you have to do or how it's done.

Since I went through all of these projects for hours to figure it out I thought I'd share how you actually do it.


From a high level, to run just python on android you must:


  1. Cross compile python and any extensions for the target ABIs (arm, arm-v7a, etc.. see https://developer.android.com/ndk/guides/abis.html)
  2. Include the cross compiled libpython and all CC'd extensions as native libraries (gradle's jniLibs https://developer.android.com/studio/projects/add-native-code.html#link-gradle) or optionally extract them to the assets folder
  3. Include the Python standard library and any extra python files as android assets (compress in a zip and have the app extract to assets on first launch)
  4. Create a C or C++ native file using the NDK and have it initialize Python using the C-API (https://docs.python.org/2/c-api/intro.html#embedding-python) as an embeded interpreter
  5. Use the JNI to invoke your native code, creating any API's needed (ex run a main.py script or invoke a python function). 

So once python is compiled for the correct arch the app must simply know where to find it and it can then access the python C-API, which can then "run" any python code.

This is how the python-for-android (ex kivy), pybridge, and pybee's implementations all work.


Example

The most simple example of this is in pybridge. It looks like it's a simplified version of Kivy's.

Setup

You have to have the Android SDK and NDK (Crystax) installed.

Cross compiling

pybridge uses the prebuilt python (2.7 or 3.5) from the Crystax NDK. Which is the easiest because it has libpython2.7.so (or 3.5m) already compiled for each arch along with several modules from the standard library (ex sockets, multiprocessing) and it has the python stdlib packaged as a zip for you.

If you need extensions or other libraries that require rebuilding python (ex SSL), just use python-for-android. Cross compiling is REALLY complicated, every library is different. Python-for-android has a lot of the popular ones already done. To add your own extension you create a new recipe and implement it (just read how the other recipes work).  It's mainly a matter of finding the correct -I and -L and -l flags the library needs (and the paths to them during building).

Including libpython

Kivy and pybridge use an Android.mk file to include python and ndk-build to complile the .c file that provides the needed API. Pybridge then uses Gradle to copy ".so" files within the jnilibs source directory into the apk for you.  Android installs any ".so" file in the jniLibs.srcDir that starts with the "lib" prefix, ex libpython.so so these don't need extracted from the apk.

Including the standard library (and other python packages)

Pybridge just uses the stdlib.zip packed with the crystax NDK. It adds this zip into a folder within the android assets directory (assets/python/stdlib.zip). When the app starts, the main activty uses an "AssetExtractor" which extracts all the files from the apk (apk is just a zip file) to the actual assets folder on the device.  After this is done, python simply needs to know the path and it can use them.

You can include any python source packages this way.  It's added to the system path and it just works normally.

Create a native bootstrap

The bootstrap is just a native c file that embeds the python interpreter and does any initialization (such as redirecting stdout to use android's log). Pybridge and Kivy's are nearly identical. https://github.com/joaoventura/pybridge/blob/master/app/src/main/jni/pybridge.c   If you look at this file it is using the Python C-API to initialize the python interpreter, set the python path (to the android assets folder) and then it imports the bootstrap file. Kivy simply runs a "main.py" file at this point and handles the rest in python (well mostly).  

Call the native bootstrap via the JNI

Kivy and Pybridge's main activities then simply define a JNI wrapper to the bootstrap functions (ex start) and invoke these after extracting the assets. Pybridge uses JSON and the JNI as a sort of RPC to invoke python from Java and return the result. Kivy simply kicks off the main.py script. 


That's all.  Read the code it's not too bad (except compiling that is)!


Cheers!

Comments

  1. Hey, how can i include numpy library in this project ?

    ReplyDelete

Post a Comment

Popular posts from this blog

Kivy vs React-Native for building cross platform mobile apps

I've built three apps now using Kivy and one with React-Native, just wanted to share my thoughts on both.

Just a warning, I am strongly biased towards python and this is all based on opinion and experience and is thus worth what you pay for it. I don't claim to be an expert in either of these, just have worked with each for several months.  If something is incorrect I'd love to hear advice.

Kivy
Demo of one of the apps



Pros:
Nice to be able to run natively on the desktop WITHOUT a simulatorPython is easy to work withUse (almost) any python libraryVery easy to create custom widgetsKivy properties and data binding just work. Way nicer than React's "state" / flux / redux whatever you want to call it (stupid?). Native interfaces (pyjnius) and (pyobjc)Runs and feels pretty smooth Cons:Default widget toolkit looks like Android 4.4. Requiring you use your own widgets or a theming kit like KivyMD if styling bothers youCreating dynamic widgets declaratively is not yet s…

Control Systems in Python - Part 1 - Bode and Step Response

I hate matlab with passion, yet sadly, nearly everyone uses it.  I'm a fan of Python and open source stuff so here's a simple article on how to do some common control systems stuff in Python.

First we need to make sure the environment is setup.
Install IPython (or you can use any other python shell, but a unicode supported shell is preferred)Install python-control (numpy, scipy)Install sympy
These should do if your on Ubuntu/debian:

sudo apt-get install python-sympy python-numpy python-scipy python-matplotlib ipython
Then you need to install python control, see How to download and install python-control
Intro to using SympyOpen ipython and run the following:

import sympy from sympy import * sympy.init_printing() s = Symbol('s')

Now we can do things like define transfer functions using the symbolic variable s.


We can expand the bottom using the .simplify() method

and we can do something more complex like...
which is really nice because it does all the multiplication for us... and it’…