IOS_ARCHITECTURE.md
This document provides a comprehensive technical architecture for iOS support in Wails v3. The implementation enables Go applications to run natively on iOS with a WKWebView frontend, maintaining the Wails philosophy of using web technologies for UI while leveraging Go for business logic.
┌─────────────────────────────────────────────────────────────┐
│ iOS Application │
├─────────────────────────────────────────────────────────────┤
│ UIKit Framework │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ WailsViewController │ │
│ │ ┌───────────────────────────────────────────────┐ │ │
│ │ │ WKWebView Instance │ │ │
│ │ │ ┌─────────────────────────────────────────┐ │ │ │
│ │ │ │ Web Application (HTML/JS) │ │ │ │
│ │ │ └─────────────────────────────────────────┘ │ │ │
│ │ └───────────────────────────────────────────────┘ │ │
│ └─────────────────────────────────────────────────────┘ │
├─────────────────────────────────────────────────────────────┤
│ Bridge Layer (CGO) │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │URL Handler │ │JS Bridge │ │Message Handler│ │
│ └──────────────┘ └──────────────┘ └──────────────┘ │
├─────────────────────────────────────────────────────────────┤
│ Go Runtime │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ Wails Application │ │
│ │ ┌──────────┐ ┌──────────┐ ┌──────────────────┐ │ │
│ │ │App Logic │ │Services │ │Asset Server │ │ │
│ │ └──────────┘ └──────────┘ └──────────────────┘ │ │
│ └──────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
application_ios.go)Purpose: Go interface for iOS platform operations
Key Functions:
platformRun(): Initialize and run the iOS applicationplatformQuit(): Gracefully shutdown the applicationisDarkMode(): Detect iOS dark mode stateExecuteJavaScript(windowID uint, js string): Execute JS in WebViewExported Go Functions (Called from Objective-C):
ServeAssetRequest(windowID C.uint, urlStr *C.char, callbackID C.uint)HandleJSMessage(windowID C.uint, message *C.char)application_ios.m)Components:
@interface WailsSchemeHandler : NSObject <WKURLSchemeHandler>
WKURLSchemeHandler protocolwails:// URL requestsMethods:
startURLSchemeTask:: Intercept request, call Go handlerstopURLSchemeTask:: Cancel pending requestcompleteRequest:withData:mimeType:: Complete request with data from Go@interface WailsMessageHandler : NSObject <WKScriptMessageHandler>
window.webkit.messageHandlers.external.postMessage()Methods:
userContentController:didReceiveScriptMessage:: Process JS messages@interface WailsViewController : UIViewController
Properties:
webView: WKWebView instanceschemeHandler: Custom URL scheme handlermessageHandler: JS message handlerwindowID: Unique window identifierMethods:
viewDidLoad: Initialize WebView with configurationexecuteJavaScript:: Run JS code in WebViewC Interface Functions:
void ios_app_init(void); // Initialize iOS app
void ios_app_run(void); // Run main loop
void ios_app_quit(void); // Quit application
bool ios_is_dark_mode(void); // Check dark mode
unsigned int ios_create_webview(void); // Create WebView
void ios_execute_javascript(unsigned int windowID, const char* js);
void ios_complete_request(unsigned int callbackID, const char* data, const char* mimeType);
Responsibilities:
Key Features:
Request Interception:
WebView Request → WKURLSchemeHandler → Go ServeAssetRequest → AssetServer → Response
JavaScript Bridge:
JS postMessage → WKScriptMessageHandler → Go HandleJSMessage → Process → ExecuteJavaScript
Components:
iOS-Specific Features:
wails://localhost/pathWKURLSchemeTaskServeAssetRequest with URL and callback IDios_complete_request with response dataWKURLSchemeTask with responseios_execute_javascript with JS codewindow.webkit.messageHandlers.wails.postMessage(data)HandleJSMessageExecuteJavaScript// Disable unnecessary features
config.suppressesIncrementalRendering = NO;
config.allowsInlineMediaPlayback = YES;
config.mediaTypesRequiringUserActionForPlayback = WKAudiovisualMediaTypeNone;
//go:build ios
#cgo CFLAGS: -x objective-c -fobjc-arc
#cgo LDFLAGS: -framework Foundation -framework UIKit -framework WebKit
build_ios.sh)Steps:
Environment Variables:
export CGO_ENABLED=1
export GOOS=ios
export GOARCH=arm64
export SDK_PATH=$(xcrun --sdk iphonesimulator --show-sdk-path)
xcrun simctl install "$DEVICE_ID" "WailsIOSDemo.app"
xcrun simctl launch "$DEVICE_ID" "com.wails.iosdemo"
wails:// to avoid conflicts// Create new iOS application
app := application.New(application.Options{
Name: "App Name",
Description: "App Description",
})
// Run the application
app.Run()
// Execute JavaScript
app.ExecuteJavaScript(windowID, "console.log('Hello')")
type MyService struct{}
func (s *MyService) Greet(name string) string {
return fmt.Sprintf("Hello, %s!", name)
}
app := application.New(application.Options{
Services: []application.Service{
application.NewService(&MyService{}),
},
})
window.webkit.messageHandlers.wails.postMessage({
type: 'methodCall',
service: 'MyService',
method: 'Greet',
args: ['World']
});
window.wailsCallback = function(data) {
console.log('Received:', data);
};
// Execute JavaScript
ios_execute_javascript(windowID, "alert('Hello')");
// Complete asset request
ios_complete_request(callbackID, htmlData, "text/html");
// Serve asset request
ServeAssetRequest(windowID, urlString, callbackID);
// Handle JavaScript message
HandleJSMessage(windowID, jsonMessage);
This architecture provides a solid foundation for iOS support in Wails v3. The design prioritizes battery efficiency, native performance, and seamless integration with the existing Wails ecosystem. The proof of concept demonstrates all four required capabilities:
The architecture is designed to scale from this proof of concept to a full production implementation while maintaining the simplicity and elegance that Wails developers expect.