Skip to content

Everything Obtainium does, and more - #1

Merged
munzzyy merged 85 commits into
mainfrom
claude/project-improvement-obtainium-a7vh81
Sep 30, 2026
Merged

munzzyy merged 85 commits into
mainfrom
claude/project-improvement-obtainium-a7vh81

Conversation

@munzzyy

@munzzyy munzzyy commented Sep 30, 2026 •

Copy link
Copy Markdown
Owner

Tern now covers Obtainium's feature list, item by item, and adds its own on top. docs/COMPARISON.md goes through Obtainium's features one by one and lists where the two still differ. CHANGELOG.md has the full list under Unreleased.

Sources

  • The stores and sites Obtainium reads: APKPure, Aptoide, Uptodown, APKCombo, APKMirror (tracking only), Farsroid, Huawei AppGallery, Samsung Galaxy Store, vivo, Tencent, CoolApk, RuStore, itch.io, Telegram, NeutronCode, LiteAPKs, Apk4Free, RockMods (tracking only). The Add screen says when a store offers again what developers publish elsewhere, and when a site offers modified apps.
  • F-Droid's author and changelog, APKMirror's changes and file size, SourceForge folders and /p/ addresses.
  • Web pages as Obtainium reads them: its link order, up to ten steps, the version from a link, its text or the whole page. Tags for tracked projects without releases. Private GitHub projects with their token, and GitHub through a hubproxy.
  • "Read as" forces how an address is read, for every source Obtainium lets be overridden. Search covers F-Droid, the searchable stores and any Forgejo, names what failed, and takes a fewest-stars limit.
  • Every per-app option Obtainium has, in the model, the release selector, both file formats and the app's page. The package name can be set later on the app's page.

Installing

  • Shizuku (and Sui), Dhizuku, root, or another installer app picked from a list with icons and its way in. Google Play as installer of record, per app or for all.
  • Dhizuku is reached through its own protocol, written for Tern, and only the provider of the package Android names as device owner is asked. The few non-SDK calls it needs go through HiddenApiBypass for eight named classes, and only once Dhizuku is chosen. It never falls back to another installer.
  • Every install, whichever installer made it, counts only when the installed app carries the certificate the checks verified.
  • RuStore's base and splits install as one; OBB files are put in place with Shizuku or root.
  • Zip and tar archives, with gzip, bzip2 and xz read by Tern's own readers.
  • Downgrades with Let Me Downgrade. New apps can be shown to Verified Apps first.
  • Downloads can be cancelled, are retried, can go one at a time, and Tern updates itself last.

Settings and background

  • Any check interval from 15 minutes to 30 days on a slider. Check on start and on opening an app. Only installed apps. Remove apps uninstalled elsewhere. A global file filter.
  • Wi-Fi-only and charging-only hold back installs, not checks, as in Obtainium. One switch pauses every background install. Failed checks are retried, and rate limits are waited out.
  • Optional certificate pinning for GitHub, GitLab and Codeberg, on top of Android's own checks. RuStore addresses that use Russia's national CA are trusted for rustore.ru only.
  • A language picker on every Android version. Colour codes, standard, vibrant and expressive schemes (all measured for contrast), and category colours.

List, pages, import and export

  • Sort, group (foldable), filter by any combination, swipe, favourites on top, category stripes, double-tap to open, minimal density, haptics, phone layout. Each row shows its release date, changes and a moved project.
  • Install, categorise and share many apps at once. Update all can include first installs, be hidden, or ask first.
  • Import address lists and obtainium://apps links. An app's settings can be shared as a link Obtainium opens too, without tokens. The kept export can use Obtainium's format and a custom name.
  • Save any file of any release, source code included, from an app, one of its versions or many apps at once.
  • Notifications with Update and Update all, the version an app was updated to, and each app's problem with its reason.
  • The activity log can keep Tern's own warnings, errors and checks, off by default, with addresses' queries, tokens, passwords and email addresses taken out first.

Beyond Obtainium

  • A home-screen widget, a Quick Settings tile and launcher shortcuts.
  • A crash report shown at the next start. The project's README on an app's page. Screen transitions that follow the reading direction.

Translations

Every new string is in all 28 languages, machine-translated and checked by tools/strings.py. Korean and Turkish now take the right endings after the name Tern.

Checks

Core (1171) and app (674) unit tests, the device-test compile, release build, lint, the Java API check against API 29, the APK checks (6,937,650 bytes against a budget raised to 7 MiB, permissions as documented), the network-door check, the handoff page check and the site check. Dhizuku has been checked against Android's sources for 10 to 16 and not yet on a device.

Merging

The branch holds many small commits; a squash or rebase merge keeps main's history tidy.

Obtainium reads 18 stores and single-app sites that Tern skipped on
import. Each now has a source of its own, registered where detection
tries it, allowed in an export, and handed its entries by an Obtainium
import instead of being skipped by name. Until a source can read its
site it recognises no address, so detection passes it by.

A source can now say three more things. Where to fetch a file right
now, for stores whose download addresses expire within minutes; the
registry takes only an https address back and never a header that
carries credentials. That it only follows releases, for sites whose
owners forbid downloads by others. And that it republishes apps
somebody else built, so the person can be told before adding one.

A source can also be searched by name through Searchable.
Some stores answer a download request with a redirect whose Location is
the file, and the address is what the source wants to know. A request
can now ask for the redirect itself. Every other request follows
redirects as before, each hop still checked.
Some stores answer only a POST. A request can now carry a body with
its content type. A redirect with 307 or 308 repeats it as it was, and
301 to 303 turn it into a GET without the body, as browsers do.
An APKPure address Tern cannot read as an app is still skipped, and the
summary now says so in the words the import gives.
Settings, Installing, now asks what installs: Android's installer as
before, Shizuku or Sui, root, or another installer app the person picks.

Shizuku and root run pm as a user that may install without asking. The
first install of an app is then silent too, and so is every update on
Android 10 and 11. pm gets exactly the files the gate passed, streamed
into one session made for the user Tern runs as, with Tern named as the
installer so later updates through Android's installer stay silent as
well. Where the person wants it, Google Play is named instead, for apps
that only run when they believe the Play store installed them. pm's
answer is read into the status PackageInstaller would have given, so
the rest of Tern cannot tell the two apart.

Another installer app is handed a read-only copy of the checked file,
or of the split files as one .apks, and always asks, so it never runs
in the background. It says nothing back, so a package that changed is
the sign: the install counts when the package has the version handed
over and the certificate the gate verified.

When the chosen installer cannot be used, because Shizuku is not
running or su said no, Android's installer is used meanwhile, and the
settings row says why. The Shizuku client library is new and held to
its hash like every other dependency; it adds the permission Shizuku
asks of its clients, which check-apk.sh now expects.
A list could come from Obtainium but not go back. ObtainiumExport
writes Obtainium's export schema 2: each app under the source name
Obtainium keeps for it, its settings under the keys Obtainium reads,
and the pinned certificates as the hashes Obtainium blocks on. What
Obtainium has no key for stays behind, and a GitHub Actions app, which
Obtainium cannot read, is named as left out.

The test writes three apps and reads them back through Tern's own
Obtainium import, which has to give the same apps.
The list can be ordered by name, developer, date added, release date,
the last check or the source, either way round, and grouped by
category or by source under headings that fold away. Updates stay on
top unless that is switched off, and apps that are not installed can
go to the bottom. The choices are kept.

A favourite, from Obtainium's pinned apps or set here, stays at the top
of the list and carries a star. The filter chips gain favourites, track
only, problems and one per source, and every word of a search has to be
found somewhere in the app.

Selected apps can now also become favourites, get the same update mode,
be shared as a list of addresses or as an export in Tern's format or
Obtainium's, and be uninstalled, Android asking about each in turn.

A row can be swiped towards the end to run its action and towards the
start to remove the app, which the snackbar can take back. Settings
switches this off, and a device without touch never has it.

An app's page gains a star and a menu: check now, the release page,
share its address, a link that opens it in Tern, or an export, and
Android's own app info and uninstall. The page also says when the app
was last checked, and what the source says the app is.
AddressList takes every https address from a list typed one a line, an
OPML file of feeds, or a page of notes, in the order they first appear,
without the punctuation that ends a sentence and with & read as &.
A bracket that belongs to the address stays. Plain http is left out.
The import screen takes a list of addresses, pasted or read from any
text file such as an OPML list. Every address is shown ticked, and
adding looks at each the way a single link is looked at, one after the
other, with the same summary starred repositories get.

An obtainium://apps link, which carries several apps with their
settings, was refused. It now opens as a list with one pick for each
app, and each pick shows that app's carried settings before anything is
added.

tern://refresh checks every app, as obtainium://refresh does when
Obtainium's links are switched on; with ?id= and a package it checks
that one app. A check only reads the sources.
An export can now be kept up to date on its own: a moment after the list
or an app's settings change, it is written again, in Download/Tern or in
a folder the person picked. Exports may carry the portable settings (the
look, the list, notifications and checks, never a token, the proxy or the
installer) and may leave out apps that are not installed. Settings may
also export in Obtainium's format, and an import takes the settings a
file carries.
… and search F-Droid

Each follows what the site offers: Telegram's own channel of releases,
NeutronCode's file pages, itch.io's download flow, LiteAPKs' WordPress
records with a timed token, Apk4Free's download pages grouped by the
version in the file names, and RockMods for tracking only. Files are
only taken from each site's own hosts. F-Droid's search finds apps by
name.
…and RuStore

Each store is read through the same interface its own pages use: the
Galaxy Store's stub with a device model and CSC of the person's choice,
vivo's and Tencent's app records, CoolApk's API with its token, the
AppGallery handshake and RuStore's signed session. Links that expire are
asked for again when the file is fetched. Addresses the stores route
after a '#' are read as typed, and icons may come from each store's own
image hosts. AppGallery, vivo and RuStore can be searched by name.
Stores whose links expire, or that hand out a file only to a request
with the right headers, are asked for a fresh link right before a file
is read or downloaded. A kept file is now named by its release as well
as its address, so a store that serves every version at one address
cannot hand an old file to a new release, and a download cut short
resumes from a fresh link. A token still only goes to its own host.
…e settings

Background checks can now run from every 15 minutes to every 30 days.
New settings: check when Tern opens, check an app when its page opens,
check only installed and tracked apps, remove apps uninstalled outside
Tern, a file filter for every app without one of its own, run the
background check now, start with groups folded, haptic feedback, always
use the phone layout, a minimal list without icons, and older versions
when Let Me Downgrade is installed. Settings now travel in exports for
Obtainium and come in from Obtainium's exports under Tern's names.
APKPure's version history gives every variant with its size and hash,
Aptoide's API the app's latest file, Uptodown's pages a file fetched
through the site's own session, APKCombo's download page a signed link
asked for again when the file is fetched, and Farsroid's download box
its files. APKMirror's feed is read for tracking only. Files only come
from each store's own hosts, and Aptoide and Uptodown can be searched.
…cked

A search by name now asks every place picked above the results: GitHub,
Codeberg and GitLab, F-Droid, and the stores that can be searched, such
as AppGallery, vivo, RuStore, Aptoide and Uptodown. The choice is kept
for the next search. Each place may fail without sinking the others,
and every hit is cleaned the same way before it is shown.
Settings has a place for categories: each can be given one of sixteen
colours, renamed or deleted for every app filed under it, and new ones
can be made before any app is filed under them. A category without a
colour of its own always takes the same one. The colours show on the
list's filters and on the headings of groups, travel in exports, and
come in from Obtainium's exports.
A notification about updates now carries a button: Update for one app,
Update all for several, which run the same checks as the buttons in
Tern. A notification about one app opens its page. New releases of apps
that are only tracked get a channel of their own, and a quiet
notification can show while a background check runs.
The activity log can be shared as plain text, one line an entry with a
time every reader can order, all of it or only the problems. Settings
offers to add Tern's own releases to the list, where they are checked
and verified like any other app's.
…ives

Tern now has three ways in that Obtainium has not: a home-screen widget
that says how many updates there are and offers Check and Update all, a
Quick Settings tile that checks and shows the count, and launcher
shortcuts to check, update everything or add an app.

Releases that come as a tar or tar.gz archive are opened: their APKs go
through the same checks as those of a zip, and a filter can pick among
them. The Add screen now says when a store republishes other people's
apps, and plainly when a site offers apps someone else changed.

The APK budget rises to 6 MiB, which every source, the privileged
installers and the widget took it past.
An app's page now shows its notes, written in Markdown and carried by
exports, as Obtainium's About did, with a way to add and edit them. Its
categories are chips in their colours: a tap files the app under one or
takes it out, and a new one can be named there.

The Add screen lists every source Tern reads, by kind, with those that
can be searched and those that are for tracking only, and links to the
configurations Obtainium's users share.
… seen

Each file an app's page offers can be saved to Download/Tern as it was
downloaded, as Obtainium's release asset download does; the page says
that Tern checks a file when it installs it. Selected apps can have
their files saved at once, and new releases of selected tracked apps
can be marked as seen at once.
…ping its icon

A row carries a thin band in the colour of each category the app is
filed under, as Obtainium's rows do. A double tap on the icon of an
installed app opens it; a single tap still opens its page.
Where Obtainium can open the source's web page in a web view, Tern reads
the project's README from GitHub, GitLab or Forgejo and shows it as
text, with the HTML a forge would draw taken out. Nothing is asked of
the forge until the page is opened, and no script runs.
…th file formats

Releases can take their version from the tag, the title or the date,
name the group of the version pattern to use or a template of several,
be ordered by version, date, name or as the source lists them, stay a
release or more behind, and be filtered by their version. The release a
forge marks as latest comes first, and GitHub and Forgejo can check it
and date a release by its newest file. Archives can be picked, with a
filter for the files inside them. An app can have a name and an author
of its own, be muted, be checked again before a download, and name
Google Play as its installer.

HTML and direct links take request headers and a way to tell files
apart when the address never changes, and the HTML reader can take the
first link, order by the last part of the address, and find links
outside anchors. Obtainium's names for all of this are read on import
and written on export, and a trip through its format leaves an app as
it was.
An app's page now sets its own name and author, where to read the
version from and which release is newest, a group or template of the
version pattern, a filter on the version, how many releases to stay
behind, archives and a filter for the files inside them, muting, a
check before each download and Google Play as the installer, and it can
offer a skipped version again. The chosen name and author show
everywhere a name does, in notifications too.

A muted app makes no sound when it has an update, a check runs before a
download where asked, the filter for files inside archives picks what
is installed, and the release a forge marks as latest and the archives
that hold an app are kept with the stored releases. Links and imports
that carry any of these say so before the app is added.
What Obtainium calls a source's additional options can now be set per
app: for GitHub and Forgejo, asking which release is latest and dating
releases by their newest file; the workflow and branch of GitHub
Actions; the device model and region the Galaxy Store is asked for; and
for a web page or a direct link, the link filter, the pages to go
through first, the order, where the version is read, links outside
link tags, request headers and how files are told apart without a
version. Headers that carry credentials are refused before they are
saved. After a change the source is read again from the start.
The header of an app's page sits on a wash of the icon's main colour that
fades into the page. The colour is the mean of the icon's coloured pixels,
weighed by how coloured each is, so a white mark on a coloured shape gives
the shape; an icon of greys, or an app without one, takes its letter's
colour.
…s in place with Shizuku or root

- A file of a release can stand for a base and its splits, each fetched
  from its own address. The parts are packed in the staging folder and
  go through every check of a bundle, then install in one session.
- RuStore is asked for its splits, as Obtainium does, so an app it only
  publishes in parts installs whole.
- OBB files in an archive are taken out and, after Android installed the
  app, written to Android/obb/<package> through the Shizuku or root
  installer. With any other installer the activity says where they are.
  A name that could leave that folder refuses the archive.
…OBB files are handled

An OBB file's name comes from the archive and goes into the command that
writes it, so it may now hold only what OBB files are named of. The
security model says how a store's separate parts become one bundle and
where OBB files go.
…e, follow a SourceForge folder, and let the package name be set on an app's page

An app without a package name now leaves in Obtainium's format with an id
Obtainium replaces at the first install, and comes back without one.
…y which version was installed, and offer new apps to Verified Apps first

Saving goes on after the page is left and shows in the Downloads
notification. A problem notification names each app with its reason, and a
tap opens what went wrong. The installer app can be picked with its icon and
the way in to use.
…ied Apps and the installer picker are handled
…asked, with every secret taken out first

A switch under Settings, Activity log, off at first. Each check notes what
started it, how many apps, what it found and how long it took. Entries are
marked and coloured by level, have a filter of their own, and are capped at
500 apart from the apps' own history. Addresses lose their query and any
name and password, and tokens, keys, passwords and email addresses become an
ellipsis, before anything is kept.
…the certificate the checks verified

Dhizuku lends its device owner role to apps the person lets in, and a
device owner installs without a prompt. Tern speaks Dhizuku's protocol
itself, asks only the owner's own provider, and relays through it just the
calls about a session Dhizuku owns; the files go from Tern to Android. The
few non-SDK calls this needs are reached through HiddenApiBypass for eight
named classes, and only once Dhizuku is chosen. Dhizuku never falls back to
another installer, and every failure says what is missing.
…nd that every install is held to the verified certificate
Malayalam Dhizuku wording, and any log strings written so far.
@munzzyy
munzzyy merged commit 8399259 into main Sep 30, 2026
2 checks passed
munzzyy added a commit that referenced this pull request Sep 30, 2026
Tern now covers Obtainium's feature list and adds its own on top.
docs/COMPARISON.md goes through it point by point, and CHANGELOG.md lists
everything under Unreleased.

- Sources: every store and site Obtainium reads, F-Droid's author and
  changelog, APKMirror's changes and file size, SourceForge folders, web
  pages with up to ten steps, tags for projects without releases, private
  GitHub projects, a hubproxy, "Read as", and search across forges and stores.
- Installing: Shizuku (and Sui), Dhizuku, root or another installer app,
  Google Play as installer of record, RuStore's splits and OBB files, tar
  archives with gzip, bzip2 and xz, downgrades with Let Me Downgrade, and
  Verified Apps first. Every install counts only when the installed app
  carries the certificate the checks verified.
- Settings and background: checks every 15 minutes to 30 days, retries and
  rate limits waited out, optional certificate pinning, a language picker,
  colour codes and schemes measured for contrast.
- List, pages, import and export: sorting, grouping, combined filters, swipes,
  favourites, bulk actions, address lists and obtainium:// links, settings
  shared as links Obtainium opens, any file of any release saved, richer
  notifications, and Tern's own messages in the log with secrets taken out.
- Beyond Obtainium: a home-screen widget, a Quick Settings tile, launcher
  shortcuts, a crash report at the next start, and the project's README on an
  app's page.
- Every new string in all 28 languages.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant