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:

Prerequisites

Common Requirements

iOS Development

Android Development

Mobile Entry Point

The mobile entry point uses the !desktop build tag:

main.go
//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 --dev

This 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 ios

Build Output

build/ios/└── Irgo.xcframework/    ├── ios-arm64/    │   └── Irgo.framework/     # Device framework    └── ios-arm64_x86_64-simulator/        └── Irgo.framework/     # Simulator framework

Xcode Integration

  1. Open your Xcode project in ios/
  2. Drag Irgo.xcframework into your project
  3. Ensure "Embed & Sign" is selected in Frameworks settings
  4. Build and run from Xcode

Android Development

Development with Hot Reload

# Start Android Emulator with hot reloadirgo run android --dev

Production Build

# Build Android AARirgo build android# Build and run on Emulatorirgo run android

Build Output

build/android/└── irgo.aar                    # Android Archive

Android Studio Integration

  1. Open your Android project in android/
  2. Copy irgo.aar to app/libs/
  3. Add to build.gradle: implementation files('libs/irgo.aar')
  4. 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)
Note

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

  1. Open Safari and go to Develop menu
  2. Select your Simulator or device
  3. Choose your app's WebView
  4. Use Safari Web Inspector to debug

Android Debugging

  1. Open Chrome and go to chrome://inspect
  2. Your app's WebView should appear under "Remote Target"
  3. Click "inspect" to open DevTools
Tip

Enable WebView debugging in your native code for production builds if needed. For security, disable it in release builds.

Mobile vs Desktop Comparison

AspectMobileDesktop
HTTPVirtual (no sockets)Real localhost server
Bridgegomobile + native codeNone (direct HTTP)
Entry Pointmain.gomain_desktop.go
Build Tag!desktopdesktop
CGO RequiredNoYes (webview)
Build Toolgomobile bindgo build

Troubleshooting

gomobile not found

go install golang.org/x/mobile/cmd/gomobile@latestgomobile init

Android 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/Developer

Next Steps