DEV Community

Indie-Developer
Indie-Developer

Posted on

What one button becomes in an ApkPy build

When I write a button in ApkPy, I write one line of Python. By the time the app runs on a phone, that line has become a layout entry, a Java listener and a callback method. I want to show the whole path, because it explains why the APK has no Python interpreter inside.

The line:

button(
    "Continue",
    id="continue_button",
    variant="filled",
    command=continue_flow,
    screen=home,
)
Enter fullscreen mode Exit fullscreen mode

home is a Screen. Each screen becomes an Android Activity, and screen= puts the button at the root of that screen. If I pass parent=summary instead, it goes inside a container or card.

The compiler does not run this file and take a screenshot of a desktop window. It parses the Python syntax tree, collects screens, components and callbacks, and resolves the theme and style selectors before writing anything. The style block is a build-time input: the generated project gets colors, drawable shapes and dimensions, not a CSS engine running on the phone.

For the button above, the layout gets this:

<com.google.android.material.button.MaterialButton
    android:id="@+id/continue_button"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:minHeight="48dp"
    android:text="Continue" />
Enter fullscreen mode Exit fullscreen mode

And the Activity gets this:

MaterialButton continue_button = findViewById(R.id.continue_button);
continue_button.setOnClickListener(view -> {
    pythonCallback_continue_flow();
});
Enter fullscreen mode Exit fullscreen mode

The callback is a real Java method generated from my Python function. Conditions, loops, conversions and component calls inside it are translated to their Java equivalents. The snippets are shortened; the real layout also carries margins, colors, accessibility text and drawable references.

One detail worth knowing: helpers are emitted only when the source asks for them. A plain screen does not get a media service. Call audio.play_background and the build adds a foreground service, a MediaSession and the notification. Call https.get and it adds the INTERNET permission and background networking. This is why a simple app stays small.

The generated project is meant to be read. Open the Gradle output from apkpy build in Android Studio and the button is there, with the ID I gave it.

The rule that matters: writehere.py is the source of truth. The generated Android project is an output. Rebuild and the generated files can be replaced, so app behavior stays in Python. apkpy.toml holds the app name, package ID, version and icon.

1.14.1, out on October 25, added classes, dataclasses and custom errors to the translated Python. That reaches the button too: a method can be a command now, command=cart.clear, instead of only a function.

To see the output:

python -m pip install --upgrade apkpy
apkpy start hello
cd hello
python writehere.py
Enter fullscreen mode Exit fullscreen mode

writehere.py opens the Hot Previewer on the desktop. apkpy build writes the Gradle project. apkpy run compiles a debug APK.

Top comments (0)