[v3] window._wails.environment is never set on Android or iOS, so System.IsAndroid()/IsIOS() always return false
Summary
window._wails.environment is only ever populated by runtime.Core(), which is injected from the three desktop webview backends. On Android and iOS Core() is never called, so the object is missing entirely — and the public runtime API that reads it always answers "no":
// internal/runtime/desktop/@wailsio/runtime/src/system.ts:138
export function IsAndroid(): boolean {
return (window as any)._wails?.environment?.OS === "android";
}System.IsAndroid() returns false on Android, and System.IsIOS() returns false on iOS.
Where the value comes from
window._wails.environment is written in exactly one place:
// internal/runtime/runtime_dev.go:10 (runtime_prod.go:8 is the same with Debug:false)
var environment = fmt.Sprintf(`window._wails.environment={"OS":"%s","Arch":"%s","Debug":true};`, runtime.GOOS, runtime.GOARCH)and concatenated into the runtime prelude in internal/runtime/runtime.go:21:
return runtimeInit + flagsStr + invoke + environment + runtimeConfigReadyThat prelude is built by runtime.Core(...), and Core( has exactly three callers, all desktop:
pkg/application/webview_window_darwin.go:1459pkg/application/webview_window_linux.go:444pkg/application/webview_window_windows.go:2672
Neither application_android.go, application_android_nocgo.go nor application_ios.go mentions Core( or _wails.environment.
Confirmed on device
Read-only probe (a single evaluateJavascript in onPageFinished, no behaviour change), physical Android 16 / API 36 arm64-v8a device, Wails v3 app:
D/WailsProbe: ENV_PROBE="{...\"hasUnderscoreWails\":true,\"environment\":null,\"flags\":null}"(excerpt — the probe reports several fields.) window._wails exists and the bridge is live, but both environment and flags are null.
Impact
System.IsAndroid() / System.IsIOS() are the documented way to branch on platform, and they cannot return true on the platform they name. The same key is read in at least two more places: appregion.ts:217 and drag.ts:46.
Worth noting this is a wrong-answer API rather than a dead runtime: on Android the transport is selected from the presence of the JavaScript bridge (runtime.ts:239, keyed off window.wails.invokeAsync), not from environment — so apps still work, which is presumably why this has gone unnoticed.
Suggested direction
Desktop receives this through a prelude injected before page scripts run; mobile has no equivalent. On Android androidx.webkit is already a dependency (androidx.webkit:webkit:1.9.0 in the Android build template), so WebViewCompat.addDocumentStartJavaScript is the natural place to inject the same prelude, with a fallback for WebViews that do not support DOCUMENT_START_SCRIPT. iOS would need the equivalent in the WKWebView setup.
Happy to prepare a PR — I would rather agree on the mechanism first, since it touches the mobile WebView setup on both platforms. If you consider the fix a change to public behaviour rather than a bug fix, say the word and I will open a WEP instead.
Source: wailsapp/wails