Package-level declarations

AssetPacks is the entry point: it shares one fetch per pack, verifies each pack against its assetdropkit.json manifest and reads files through a PackSource (PlayAssetPacks on Android, AppleStoreSource on iOS, LocalPacks in debug builds). Start with the README quickstart.

AssetPacks is the entry point: it shares one fetch per pack, verifies each pack against its assetdropkit.json manifest and reads files through a PackSource (PlayAssetPacks on Android, AppleStoreSource on iOS, LocalPacks in debug builds). Start with the README quickstart.

AssetPacks is the entry point: it shares one fetch per pack, verifies each pack against its assetdropkit.json manifest and reads files through a PackSource (PlayAssetPacks on Android, AppleStoreSource on iOS, LocalPacks in debug builds). Start with the README quickstart.

Types

Link copied to clipboard

What the app's Swift adapter (templates/ios/AssetDropAdapter.swift) reports for one call. Call one of onFinished, onFailed, onPending or onNotDownloaded to end it; anything after the first ending call is ignored. Plain methods rather than lambdas, so progress ticks box no numbers and nothing trips Swift 6's Sendable checks.

Link copied to clipboard
interface ApplePackStore

The app's Swift adapter over the AssetDropKit Swift package (Apple-hosted packs on iOS 26+, On-Demand Resources on iOS 17 and 18). The app framework re-exports this library (export("com.vocabloot:assetdropkit")) so Swift sees these names.

Link copied to clipboard
class AppleStoreSource(store: ApplePackStore, dispatcher: CoroutineDispatcher = Dispatchers.Default) : PackSource

Apple's stores through the app's Swift adapter: Apple-hosted packs on iOS 26 and later, On-Demand Resources on iOS 17 and 18. Callbacks may arrive on any thread; each call resumes once, and file bytes are copied out of NSData on dispatcher straight away.

Link copied to clipboard
class AssetPacks(source: PackSource, dispatcher: CoroutineDispatcher = Dispatchers.Default, markers: VerifiedMarkers = InMemoryVerifiedMarkers(), stallTimeoutMillis: Long = 0)

The app's entry point: one shared fetch per pack, an integrity check against the pack's assetdropkit.json, and reads on dispatcher, never the caller's thread.

Link copied to clipboard

Packs shipped inside the APK as plain assets (assets/<packId>/...), for debug builds: an APK installed with installDebug has no asset packs. Add the pack's folder to the debug source set's assets; release builds use PlayAssetPacks.

Link copied to clipboard

VerifiedMarkers for one process: each launch verifies each pack once.

Link copied to clipboard
class LocalPacks(root: Path, delayMillis: Long = 0, failEvery: Int = 0) : PackSource

Packs read from root/<packId>/ on disk, for debug builds and tests. A fetch waits delayMillis (showing Downloading) and every failEvery-th fetch fails as NoNetwork (0 never fails). Like a store, nothing is readable before a fetch; remove forgets the fetch and never deletes the files. Release builds never use it.

Link copied to clipboard
interface PackCancel

Cancels the Swift task behind one fetch.

Link copied to clipboard

Why a fetch failed, the same on every store. Swift sees camel-case names (.noNetwork).

Link copied to clipboard
@Serializable
data class PackManifest(val packId: String, val version: Int, val files: Map<String, String>)

<packId>/assetdropkit.json: the pack's content version and the lowercase hex SHA-256 of each file, keyed by its path inside the pack. scripts/write-pack-manifest.py writes it at build time.

Link copied to clipboard
interface PackSource

One store's delivery: Play, Apple's, or local files. Paths are inside the pack, without the <packId>/ prefix; each source adds it. Apps use AssetPacks, which adds shared fetches and the integrity check on top of a source.

Link copied to clipboard

Picks the Android source: packs bundled in the APK in debug builds, Play otherwise.

Link copied to clipboard
sealed interface PackState

Where a pack stands, as its store reports it.

Link copied to clipboard

Google Play Asset Delivery: on-demand asset packs hosted by Play. Each pack is an asset-pack module whose files sit under assets/<packId>/. A sideloaded build gets NeedsPlayConfirmation, never local files.

Link copied to clipboard

Play's two dialogs: mobile data for a large pack (WaitingForWifi) and Play's confirmation for an install it does not recognise (NeedsPlayConfirmation). Fetch again after the user answers.

Link copied to clipboard
object Sha256

SHA-256 (FIPS 180-4). The Kotlin standard library has no digest on every target.

Link copied to clipboard
interface VerifiedMarkers

Remembers which pack versions passed the integrity check, so a version is hashed once. Back it with persistent settings to hash once per install instead of once per launch. AssetPacks calls it under its own lock, so an implementation need not be thread-safe.

Properties

Link copied to clipboard

True for the states PackSource.fetch returns on: nothing more happens without the user or a new fetch.

Functions

Link copied to clipboard

Registers Play's dialogs; call from the activity's onCreate, before it starts.