ApkPy 1.14.2¶
Released 2026-10-30. python -m pip install --upgrade apkpy==1.14.2.
sorted(), list.sort(), min() and max() take a key=, and
json.loads() and json.dumps() read and write what CPython does. The
Previewer reloads when you save, and apkpy logs shows what the app prints on
the phone, with the line of writehere.py a crash came from.
import json
SCORES = '[{"name": "Ana", "score": 9}, {"name": "Rui", "score": 12}, {"name": "Eva", "score": 10}]'
def rank():
players = json.loads(SCORES)
players.sort(key=lambda p: p["score"], reverse=True)
names = [p["name"] for p in players]
out.set_value(f"{json.dumps(names)}, top score {players[0]['score']}")
On the phone the label reads ["Rui", "Eva", "Ana"], top score 12, the same
as in CPython.
Sorting with key=¶
key= takes a lambda of one parameter (key=lambda r: r["price"]), the name
of a function (key=len, or a def of the app), str.lower or d.get, with
reverse= and default=. Each key is worked out once per item and the order
is stable, also reversed, as in CPython. A key read from a list or a dict
keeps its type, so a price of 10 sorts after 9.
import json¶
json.loads() reads JSON while the app runs; a text that is not JSON raises
json.JSONDecodeError with CPython's message, line and column. json.dumps()
writes CPython's text, with indent=, sort_keys=, ensure_ascii=,
separators= and allow_nan=. With files, they keep data in a file:
json.loads(files.read("data.json")). A call given text written out in the
source is worked out while the app builds, so
CONFIG = json.loads('{"theme": "dark"}') works at the top of the file.
Lists and dicts answer as CPython's¶
An item read from a list or a dict keeps its type wherever it goes: into
another list, into a name, into json.dumps(), through pop() and get().
Two items compare as CPython compares them, numbers as numbers and text as
text. What a function returns is read as the list, dict or text it gives.
A list changed through a second name stops the build with the form that
answers the same on the phone (see Changed).
The Previewer reloads when you save¶
python writehere.py watches the app's folder. Saving a .py file there
starts the new code behind the open window, on the same screen, with what was
typed and chosen kept by each component's id and the screen scrolled where
it was. A save that changes only style redraws in place. A change that does
not start leaves the window running the last version, with the error and its
line on it. APKPY_RELOAD=0 turns it off.
apkpy logs¶
With the phone connected by USB, apkpy logs shows the app's print() as it
runs, ApkPy's warnings and errors, and a crash with its error and the line of
writehere.py it came from:
at writehere.py, line 13: n = int(field.get_value()). It finds the app by
the application_id in apkpy.toml and follows it through a crash and a
reopen. See Build a release.
Same on the phone and in the Previewer¶
- A label, markdown, a tree and the rows of a list that name no colour of
their own read on what is under them: the screen's
color, then the Theme's text, while it reads there, else the colour that does. On the phone a label without a colour was Material's grey, and markdown was white on the light screen of an app without a Theme. - The top bar runs under the status bar in its own colour, and the clock and battery follow it. Without a Theme it is dark on both.
- In the Previewer, a button with no colour is Material's own, as on the phone, and button text and the bar's title are the phone's size.
Fixed¶
storage.set(name, value)with the key in a name or an f-string used one key for every value on the phone, so each overwrote the last.on_click_navigate(detail, {"id": 7}), the data given withoutdata=, opened the next screen without it.int()andfloat()of a text that is not a number raise Python'sValueErrorwith CPython's message, and read1_000and0x1fas CPython does.markdown(...).set_value(text)stopped the app on the phone.- A list, a dict or a text above 64 KB at the top of the file stopped javac.
- The whole list is in the changelog.
Changed¶
- A name used at the top of the file above the line that makes it stops the
build (
E1201), as Python stops:button("Save", command=save)abovedef save():. The message says which line makes it. - One list or dict changed through a second name stops the build (
U2033) where CPython would show the change under both names:l2 = l1thenl2.append(x), or a defaulttags=[]that the function changes. The message gives the form that answers the same on both:list(l1),tags=None,cart = add(cart, x).
Checked on a phone¶
The new examples, examples/46_sorting_with_key.py (a scoreboard) and
examples/47_saving_with_json.py (a reading list kept in books.json),
were built and run on a phone with Android 16, and so were the fixes above.
The tests also run the generated Java of whole apps on the JVM and compare it
with CPython: 1,261 programs generated at random gave the same answers, or
now stop the build.
Upgrade¶
python -m pip install --upgrade apkpy==1.14.2, and build again. An app that
uses a name above the line that makes it, or changes one list through two
names, now stops the build at that line with the form to write instead.