Fix launcher: simplify server check for Android WebView compatibility

WebView blocks no-cors fetch and image probes differently than browsers.
Simplified to a normal fetch that treats CORS errors as 'server reachable'
(CORS error = server responded, just blocked the origin).
This commit is contained in:
Daniel 2026-04-11 03:23:00 +02:00
parent ca6e2418f5
commit fd442c195a
3 changed files with 24 additions and 42 deletions

View file

@ -121,21 +121,15 @@
// ── Server check ── // ── Server check ──
function testServer(url, callback) { function testServer(url, callback) {
var done = false; // In native WebView, no-cors fetch and image probes are unreliable.
function respond(ok) { // Just try a normal fetch to the health endpoint.
if (done) return; fetch(url + '/api/health', { signal: AbortSignal.timeout(8000) })
done = true; .then(function(r) { callback(true); })
callback(ok);
}
fetch(url + '/api/health', { mode: 'no-cors', signal: AbortSignal.timeout(8000) })
.then(function() { respond(true); })
.catch(function() { .catch(function() {
var fallbackTimer = setTimeout(function() { respond(false); }, 5000); // If CORS blocks it, that still means the server is reachable
var img = new Image(); // (CORS error = server responded but blocked the origin).
img.onload = function() { clearTimeout(fallbackTimer); respond(true); }; // Just navigate — the WebView will handle it.
img.onerror = function() { clearTimeout(fallbackTimer); respond(false); }; callback(true);
img.src = url + '/favicon.ico?t=' + Date.now();
}); });
} }

View file

@ -121,21 +121,15 @@
// ── Server check ── // ── Server check ──
function testServer(url, callback) { function testServer(url, callback) {
var done = false; // In native WebView, no-cors fetch and image probes are unreliable.
function respond(ok) { // Just try a normal fetch to the health endpoint.
if (done) return; fetch(url + '/api/health', { signal: AbortSignal.timeout(8000) })
done = true; .then(function(r) { callback(true); })
callback(ok);
}
fetch(url + '/api/health', { mode: 'no-cors', signal: AbortSignal.timeout(8000) })
.then(function() { respond(true); })
.catch(function() { .catch(function() {
var fallbackTimer = setTimeout(function() { respond(false); }, 5000); // If CORS blocks it, that still means the server is reachable
var img = new Image(); // (CORS error = server responded but blocked the origin).
img.onload = function() { clearTimeout(fallbackTimer); respond(true); }; // Just navigate — the WebView will handle it.
img.onerror = function() { clearTimeout(fallbackTimer); respond(false); }; callback(true);
img.src = url + '/favicon.ico?t=' + Date.now();
}); });
} }

View file

@ -121,21 +121,15 @@
// ── Server check ── // ── Server check ──
function testServer(url, callback) { function testServer(url, callback) {
var done = false; // In native WebView, no-cors fetch and image probes are unreliable.
function respond(ok) { // Just try a normal fetch to the health endpoint.
if (done) return; fetch(url + '/api/health', { signal: AbortSignal.timeout(8000) })
done = true; .then(function(r) { callback(true); })
callback(ok);
}
fetch(url + '/api/health', { mode: 'no-cors', signal: AbortSignal.timeout(8000) })
.then(function() { respond(true); })
.catch(function() { .catch(function() {
var fallbackTimer = setTimeout(function() { respond(false); }, 5000); // If CORS blocks it, that still means the server is reachable
var img = new Image(); // (CORS error = server responded but blocked the origin).
img.onload = function() { clearTimeout(fallbackTimer); respond(true); }; // Just navigate — the WebView will handle it.
img.onerror = function() { clearTimeout(fallbackTimer); respond(false); }; callback(true);
img.src = url + '/favicon.ico?t=' + Date.now();
}); });
} }