Mobile Apps
irgo enables you to build native iOS and Android apps using Go, HTML, and HTMX. The mobile architecture uses a "virtual HTTP" approach where requests are handled in-process without network sockets.
How Mobile Mode Works
┌─────────────────────────────────────────┐│ Mobile App ││ ┌─────────────────────────────────┐ ││ │ WebView (HTMX) │ ││ │ • HTML rendered by Go templates │ ││ │ • Requests via irgo:// scheme │ ││ └──────────────┬──────────────────┘ ││ │ ││ ┌──────────────▼──────────────────┐ ││ │ Native Bridge (Swift/Kotlin) │ ││ │ • Intercepts irgo:// requests │ ││ │ • Routes to Go via gomobile │ ││ └──────────────┬──────────────────┘ ││ │ ││ ┌──────────────▼──────────────────┐ ││ │ Go Runtime (gomobile bind) │ ││ │ • HTTP router (chi) │ ││ │ • Template rendering (templ) │ ││ │ • Business logic │ ││ └─────────────────────────────────┘ │└─────────────────────────────────────────┘Key characteristics:
- No network sockets - Requests never leave the device
- In-process execution - Go handlers run directly in the app process
- Custom URL scheme - HTMX uses
irgo://for requests - gomobile binding - Go code compiled to native frameworks
Prerequisites
Common Requirements
- Go 1.21+
- gomobile:
go install golang.org/x/mobile/cmd/gomobile@latest && gomobile init - entr (for hot reload):
brew install entr(macOS)
iOS Development
- macOS with Xcode installed
- iOS Simulator or physical device
- Apple Developer account (for device deployment)
Android Development
- Android Studio with SDK installed
- Android NDK (install via SDK Manager)
- Android Emulator or physical device
Mobile Entry Point
The mobile entry point uses the !desktop build tag:
//go:build !desktoppackage mainimport ( "fmt" "log" "net/http" "os" "myapp/app" "github.com/stukennedy/irgo/mobile")func main() { // If run with "serve" argument, start web dev server if len(os.Args) > 1 && os.Args[1] == "serve" { runDevServer() return } // Otherwise, initialize for mobile initMobile()}func initMobile() { mobile.Initialize() r := app.NewRouter() mobile.SetHandler(r.Handler()) fmt.Println("Mobile app initialized")}func runDevServer() { r := app.NewRouter() mux := http.NewServeMux() mux.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.Dir("static")))) mux.Handle("/", r.Handler()) fmt.Println("Dev server at http://localhost:8080") log.Fatal(http.ListenAndServe(":8080", mux))}iOS Development
Development with Hot Reload
# Start iOS Simulator with hot reloadirgo run ios --devThis watches for changes in your Go and templ files, rebuilds the framework, and refreshes the Simulator automatically.
Production Build
# Build iOS frameworkirgo build ios# Build and run on Simulatorirgo run iosBuild Output
build/ios/└── Irgo.xcframework/ ├── ios-arm64/ │ └── Irgo.framework/ # Device framework └── ios-arm64_x86_64-simulator/ └── Irgo.framework/ # Simulator frameworkXcode Integration
- Open your Xcode project in
ios/ - Drag
Irgo.xcframeworkinto your project - Ensure "Embed & Sign" is selected in Frameworks settings
- Build and run from Xcode
Android Development
Development with Hot Reload
# Start Android Emulator with hot reloadirgo run android --devProduction Build
# Build Android AARirgo build android# Build and run on Emulatorirgo run androidBuild Output
build/android/└── irgo.aar # Android ArchiveAndroid Studio Integration
- Open your Android project in
android/ - Copy
irgo.aartoapp/libs/ - Add to
build.gradle:implementation files('libs/irgo.aar') - Build and run from Android Studio
The Virtual HTTP Adapter
The mobile bridge uses an HTTP adapter that executes handlers in memory:
// The adapter converts core.Request/Response to net/http// This happens automatically when you call mobile.SetHandler()import "github.com/stukennedy/irgo/pkg/adapter"// The adapter executes handlers without network I/Oadapter := adapter.NewHTTPAdapter(handler)// Native code calls this with request dataresponse := adapter.HandleRequest(request)The adapter uses special core.Request and core.Response types that are compatible with gomobile (which doesn't support maps or slices of custom types).
Static Assets on Mobile
Static files are bundled into the native app and served via the Go runtime:
// In your router setupr := router.New()// Embed static files//go:embed staticvar staticFS embed.FS// Serve embedded filesr.StaticFS("/static", http.FS(staticFS))Debugging Mobile Apps
iOS Debugging
- Open Safari and go to Develop menu
- Select your Simulator or device
- Choose your app's WebView
- Use Safari Web Inspector to debug
Android Debugging
- Open Chrome and go to
chrome://inspect - Your app's WebView should appear under "Remote Target"
- Click "inspect" to open DevTools
Enable WebView debugging in your native code for production builds if needed. For security, disable it in release builds.
Mobile vs Desktop Comparison
| Aspect | Mobile | Desktop |
|---|---|---|
| HTTP | Virtual (no sockets) | Real localhost server |
| Bridge | gomobile + native code | None (direct HTTP) |
| Entry Point | main.go | main_desktop.go |
| Build Tag | !desktop | desktop |
| CGO Required | No | Yes (webview) |
| Build Tool | gomobile bind | go build |
Troubleshooting
gomobile not found
go install golang.org/x/mobile/cmd/gomobile@latestgomobile initAndroid NDK not found
Install via Android Studio SDK Manager, or set:
export ANDROID_HOME=$HOME/Library/Android/sdkexport ANDROID_NDK_HOME=$ANDROID_HOME/ndk/<version>iOS build fails
Ensure Xcode CLI tools are installed and selected:
xcode-select --installsudo xcode-select -s /Applications/Xcode.app/Contents/DeveloperNext Steps
- Desktop Apps - Desktop development
- Deployment - App store distribution
- Examples - Sample mobile applications
