Publishing and maintaining extensions¶
An extension update must be recognizable as the same Android package, signed by the same publisher, and compatible with Katari's Entry API family. It should also preserve source and content identities so an upgrade does not duplicate a user's library or lose history.
Before the first release¶
Choose values that can remain stable:
- A unique Android
applicationIdsuch aseu.kanade.tachiyomi.extension.en.example. - A signing key that is backed up securely and never committed to the repository.
- A source
name,lang, andversionId, or an explicit sourceid. - Stable entry and chapter URL formats.
The APK must declare the tachiyomi.extension feature, its source or factory class, the supported Entry API family, and its content classification. See getting started.
Version the APK¶
Increase Android versionCode for every published update. Katari and Android use it to decide which package is newer; a lower version code cannot replace a higher installed version.
The extension versionName has three numeric components:
For example, 2.0.1 targets Entry API family 2.0 and is revision 1 of the extension. The next release of that extension is 2.0.2, even if it still compiles against SDK artifact sdk-2.0.1. Katari and the extension repository derive the compatibility family by removing the final component from versionName.
Do not treat versionName as an independent SemVer for the extension. Read API compatibility and versioning before changing either of its first two components.
Preserve Android identity¶
Updates must use the same applicationId and signing certificate. Changing either makes the APK a different or untrusted installation. Protect the signing key and document its recovery procedure outside the public repository.
Katari asks the user to trust a certificate it has not seen before. That is expected for a first installation, but an unexpected trust prompt during a routine update can indicate a signing change.
Preserve source identity¶
EntryHttpSource generates its source ID from lowercased name, lang, and versionId. Changing any of these can create a new source and disconnect existing library entries from their implementation.
When a public name must change, preserve the old ID explicitly:
Record the existing ID before making the change. Do not invent a replacement number after publishing. Moving a source between factories is safe only when its package, class loading, and source ID remain compatible.
Preserve content identity¶
Inside a source, entry and chapter URLs are persistent identifiers, not merely navigation links.
- Keep an entry's
urlstable when its title, cover, or provider domain changes. - Keep chapter URLs stable when labels or numbering change.
- Prefer domain-free paths with
setUrlWithoutDomain()when the path is stable. - Retain query parameters when the provider uses them as identifiers.
- Resolve temporary tokens and media URLs at request time; never use them as content identity.
If a provider changes its identifiers, implement an intentional migration strategy before publishing. Merely returning new URLs can duplicate entries and discard the connection to history and downloads.
Maintain a released source¶
For every update:
- Build against a tagged SDK, not
local-SNAPSHOT. - Increase
versionCodeand the final extension-revision component ofversionName. - Build with the release signing configuration.
- Install the update over the previous public APK in a disposable test environment.
- Confirm the source loads without a new trust decision.
- Open existing library entries and chapters before testing newly discovered ones.
- Exercise popular, latest, search, details, chapter, and media requests.
- Check pagination, filters, image headers, playback selections, and subtitles as applicable.
- Verify the APK does not package
entry-source-api; it must remaincompileOnly.
Test a clean installation as well as an upgrade. A clean install cannot reveal identity and signing regressions.
Retire or replace a source¶
Do not silently reuse an existing source ID for a different provider. If a provider closes, return actionable failures and communicate the retirement through the extension distribution channel. If another provider replaces it, publish it as a distinct source unless it genuinely represents the same stored identities and an explicit migration exists.