Description
EditorService's cache policy is documented to cover plugin and theme assets, but on Android it never does. Once any asset bundle is on disk, prepare() returns the newest one without checking the site's editor-assets manifest, whatever the policy:
private suspend fun prepareAssetBundle(): EditorAssetBundle {
val latestAssetBundle = assetLibrary.readAssetBundles().firstOrNull()
if (latestAssetBundle != null) {
incrementProgress(DependencyWeights.ASSET_BUNDLE)
return latestAssetBundle
}
// …
}
(EditorService.kt#L272-L282)
EditorCachePolicy.MaxAge and EditorCachePolicy.Ignore refresh API responses and never assets. The only way to pick up a plugin or theme change is purge(), which deletes everything first and forces a cold load for the next editor.
For assets, the policy is consulted in one place, EditorAssetsLibrary.fetchManifest(). The service only calls it when there is no bundle on disk, and there the policy only decides whether to parse the manifest again.
iOS had the same gap. #742 closes it there, and docs/code/preloading.md describes the behavior Android should match.
Expected behavior
The policy decides when to check the site's manifest again:
| Policy |
Today |
Expected |
Always (default) |
Manifest checked only when no bundle is on disk |
Unchanged |
MaxAge |
Same as Always |
Manifest checked once the last check is older than the age |
Ignore |
Same as Always |
Manifest checked on every prepare() |
An unchanged manifest keeps the bundle already on disk rather than downloading every asset again — asset URLs carry their version (?ver=), so the same manifest means the same assets. A changed manifest builds a new bundle beside the old one.
A host can then refresh a site's editor data with EditorService.create(…, cachePolicy = EditorCachePolicy.Ignore).prepare(), without purge().
Related gaps found on iOS
#742 also fixes three problems on iOS that Android's code shares. They're worth doing in the same change, since a refresh makes each of them more visible:
- Download progress passes its total.
buildBundle reports a running total (EditorAssetsLibrary.kt#L208), and incrementProgress adds that fraction of the bundle's weight in full on every report (EditorService.kt#L252). With 4 assets the bundle contributes 12 + 25 + 37 + 50 = 124 against a weight of 50. On iOS the same arithmetic reached 175 of 100.
- Automatic cleanup shares one daily turn between every site. The key is
once-every-cleanup for all of them (EditorService.kt#L208-L210), so whichever site is prepared first each day uses it. That hasn't mattered while a site only ever has one bundle; once a refresh builds a second, the others' old bundles linger.
cleanup() deletes every bundle but the newest, including one that an open editor or EditorDependencies the host prepared earlier still reads (EditorAssetsLibrary.kt#L284). iOS now keeps any bundle handed out since launch.
Design notes from the iOS change
- "Latest" can't be the newest
downloadDate: a site can go back to a manifest it had before, whose bundle was downloaded earlier than the one it replaced. iOS stamps a separate lastCheckedDate in the bundle's manifest and orders by that, leaving downloadDate alone.
- The bundle has to be looked for again, under a lock shared with
cleanup() and purge(), before it's marked as the latest. Otherwise a cleanup landing between the check and the write leaves a directory holding only manifest.json, and the editor opens without plugin or theme assets.
- A manifest check should ask the site afresh rather than take a cached response or join a request already in flight.
Description
EditorService's cache policy is documented to cover plugin and theme assets, but on Android it never does. Once any asset bundle is on disk,prepare()returns the newest one without checking the site'seditor-assetsmanifest, whatever the policy:(
EditorService.kt#L272-L282)EditorCachePolicy.MaxAgeandEditorCachePolicy.Ignorerefresh API responses and never assets. The only way to pick up a plugin or theme change ispurge(), which deletes everything first and forces a cold load for the next editor.For assets, the policy is consulted in one place,
EditorAssetsLibrary.fetchManifest(). The service only calls it when there is no bundle on disk, and there the policy only decides whether to parse the manifest again.iOS had the same gap. #742 closes it there, and
docs/code/preloading.mddescribes the behavior Android should match.Expected behavior
The policy decides when to check the site's manifest again:
Always(default)MaxAgeAlwaysIgnoreAlwaysprepare()An unchanged manifest keeps the bundle already on disk rather than downloading every asset again — asset URLs carry their version (
?ver=), so the same manifest means the same assets. A changed manifest builds a new bundle beside the old one.A host can then refresh a site's editor data with
EditorService.create(…, cachePolicy = EditorCachePolicy.Ignore).prepare(), withoutpurge().Related gaps found on iOS
#742 also fixes three problems on iOS that Android's code shares. They're worth doing in the same change, since a refresh makes each of them more visible:
buildBundlereports a running total (EditorAssetsLibrary.kt#L208), andincrementProgressadds that fraction of the bundle's weight in full on every report (EditorService.kt#L252). With 4 assets the bundle contributes 12 + 25 + 37 + 50 = 124 against a weight of 50. On iOS the same arithmetic reached 175 of 100.once-every-cleanupfor all of them (EditorService.kt#L208-L210), so whichever site is prepared first each day uses it. That hasn't mattered while a site only ever has one bundle; once a refresh builds a second, the others' old bundles linger.cleanup()deletes every bundle but the newest, including one that an open editor orEditorDependenciesthe host prepared earlier still reads (EditorAssetsLibrary.kt#L284). iOS now keeps any bundle handed out since launch.Design notes from the iOS change
downloadDate: a site can go back to a manifest it had before, whose bundle was downloaded earlier than the one it replaced. iOS stamps a separatelastCheckedDatein the bundle's manifest and orders by that, leavingdownloadDatealone.cleanup()andpurge(), before it's marked as the latest. Otherwise a cleanup landing between the check and the write leaves a directory holding onlymanifest.json, and the editor opens without plugin or theme assets.