From Tkinter to Android¶
A Tkinter script cannot be packaged as an Android app as it is. Tkinter draws its windows through Tk, which needs a desktop windowing system, and Android does not have one. That is why "convert my Tkinter app to an APK" has no one-click answer, whichever tool you try.
What does carry over is most of your Python. With ApkPy you keep the logic, the functions, conditions, loops, calculations and f-strings, and rewrite the window part with calls that look a lot like Tkinter's. ApkPy then translates the file into an Android app with Android's own views. On the desktop you even keep a Tk window: the Previewer that shows your app while you work is built on Tkinter.
The same converter, twice¶
A Celsius-to-Fahrenheit converter in Tkinter:
import tkinter as tk
root = tk.Tk()
root.title("Converter")
celsius = tk.Entry(root)
celsius.pack(padx=24, pady=8)
result = tk.Label(root, text="", font=("Arial", 20))
result.pack(pady=8)
def convert():
text = celsius.get()
if text == "":
result.config(text="Type a number first")
return
fahrenheit = float(text) * 9 / 5 + 32
result.config(text=f"{fahrenheit:.1f} °F")
tk.Button(root, text="Convert", command=convert).pack(pady=8)
root.mainloop()
The same app in ApkPy. The function convert() barely changes:
from apkpy_lib import Screen, button, inputs, label, run
home = Screen(id="home")
celsius = inputs("Degrees Celsius", id="celsius", type="number", screen=home)
result = label("", id="result", screen=home)
def convert():
text = celsius.get_value()
if text == "":
result.set_value("Type a number first")
return
fahrenheit = float(text) * 9 / 5 + 32
result.set_value(f"{fahrenheit:.1f} °F")
button("Convert", id="convert", command=convert, screen=home)
style = """
home {
padding: 24px;
gap: 16px;
}
result {
font-size: 28px;
}
"""
if __name__ == "__main__":
run(start_screen=home)
python writehere.py opens it in the Previewer, a Tk window on your desktop.
apkpy run builds the APK: the field becomes an Android EditText with the
numeric keyboard (type="number"), and convert() becomes a Java method.
What maps to what¶
| In Tkinter | In ApkPy |
|---|---|
tk.Tk(), root.mainloop() |
Screen(id=...), run(start_screen=home) |
root.title(...) |
name in apkpy.toml (the name under the icon), or app_bar(title) on the screen |
tk.Label, label.config(text=...) |
label("..."), set_value(...) |
tk.Button(command=...) |
button("...", command=...) |
tk.Entry, entry.get() |
inputs("placeholder"), get_value() |
tk.Text |
inputs(type="textarea") |
tk.Checkbutton |
inputs(type="checkbox") |
tk.Radiobutton |
segmented(options) |
tk.Scale |
inputs(type="range") |
tk.Listbox |
list_view(items=...) |
tk.PhotoImage in a label |
image(src) |
tk.Frame with pack() or grid() |
components stack in their screen; row(), column() and container() group them; gap and padding in the stylesheet |
font=, bg=, fg= |
font-size, background-color, color in the stylesheet |
StringVar, IntVar |
get_value() and set_value(), or a state value |
messagebox.showinfo(...) |
toast(...) or snackbar(...) |
messagebox.askyesno(...) |
confirm(title, message, on_result=...) |
tk.Toplevel (a second window) |
a second Screen, opened with on_click_navigate(screen), closed with back() |
root.after(1000, fn) |
timer.after(1, fn): seconds, not milliseconds |
filedialog.asksaveasfilename(...) |
files.save_as(...) |
A few habits change:
- Values from fields are text. As with
entry.get(), convert before you calculate:float(text) * 2, nottext * 2. ApkPy stops the build when it sees arithmetic on text it cannot type, and says which line. - One screen at a time. A phone shows one screen; a second Tk window
becomes a second
Screenthat opens on top, and Back returns. - The look is a stylesheet. Instead of options on each widget, sizes, colours and spacing go in one CSS-like block. See Themes and styling.
What has to change¶
Said once, as the price of an app with no interpreter inside:
- Classes. A Tkinter app written as a class (
class App(tk.Frame)) is rewritten as functions and names at the top of the file. ApkPy translates a listed vocabulary of Python, functions, control flow, lists, dicts, f-strings,try/except,mathand commonrepatterns, and classes are not in it. Anything outside the list stops the build at its line and says what to write instead. Compatibility and limits has the list. - Packages from
pip.requests,numpy,pandasorpillowneed an interpreter on the phone, and there is none. ApkPy has its own calls for network requests, data and storage, files and the device. An app built around one of those libraries fits Kivy or BeeWare better. - The
Canvaswidget. Free drawing has no counterpart; interfaces are made from Android's components, with charts for data.
In exchange the phone gets a small APK, about 1.5 MB signed and shrunk for a small app, with Android's own scrolling, keyboard and dark mode.
Building it¶
On Windows, ApkPy needs no WSL and no Android Studio: Python to APK on Windows goes from
pip install apkpy to the APK on your phone.
Next: the Installation page, or the end-to-end tutorial.