Skip to content

ApkPy compared with Kivy, BeeWare and Flet

All of these let you write an Android app in Python. They disagree about one thing, and everything else follows from it: is there a Python interpreter inside the APK?

ApkPy is the only one here that answers no. That is what lets it generate a lean native Android app with Android's own views, a desktop Previewer that simulates Android, and a Java/XML project you can inspect. This page shows what that changes for the app you ship.

The short version

Python in the APK? What draws the screen An Android API nobody wrapped Source
ApkPy No — Python is translated to Java at build time Android's own views (TextView, RecyclerView, Material) Compiled with the app, checked when it is built Open
Kivy Yes — CPython is bundled Its own widgets, drawn with OpenGL Pyjnius, looked up while the app runs Open
BeeWare / Toga Yes — CPython is bundled Android's widgets, called from Python Chaquopy, looked up while the app runs Open
Flet Yes — CPython is bundled Flutter Pyjnius, looked up while the app runs Open
Chaquopy Yes — CPython is embedded You write the UI in Kotlin/Java Your own Kotlin/Java Open

In the benchmark, the same 100-note app measured in one emulator session came to a 5.37 MiB debug APK with ApkPy and 34.46 MiB with BeeWare/Toga, and started cold in 2,565 ms against 5,536 ms. Signed as a release, the ApkPy app is 1.48 MiB.

ApkPy also ships a Previewer with an in-device notification drawer, an NFC tag simulator, fictional contacts, a biometric prompt, and sensor, battery, GPS and push controls, so the desktop loop can exercise Android behaviour before a Gradle build.

What each one does

Kivy ships a Python runtime and draws every button, label and list itself with OpenGL, so a Kivy app looks the same on every platform rather than using the operating system's widgets.

BeeWare / Toga also ships a Python runtime and maps your code onto Android's widgets, calling them from Python through Chaquopy while the app runs. The same code also targets iOS and desktop.

Flet ships a Python runtime and renders with Flutter. You get Flutter's Material widgets, which look close to Android's without being Android's, and the same code runs on desktop and the web.

Chaquopy puts Python inside a normal Android Studio project: the interface is written in Kotlin or Java, and Python is called for the parts written in Python.

ApkPy reads your Python file rather than running it, and writes Android source: Activity classes, layout XML, res/ drawables and strings. There is nothing to interpret on the device. The output is a project you can open in Android Studio and read. Its API covers screens, data, background jobs, media, maps, notifications, NFC, contacts, billing and the rest of the phone.

Where ApkPy wins

  • Nothing to boot. No interpreter starts, because there is not one. The app launches like any other Android app: about twice as soon as BeeWare/Toga in the same benchmark session.
  • Size. The benchmark app ships at about 1.5 MB, signed and shrunk with R8; its debug build is about 5 MB. One pulling in Firebase, WorkManager, media3 and RecyclerView came to 2 MB. A bundled runtime is the largest single thing in the other approaches.
  • They are Android's widgets, not lookalikes. Scrolling, text selection, accessibility services, keyboard behaviour and dark mode are the platform's, because the views are the platform's.
  • A Previewer that simulates Android. The notification drawer, NFC tags, contacts, biometrics, sensors, battery, GPS and push all have desktop controls, so the edit loop covers more than layout.
  • The Android app, not just the screen. ApkPy covers all 60 capabilities in What ApkPy covers: feeds, chat, media, maps, notifications, background jobs, NFC, contacts, billing, widgets and the rest of the phone.
  • You can read the output. apkpy build gives you a normal Android project that you can open in Android Studio, change and keep.
  • Errors that name themselves. Python ApkPy does not translate stops the build and says which construct and why, instead of producing a blank value.

An Android API nobody wrapped

Every one of these wraps some of Android and leaves the rest. What you do about the rest is where they differ, and it follows from the first question again: with an interpreter on the phone, a class is looked up by name while the app runs, and a mistake shows when that line runs on a phone.

How you reach it You write A mistake shows
ApkPy native.java(), or @native since 1.13.0: compiled with the app Java, or Python checked against android.jar when the app is built
Kivy Pyjnius: autoclass("android.os.Vibrator") Python when that line runs on a phone
BeeWare / Toga Chaquopy: from java import jclass Python when that line runs on a phone
Flet Pyjnius, added as an Android dependency Python when that line runs on a phone

In ApkPy the block is compiled with the app. In Java, with the imports it needs and the answer the desktop gives instead:

battery = native.java(
    "batteryLevel",
    imports=["android.os.BatteryManager", "android.content.Context"],
    code="""
        BatteryManager bm = (BatteryManager)
                context.getSystemService(Context.BATTERY_SERVICE);
        return String.valueOf(bm.getIntProperty(
                BatteryManager.BATTERY_PROPERTY_CAPACITY));
    """,
    preview=lambda: "87",
)

reading.set_value("Battery: " + battery() + "%")

Since 1.13.0 the block can also be written in Python: the classes are named with native.use() and checked against android.jar when the app is built. Either way, javac compiles it with the rest of the app, so a misspelt method stops the build instead of crashing in somebody's hand; nothing is resolved by name at run time; and preview= gives the Previewer an answer, so the desktop runs the same code. native.gradle(), native.manifest() and native.keep() add the dependency, the permission and the R8 rule that go with it. See Your own Java, and six blocks already written -- reading text aloud, opening a page, saving a file, a calendar event.

For what goes beyond one call, ApkPy has functions of its own: an answer from another app with files.save_as() and incoming.shares(), a web page over the whole screen with browser.show(), ads.banner(), and a home-screen widget with home_widget. What ApkPy covers lists every capability it has.

When to pick ApkPy

Pick ApkPy for a complete Android app whose interface should be Android's own, whose APK should carry no interpreter, and whose logic is written in everyday Python: functions, control flow, lists, dicts, tuples, comprehensions, f-strings, try/except and the rest of the list.

That is wider than a form over a database: the 60 capabilities in What ApkPy covers include production feeds, chat and real-time events, background audio and video, OAuth sign-in, maps and location, notifications and push, background jobs and offline queues, NFC, contacts, billing, home-screen widgets and the rest of the phone. The Previewer runs the same source on the desktop with Android-specific simulations, and apkpy build leaves a Java/XML/Gradle project you can read and keep.

Frequently asked

Does the APK contain Python? No. The Python is translated at build time and does not exist on the device.

Is there a WebView? No. The screens are Android views.

What about requests, numpy and other packages? ApkPy compiles your code instead of shipping an interpreter, so in place of pip packages it brings its own calls: https for network requests, db for data, files, background_job, and native for any Android API. Python compatibility lists the Python it translates.

Can I call an Android API ApkPy has no function for? Yes, with a block that is compiled with the app and called from your Python like any function: native.java() in Java, or since 1.13.0 @native in Python. In Kivy, BeeWare and Flet the same call goes through Pyjnius or Chaquopy while the app runs. See An Android API nobody wrapped.

Can I open the result in Android Studio? Yes — apkpy build produces a normal Android project.

I have a Kivy app. How much changes? Coming from Kivy maps App, KV, layouts, widgets, Clock, plyer and buildozer.spec onto ApkPy.

Can I bring a Tkinter app? Most of the Python carries over, and the windows become ApkPy screens: see From Tkinter to Android.

Is it open source? Yes, under the Apache License 2.0 since 1.13.0, and the apps you build are yours: see what the licence says.