fix(android): bootstrap legacy APK updater

This commit is contained in:
AverageConsumer
2026-08-21 00:55:32 +02:00
parent 087a275189
commit 8c65e76145
5 changed files with 37 additions and 9 deletions
+6 -3
View File
@@ -126,9 +126,12 @@ bundled game, in that case.
persistent launcher control. Android downloads the release APK, verifies
its SHA-256 entry from `sha256sums.txt`, then invokes Android's Package
Installer. The installer asks the user for consent and enforces package,
version-code, and signing-certificate compatibility. iOS links the
sideload repository for a re-sideload; Xbox, desktop, and PortMaster builds
link their correctly named full package. Switch keeps its native OTA flow.
version-code, and signing-certificate compatibility. A legacy APK without
the installer bridge links its full package for one manual bootstrap
update, including when its downloaded payload already reports the latest
engine version. iOS links the sideload repository for a re-sideload; Xbox,
desktop, and PortMaster builds link their correctly named full package.
Switch keeps its native OTA flow.
## Known limitations
+1 -1
View File
@@ -1320,7 +1320,7 @@ local function buildHeader(imp, m)
return y + math.floor(10 * m.s)
end
-- The state of the self-updater, as a top-right control.
-- The state of the self-updater, shown in the launcher footer.
-- Returns status, label, action, glow.
function LauncherView._updateControl(imp)
if not imp.Check then return nil end
+15 -5
View File
@@ -58,6 +58,13 @@ function Check.fullAssetName(version, osName, arch, port)
return fullAssetName(version, osName, arch, port)
end
-- A legacy Android APK can run a newer downloaded payload while still lacking
-- the native bridge that installs future APK updates. It needs one manual
-- package update even when that payload already reports the latest engine.
function Check.androidNeedsInstallerBootstrap(osName, hasInstaller)
return osName == "Android" and not hasInstaller
end
local CMD = "update_check_cmd"
local STATE = "update_check_state"
@@ -266,12 +273,15 @@ function Check.fullUpdateAction()
local st = Check.state()
if st.status ~= "needs_full" and st.status ~= "full_ready" then return nil end
local osName = love and love.system and love.system.getOS and love.system.getOS() or ""
if osName == "Android" and type(love.system.installApk) == "function"
and type(st.full) == "table" and type(st.full.url) == "string" then
if st.status == "full_ready" and type(st.full.path) == "string" then
return { label = "Install Android update", kind = "install" }
if osName == "Android" and type(st.full) == "table"
and type(st.full.url) == "string" then
if type(love.system.installApk) == "function" then
if st.status == "full_ready" and type(st.full.path) == "string" then
return { label = "Install Android update", kind = "install" }
end
return { label = "Download Android update", kind = "download" }
end
return { label = "Download Android update", kind = "download" }
return { label = "Update app manually", url = st.full.url }
end
if osName == "iOS" then
return { label = "Re-sideload app", url =
+6
View File
@@ -243,6 +243,12 @@ local function doCheck(target)
return
end
if Check.androidNeedsInstallerBootstrap(osName,
type(love.system.installApk) == "function") then
postFullRequirement(rel, "native_installer_missing")
return
end
if compareVersions(rel.version, currentEngine) <= 0 then
-- We are now running a native shell at least as new as GitHub's latest
-- release, so a former minShell/payloadHost prompt no longer applies.
+9
View File
@@ -48,6 +48,15 @@ eq(Check.fullAssetName("1.4.2", "iOS", "arm64"),
eq(Check.fullAssetName("not-a-version", "Android", "arm64"), nil,
"invalid full-package version rejected")
-- A legacy Android shell needs one manual package update even when its
-- downloaded payload already reports the latest engine version.
eq(Check.androidNeedsInstallerBootstrap("Android", false), true,
"legacy Android shell requires one bootstrap package")
eq(Check.androidNeedsInstallerBootstrap("Android", true), false,
"current Android shell keeps the selective updater")
eq(Check.androidNeedsInstallerBootstrap("Windows", false), false,
"non-Android update behavior remains unchanged")
local withNotes = Check.parseRelease(Json.encode({
tag_name = "v1.4.2",
body = "## Issues closed\n\n- #1 cart padding",