Skip to content

feat(v3/mobile): IOS/Android manager API + event rename; first-class mobile docs#5602

Merged
leaanthony merged 30 commits into
masterfrom
worktree-add-mobile-landing
Jun 15, 2026
Merged

feat(v3/mobile): IOS/Android manager API + event rename; first-class mobile docs#5602
leaanthony merged 30 commits into
masterfrom
worktree-add-mobile-landing

Conversation

@leaanthony

@leaanthony leaanthony commented Jun 14, 2026

Copy link
Copy Markdown
Member

Summary

This PR now carries two related pieces of work:

  1. API refactor — move all iOS/Android native features onto platform managers and rename the mobile bridge events.
  2. Docs / landing page — make mobile a first-class, headline feature.

1. Mobile API refactor

Manager pattern

The iOS/Android native-feature free functions are now methods on platform manager singletons:

application.IOSShare(payload)            ->  application.IOS.Share(payload)
application.IOSHaptic("medium")          ->  application.IOS.Haptic("medium")
application.IOSSetScrollEnabled(true)    ->  application.IOS.SetScrollEnabled(true)
application.AndroidShare(payload)        ->  application.Android.Share(payload)
application.AndroidHaptic("medium")      ->  application.Android.Haptic("medium")

application.IOS and application.Android are zero-size singletons that only exist on their respective builds; all callers live in //go:build ios / //go:build android files. (38 iOS methods, 31 Android methods.)

Event renaming — native:* is gone

Mobile bridge events are now namespaced by reach:

Old New Scope
native:haptic, native:location, native:share, … common:* handled identically on both platforms (one frontend listener per event)
native:beginBackgroundTask, native:backgroundTask ios:* iOS-only
native:foregroundService android:* Android-only

The frontend keeps a single listener per event under common:*, matching the shared-codebase model. Applied consistently across every emit and listen site: the Objective-C/C bridge (.m/.h), the Android Java bridge (build-asset template and the git-tracked example build/ copy), the kitchen-sink example (Go handlers + frontend/main.js), IOS.md/ANDROID.md, and the docs-site guides.

Files touched

v3/pkg/application/{mobile_features_ios.go,mobile_features_android.go,ios_runtime_api.go,mobile_features_ios.m,mobile_features_ios.h,webview_window_ios.m}, the Android Java bridge (template + example build copy), v3/examples/{mobile,ios}/…, v3/IOS.md, v3/ANDROID.md, v3/UNRELEASED_CHANGELOG.md, and the docs-site mobile guides.

✅ Verification status — built & launched on both platforms

  • ✅ Desktop go build ./... and go test ./pkg/application/... pass; the example builds clean for desktop.
  • iOS Simulator (Xcode 26.5, iPhone 17 Pro): wails3 task ios:run builds the iOS-tagged Go C-archive (application.IOS.* managers), compiles + links the Objective-C bridge (renamed event strings), installs and launches. App runs and renders correctly with Platform: iOS.
  • Android Emulator (NDK 26.3, API level emulator): wails3 task android:run builds libwails.so (cgo application.Android.* managers via the NDK), compileDebugJavaWithJavac compiles the Java bridge (renamed event strings), assembles + installs the APK, launches MainActivity. App runs with a working Go↔JS binding (Platform: ANDROID).
  • ✅ Event rename verified as a pure bijection (no native: suffix dropped/merged); all jsonToMap() calls now take JSON-returning getters (fixed the iOS orientation handler).
  • ℹ️ One pre-existing nocgo-stub gap remains (androidBridgeVoid/androidBridgeStringString missing under CGO_ENABLED=0), surfaced only in generate bindings warnings — present on master, unrelated to this change, and harmless to the real cgo build.

2. Docs & landing page

  • Adds 'Mobile' to the MorphText cycling words — H1 now cycles Desktop → Server → Mobile
  • Landing page makes a song-and-dance about mobile: the key message is zero changes to your app to deploy to mobile
  • Promotes mobile to a first-class top-level documentation section in the sidebar
  • Removes "Mobile coming soon..." from the landing page feature card

Mobile docs section

  • Overview (/guides/mobile) — how it works, prereqs, feature matrix, build-tag rules, featured Kitchen Sink callout with run commands
  • Your First Mobile App (/guides/mobile/first-mobile-app) — step-by-step zero-to-running tutorial (iOS Simulator + Android Emulator), responsive CSS, platform detection in Go and JS, the platform-gating pattern, haptics, production builds, troubleshooting. Includes a note documenting the new application.IOS.* / application.Android.* manager API and the common:* / ios:* / android:* event convention.
  • iOS (/guides/mobile/ios) and Android (/guides/mobile/android) — full reference guides, moved from /guides/build/* (links updated across the docs; no redirect stubs)

Screenshots

Screenshot_1781430329

Test plan

  • Simulator/emulator build of v3/examples/mobile on iOS (Xcode 26.5) and Android (NDK 26.3) — both compile, install, launch and render
  • H1 on landing page cycles Desktop → Server → Mobile
  • Sidebar shows a "Mobile" section above "Guides"
  • /guides/mobile and /guides/mobile/first-mobile-app render correctly
  • Landing page card no longer says "Mobile coming soon..."

Summary by CodeRabbit

  • Documentation
    • Added comprehensive iOS and Android development guides with setup, deployment, and troubleshooting details
    • Introduced "Your First Mobile App" quickstart guide for running Wails apps on iOS Simulator and Android Emulator
    • Added new "Mobile" documentation section (marked experimental) with overview and platform-specific guides
    • Updated homepage to highlight iOS and Android platform support alongside desktop platforms

Copilot AI review requested due to automatic review settings June 14, 2026 07:31
@coderabbitai

coderabbitai Bot commented Jun 14, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

Adds experimental Wails v3 mobile documentation across five new or updated pages, refactors iOS and Android native feature APIs from function-based to method-based patterns, and unifies event routing through common:* namespaces. Updates navigation, homepage, Go SDK APIs, event wiring across JavaScript and native implementations, and documentation tables.

Changes

Mobile Platform Documentation & API Refactoring

Layer / File(s) Summary
Navigation and homepage updates
docs/src/components/MorphText.astro, docs/astro.config.mjs, docs/src/content/docs/index.mdx
MorphText adds "Mobile" to the rotation; sidebar gains a new collapsed "Mobile (Experimental)" section with iOS, Android, and overview links while removing them from Building & Packaging; homepage adds iOS Simulator and Android Emulator run commands and replaces "Cross-Platform Native" card with "Desktop & Mobile" listing Windows, macOS, Linux, iOS, and Android.
Mobile overview and getting-started guides
docs/src/content/docs/guides/mobile/index.mdx, docs/src/content/docs/guides/mobile/first-mobile-app.mdx
New index.mdx page introduces shared Go/WebView architecture, iOS vs Android prerequisites and feature-support tables, build tag rules, and Kitchen Sink example; new first-mobile-app.mdx walkthrough covers simulator/emulator setup, ios:run/android:run workflows for both platforms, making code mobile-aware with responsive CSS and build tags, production packaging for iOS (IPA) and Android (APK/fat-APK), troubleshooting, and links to detailed guides.
Comprehensive iOS and Android platform references
docs/src/content/docs/guides/mobile/ios.mdx, docs/src/content/docs/guides/mobile/android.mdx
New iOS guide covers UIKit/WKWebView runtime, simulator and device build commands, application.Options.IOS configuration, IOS runtime object, native tab event handling, compatibility matrix, and porting notes; new Android guide covers SDK/NDK prerequisites, emulator setup, android:run workflow, APK/fat-APK packaging, keystore signing with environment variables, Android runtime object (haptics, device info, toast), compatibility matrix, and porting notes.
API documentation and changelog updates
v3/ANDROID.md, v3/IOS.md, v3/UNRELEASED_CHANGELOG.md
Updated capability tables now document the new method-based API patterns (Android.Share(), IOS.Share()) and event namespace changes from native:* to common:* with platform-specific ios:* and android:*; changelog records both the API refactoring and event naming scheme.
iOS native feature API and event refactoring
v3/pkg/application/mobile_features_ios.go, v3/pkg/application/ios_runtime_api.go, v3/pkg/application/mobile_features_ios.h, v3/pkg/application/mobile_features_ios.m, v3/pkg/application/webview_window_ios.m
Refactored iOS bindings from exported IOS* functions to methods on an IOS singleton; moved IOSSet* functions to iosManager receiver methods; updated C-bridge documentation; changed all event emissions from native:* to common:* for cross-platform features (location, biometric, motion, proximity, keyboard, screen capture, capture, torch) and ios:* for platform-exclusive features (background task), plus safe-area event.
iOS event wiring and example updates
v3/examples/mobile/native_features_ios.go, v3/examples/mobile/ios_runtime_events_ios.go, v3/examples/ios/ios_runtime_events_ios.go
Updated iOS event registrations to call new application.IOS.* methods and emit common:* events; updated example event handler files to invoke application.IOS.Set* methods instead of application.IOSSet* functions while preserving parameter parsing logic.
Android native feature API refactoring
v3/pkg/application/mobile_features_android.go
Refactored Android bindings from exported Android* functions to methods on an Android singleton, delegating to the same JNI helpers while updating documentation to reference common:* event names.
Android event wiring and Java implementation updates
v3/examples/mobile/native_features_android.go, v3/examples/mobile/build/android/.../MainActivity.java, v3/examples/mobile/build/android/.../WailsBridge.java, v3/internal/commands/build_assets/android/.../MainActivity.java, v3/internal/commands/build_assets/android/.../WailsBridge.java
Updated Android event registrations to call new application.Android.* methods and emit common:* events; updated Java implementations in both example and build-asset directories to emit common:* (or android:* for foreground service) instead of native:* for all feature handlers including torch, biometric, notification, location, motion, proximity, keyboard, screen capture, camera capture, and lifecycle events.
Frontend event wiring refactoring
v3/examples/mobile/frontend/main.js
Comprehensive refactor of all mobile feature event channels from native:* to common:* with platform-specific ios:* and android:* prefixes; updated all emit/listen pairs for 30+ feature categories including share, URL open, keep-awake, torch, brightness, safe-area, app info, orientation, status-bar, biometric, notifications, secure storage, haptics, location, motion, proximity, speech, device queries, camera capture, foreground service, and background tasks.
Supporting documentation and comment updates
v3/examples/mobile/native_features_common.go, v3/examples/mobile/native_features_stub.go, v3/examples/mobile/README.md
Updated helper documentation comments from native:* to common:* event naming while preserving all functional logic.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Suggested labels

Documentation, Enhancement, v3-alpha

Poem

🐇 A tale of refactoring spreads far and wide,
From native:* to common:*, with platform pride.
iOS and Android now share the same call,
Through .IOS and .Android methods for all.
The docs bloom like clover, the guides shine so bright—
A fluffy mobile launch that's done just right! 🌸

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 70.18% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The PR title accurately summarizes the main changes: introducing IOS/Android manager API, renaming events, and adding first-class mobile documentation.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description check ✅ Passed PR description is comprehensive, well-structured, and includes clear summaries of both API refactoring and documentation changes with verification status.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch worktree-add-mobile-landing

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Updates the docs landing-page morphing headline to include “Mobile”, extending the existing Desktop → Server cycle to Desktop → Server → Mobile.

Changes:

  • Add "Mobile" to the words array used by the inline morphing script.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

- New Mobile section in sidebar (promoted out of Building & Packaging)
- Mobile overview page: how it works, prereqs table, feature matrix, build tag rules
- 'Your First Mobile App' tutorial: iOS Simulator + Android Emulator paths,
  step-by-step from zero to running app, responsive CSS, platform detection,
  haptics, production builds, troubleshooting
- iOS and Android guides moved to guides/mobile/; old paths redirect
- Landing page card updated: 'Mobile coming soon...' → iOS + Android listed
- Both platform guides link back to the first-mobile-app tutorial for newcomers
@leaanthony leaanthony changed the title docs: add Mobile to landing page MorphText cycle docs: add Mobile to landing page morph cycle + first-class mobile docs Jun 14, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docs/src/content/docs/guides/build/android.mdx`:
- Line 7: The redirect frontmatter fields in
docs/src/content/docs/guides/build/android.mdx (line 7) and
docs/src/content/docs/guides/build/ios.mdx (line 7) are not being processed
because there is no redirect handling mechanism configured. Implement redirect
handling by adding Astro's standard redirects configuration in astro.config.mjs
to map the old paths /guides/build/android and /guides/build/ios to their new
destinations /guides/mobile/android and /guides/mobile/ios respectively.
Alternatively, you can install a community plugin like astro-redirect-from to
process the custom redirect frontmatter fields. Choose one approach and
implement it to ensure the legacy URLs properly redirect to the mobile section
paths.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 95c93447-bae4-4a94-ae7c-8e3f2dbf6ac9

📥 Commits

Reviewing files that changed from the base of the PR and between 975bf48 and 7bfc222.

📒 Files selected for processing (8)
  • docs/astro.config.mjs
  • docs/src/content/docs/guides/build/android.mdx
  • docs/src/content/docs/guides/build/ios.mdx
  • docs/src/content/docs/guides/mobile/android.mdx
  • docs/src/content/docs/guides/mobile/first-mobile-app.mdx
  • docs/src/content/docs/guides/mobile/index.mdx
  • docs/src/content/docs/guides/mobile/ios.mdx
  • docs/src/content/docs/index.mdx
✅ Files skipped from review due to trivial changes (2)
  • docs/src/content/docs/index.mdx
  • docs/src/content/docs/guides/mobile/android.mdx

Comment thread docs/src/content/docs/guides/build/android.mdx Outdated
…name events

Convert the iOS and Android native-feature free functions into methods on
platform manager singletons:

  application.IOSShare(...)   -> application.IOS.Share(...)
  application.AndroidHaptic() -> application.Android.Haptic(...)
  application.IOSSetScrollEnabled(...) -> application.IOS.SetScrollEnabled(...)

`application.IOS` / `application.Android` are zero-size singletons that only
exist on their respective builds; all callers live in //go:build ios/android
files.

Rename the mobile bridge events away from the `native:*` prefix:
  - cross-platform events -> `common:*` (common:haptic, common:location, …)
  - iOS-only             -> `ios:*`     (ios:beginBackgroundTask, ios:backgroundTask)
  - Android-only         -> `android:*` (android:foregroundService)

The frontend keeps a single listener per event under `common:*`, matching the
shared-codebase model. Updated the Objective-C/C bridge, the Android Java
bridge (template + committed example build copy), the kitchen-sink example
(Go handlers + frontend), IOS.md/ANDROID.md, the docs-site mobile guides and
the unreleased changelog.

Refs #5602
@leaanthony leaanthony changed the title docs: add Mobile to landing page morph cycle + first-class mobile docs feat(v3/mobile): IOS/Android manager API + event rename; first-class mobile docs Jun 14, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@v3/examples/mobile/native_features_ios.go`:
- Around line 50-52: The issue is that `application.IOS.GetOrientation()`
returns a plain string value (like "portrait", "landscape", or "unknown"), not
JSON, so passing it to `jsonToMap()` will fail to parse and return an empty or
nil map. In the event handler for "common:getOrientation", replace the
`jsonToMap(application.IOS.GetOrientation())` call with a direct map
construction that wraps the orientation string as a map value, ensuring the
emitted event contains the proper map structure with the orientation data.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: cbc2893f-29f7-4750-9e03-b216faea9ba3

📥 Commits

Reviewing files that changed from the base of the PR and between f1d1230 and 9eb7752.

📒 Files selected for processing (23)
  • docs/src/content/docs/guides/mobile/first-mobile-app.mdx
  • docs/src/content/docs/guides/mobile/index.mdx
  • v3/ANDROID.md
  • v3/IOS.md
  • v3/UNRELEASED_CHANGELOG.md
  • v3/examples/ios/ios_runtime_events_ios.go
  • v3/examples/mobile/README.md
  • v3/examples/mobile/build/android/app/src/main/java/com/wails/app/MainActivity.java
  • v3/examples/mobile/build/android/app/src/main/java/com/wails/app/WailsBridge.java
  • v3/examples/mobile/frontend/main.js
  • v3/examples/mobile/ios_runtime_events_ios.go
  • v3/examples/mobile/native_features_android.go
  • v3/examples/mobile/native_features_common.go
  • v3/examples/mobile/native_features_ios.go
  • v3/examples/mobile/native_features_stub.go
  • v3/internal/commands/build_assets/android/app/src/main/java/com/wails/app/MainActivity.java
  • v3/internal/commands/build_assets/android/app/src/main/java/com/wails/app/WailsBridge.java
  • v3/pkg/application/ios_runtime_api.go
  • v3/pkg/application/mobile_features_android.go
  • v3/pkg/application/mobile_features_ios.go
  • v3/pkg/application/mobile_features_ios.h
  • v3/pkg/application/mobile_features_ios.m
  • v3/pkg/application/webview_window_ios.m
✅ Files skipped from review due to trivial changes (7)
  • v3/examples/mobile/native_features_stub.go
  • v3/examples/mobile/native_features_common.go
  • v3/pkg/application/webview_window_ios.m
  • v3/examples/mobile/README.md
  • v3/UNRELEASED_CHANGELOG.md
  • v3/pkg/application/mobile_features_ios.h
  • docs/src/content/docs/guides/mobile/index.mdx
🚧 Files skipped from review as they are similar to previous changes (1)
  • docs/src/content/docs/guides/mobile/first-mobile-app.mdx

Comment thread v3/examples/mobile/native_features_ios.go
IOS.GetOrientation() returns a plain string ('portrait'/'landscape'/…),
not JSON, so jsonToMap() failed to parse it and emitted an empty map.
Wrap it under the 'orientation' key the frontend reads (matching the
Android handler). Caught in CodeRabbit review of #5602.

Refs #5602
…dia type

mfPresentCamera set picker.mediaTypes to public.movie/public.image without
checking the camera actually offers that type. On the iOS Simulator (and any
device whose camera reports available but does not support video) the virtual
camera exposes stills only, so requesting video made -[UIImagePickerController
setMediaTypes:] throw an uncaught NSException -> SIGABRT.

Check availableMediaTypesForSourceType: before configuring the picker and emit
a graceful common:capture error instead, with an @try/@catch safety net. Pre-
existing since #5562; surfaced by the Xcode 26 simulator's virtual camera.

Refs #5602
… media list

Follow-up to ec23d47: the previous fix pre-checked
availableMediaTypesForSourceType:, but that list is unreliable on the iOS
Simulator — it returns empty even when the camera is authorized and can
present, so the pre-check would wrongly block capture. Verified on-simulator:
the list stays empty across authorization states and a 3s poll, yet photo
capture presents fine.

Instead: photos use the picker's default media type (public.image, never
throws); video opts into public.movie inside an @try/@catch so the
'No available types for source 1' NSException degrades to a graceful
common:capture error instead of SIGABRT. Real devices list public.movie and
record normally.

Refs #5602
The pbxproj template left the c-archive PBXFileReference path and the build
phase's 'go build -o' path unquoted, so a productName containing a space (the
default config ships 'My Product') produced an invalid project.pbxproj —
Xcode reported 'The project main is damaged ... parse error'. Quote both
paths. Also give the mobile example a real, space-free productName
(KitchenSink) and identifier.

Refs #5602
…er control group

- Add NSFaceIDUsageDescription to the iOS Info.plist(s). Tapping Authenticate
  called LAContext biometric evaluation, which hard-crashes on a real device
  without this key (same class as the camera/mic keys). The crash left the app
  white-screening on relaunch; a clean reinstall + this key resolve it.
- Move result feedback out of one box at the bottom of each section into a
  compact inline output beside each control group (Share, Screen, Status bar,
  Security, Secure storage, Haptics, Location, Motion, Speech, Keyboard,
  Camera, Background), so results appear next to the control you tapped.

Refs #5602
WKWebView's renderer (WebContent) process is reaped by iOS under memory
pressure or after repeated background/foreground and launch cycles. With no
webViewWebContentProcessDidTerminate: handler the view stayed permanently
blank — the 'white screen on the 3rd+ launch' reported on device. Implement
the delegate method to reload and respawn the renderer. Framework-level fix;
affects all Wails v3 iOS apps.

Refs #5602
…lash

Two iOS fixes:
- ios_create_webview_with_id manually called -loadView and -viewDidLoad, so
  UIKit ALSO loaded the view automatically — two WebViews/viewDidLoad passes per
  cold launch. Content loaded into one while the blank one was displayed →
  intermittent white screen after force-quit + relaunch. Load the view once via
  -loadViewIfNeeded. Verified on-device: one viewDidLoad per launch, renders
  reliably across repeated force-quit relaunches.
- Also fix the missing withError: parameter on didFailProvisionalNavigation
  (the old selector never matched, so load failures were swallowed) and add a
  didFailNavigation:withError: handler.

Flash: any non-zero IOSOptions.BackgroundColour is now applied to the app
window automatically (no need to also set AppBackgroundColourSet), so the
window matches the web background instead of flashing white before the WebView
paints. The mobile example sets it to its web background (#1b2636).

Refs #5602
The flag only existed to distinguish a deliberate fully-transparent app window
({0,0,0,0}) from the unset zero value — but a transparent app-window background
is meaningless (the window needs an opaque backing), so the distinction had no
real use. Drop it and treat any non-zero BackgroundColour as set; the zero
value means unset (defaults to white). Simpler API, one field instead of two.

Refs #5602
The app declared UILaunchStoryboardName but the build never bundled a compiled
storyboard, so iOS showed a white default launch screen; and the window was
created white in the delegate before Go could apply a background colour. Both
caused a white flash on (cold) launch.

- Add a LaunchBackground colour asset (#1b2636) and switch Info.plist(s) to
  UILaunchScreen { UIColorName = LaunchBackground } — bundled via the asset
  catalog the build already compiles.
- Colour the initial UIWindow/root view from the same LaunchBackground asset in
  didFinishLaunching (timing-independent; falls back to white if absent).

Refs #5602
iOS suppresses a local notification's banner while the app that posted it is
in the foreground unless the app registers a UNUserNotificationCenterDelegate
and opts into presentation. Wails registered no such delegate, so notifications
fired but were delivered silently to Notification Center with no banner.

Add an MFNotificationDelegate (UNUserNotificationCenterDelegate) whose
willPresentNotification returns banner+list+sound (alert+sound pre-iOS 14) and
didReceiveNotificationResponse handles taps. Register it via
ios_notifications_init() — both at launch (see delegate change) and defensively
at the top of ios_post_notification so it is set regardless of build path.

The mobile example surfaces the new common:notification {presented}/{tapped}
signals so foreground delivery is visible in the UI.
Start the Go runtime from the app delegate's didFinishLaunchingWithOptions
(after UIKit has launched) instead of concurrently with UIApplicationMain,
which intermittently corrupted the FrontBoard launch handshake on device
(blank cold launch / 0x8BADF00D). main.m is now a minimal bootstrap; because
it no longer references a Go symbol the archive must be linked with
-Wl,-force_load (set in all iOS Taskfiles) or the WailsAppDelegate class is
dead-stripped.

Also: register the notification delegate before launch finishes; remove the
dead, archive-less build.sh.tmpl (+ rendered copies); align the older
examples/ios bootstrap with the verified examples/mobile pattern; tidy the
example go.mod.
Three bugs prevented a plain 'wails3 init' app from building/running on iOS,
while the in-repo examples masked them:

- overlay:gen read its main_ios.go template from the wails SOURCE TREE via
  repoRoot(); outside the wails repo that path doesn't exist, so it failed with
  'file does not exist'. Read it from the embedded build_assets FS instead
  (same approach as xcode:gen).
- run/deploy-simulator/deploy-device hardcoded a com.wails.<app>[.dev] bundle
  id for simctl/devicectl, but the real id comes from build/config.yml (e.g.
  com.example.<app>). simctl install succeeded but launch failed (code 4). Read
  CFBundleIdentifier from the built bundle's Info.plist instead.
- the iOS build depended on common:generate:icons (icns/ico — not used by iOS,
  and its dir:build broke through the nested include) and a redundant
  generate:ios:bindings that raced build:frontend's own bindings -clean. Both
  removed; iOS icons come from Assets.xcassets via actool and bindings from
  build:frontend.

Verified end-to-end: 'wails3 init' + 'wails3 task ios:run' builds, installs and
launches a default app on the iOS Simulator.
…verified simulator screenshot

- ios.mdx: replace the inaccurate runtime blurb (which mixed Go and JS APIs and
  referenced a non-existent IOS.Scroll.SetEnabled JS call) with proper sections:
  * 'Native device features — the IOS manager': the Go application.IOS.* pattern
    (one-shot actions, JSON query helpers) with correct Haptic values.
  * 'Asynchronous results: common:* and ios:* events': the event model with a
    full table mapping each event to the manager call that triggers it and its
    payload (common:* = shared with Android, ios:* = iOS-only).
  * 'Runtime WebView controls': the Go SetScrollEnabled/... toggles plus the
    real frontend runtime (IOS.Haptics.Impact, IOS.Device.Info).
- first-mobile-app.mdx: add a screenshot of a default 'wails3 init' app running
  on the iOS Simulator, captured by actually running the tutorial end to end.

The tutorial's command sequence (wails3 init -> wails3 task ios:run -> ios:logs:dev
-> ios:xcode) was verified by running it against a fresh project on the Simulator.
On a phone the starter app's 'Wails + <Framework>' heading (font-size: 3.2em)
overflowed and wrapped onto two lines, and content ran to the screen edges
under the notch. Applied the same responsive treatment to every template's
style.css and index.html:

- h1 uses clamp(1.9rem, 8vw, 3.2rem) so it fits one line on phones and stays
  3.2rem on desktop.
- .container gets box-sizing, a 720px max-width and safe-area-aware padding
  (env(safe-area-inset-*)) so content clears the notch/home indicator.
- logos cap at 40vw and shrink on <=480px viewports.
- viewport meta gains viewport-fit=cover so the safe-area insets apply on iOS.

Verified on the iOS Simulator with a fresh 'wails3 init' app: the heading now
renders on a single line. The docs tutorial screenshot is updated to match.
- The mobile guides stated 'Go 1.24+', but the generated project's go.mod (and
  wails/v3) require go 1.25.0. Corrected to 1.25+ in ios, android,
  first-mobile-app and the index requirements table.
- first-mobile-app: replaced the six-bullet technical breakdown of 'wails3 task
  ios:run' (Xcode scaffold, c-archive, GOOS=ios, ad-hoc signing, ...) with a
  single beginner-friendly sentence plus a short 'first run is slow' tip.

Verified against the code: config.yml keys (bundleID/displayName/version/
minIOSVersion), IOSOptions fields, and the what-works table (save-file dialog
error, UIPasteboard clipboard, UIDocumentPicker) are all accurate.
A plain 'wails3 init' app could not run on Android. Four bugs, the same class
as the iOS ones (masked by the in-repo example):

- ensure-emulator had a go-task template with backslash-escaped quotes
  ({{if eq .HOST_ARCH \"arm64\"}}) that fails to parse ('unexpected \ in
  operand'), aborting any android task. Replaced with a precomputed ANDROID_ABI
  var.
- gradlew lost its executable bit when extracted from the embedded build assets
  ('permission denied', exit 127). chmod +x before invoking it.
- the app launched but showed ERR_CONNECTION_REFUSED: the c-shared library has
  no main registered because main_android.go (which calls
  application.RegisterAndroidMain in init) was only extracted to build/android/,
  not the main package. Added 'wails3 android overlay:gen' (mirrors iOS
  overlay:gen) to inject main_android.gen.go into the main package via
  -overlay, wired into the c-shared build.
- dropped the bogus common:generate:icons (unused on android, breaks through the
  nested include) and redundant generate:android:bindings (races
  build:frontend's own bindings) deps.

Verified end to end: a fresh 'wails3 init' app builds, installs and renders on
the Android emulator.
…approach

- ensure-emulator: start the emulator via 'nohup sh -c "... &"' so it is
  reparented to launchd and survives go-task reaping background jobs (a bare
  'emulator &' is killed before the install/launch steps run); also tolerate the
  logcat grep exiting non-zero.
- example: bring build/android/Taskfile.yml in line with the template (overlay
  wiring, gradlew chmod, dropped bogus deps) and remove the hand-written root
  main_android.go — the build overlay now injects main registration, so the
  example matches what a fresh project generates. Update main.go's comment to
  describe the ios/android overlay mechanism.

Verified on the Android emulator: both a fresh 'wails3 init' app and the
kitchen-sink example build, install and render (dark mode).
The iOS/Android build overlays (overlay.json + gen/) contain per-machine
absolute paths and are regenerated each build, so they must not be committed.
The example already ignored the iOS ones; add the Android equivalents, and add
both to the fresh-project template .gitignore so 'wails3 init' projects ignore
them too.
…kfile

(Completes the previous commit, whose git add aborted on an already-removed
path and silently dropped these files.)

- ensure-emulator: daemonize the emulator via 'nohup sh -c "... &"' so it
  survives go-task reaping background jobs; tolerate the logcat grep exiting
  non-zero.
- example: sync build/android/Taskfile.yml with the template (overlay wiring,
  gradlew chmod, dropped bogus deps) and update main.go's comment to describe
  the ios/android overlay mechanism (root main_android.go was already removed).
@leaanthony leaanthony merged commit b12f507 into master Jun 15, 2026
14 of 15 checks passed
@leaanthony leaanthony deleted the worktree-add-mobile-landing branch June 15, 2026 13:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants