Add the dependency, capture traffic, connect the desktop companion. Android auto-initializes; iOS needs a few more steps.
Alohomora is published to Maven Central. Most projects already include mavenCentral() in their repository list. If yours doesn't:
dependencyResolutionManagement { repositories { mavenCentral() } }
No authentication or tokens required.
Add the debug library and the release no-op stub. The no-op module mirrors every public method but compiles to nothing after R8.
dependencies { debugImplementation("io.github.yashkasera:alohomora:1.0.0") releaseImplementation("io.github.yashkasera:alohomora-noop:1.0.0") }
init() call needed.
Optional. The Gradle plugin injects build metadata (Git branch, commit SHA, dirty flag, recent commits) into your debug build at compile time. This data appears in the Config and Git History tabs of the console.
plugins { id("io.github.yashkasera.alohomora") version "1.0.0" } alohomora { enabledVariants = setOf("debug") maxCommits = 50 versionName = project.version.toString() versionCode = 1 slackWebhookUrl = "https://hooks.slack.com/services/..." }
versionName is required when the plugin is applied.slackWebhookUrl is automatically dropped for non-debuggable variants to prevent the webhook from shipping in a release APK.enabledVariants controls which build variants get the generated config. Defaults to debug only.Wire up your HTTP client so Alohomora can capture requests and responses. Both OkHttp and Ktor are supported out of the box.
val client = OkHttpClient.Builder() .addInterceptor(TrafficInterceptor()) .build()
val client = HttpClient { install(AlohomoraInspector) }
For HTTP clients not covered by the interceptors above, use the manual recording API:
Alohomora.recordTraffic( url = "https://api.example.com/users", method = "GET", requestHeaders = headers, responseCode = 200, responseBody = body )
Optional. Register a replay handler so captured traffic can be edited and re-sent from the console or the desktop companion. The request goes back through your app's own client, so interceptors regenerate auth headers and signatures.
Alohomora.registerReplayHandler( okHttpReplayHandler(client) )
Alohomora.registerReplayHandler( ktorReplayHandler(client) )
For custom signing or clients that need extra handling, use the lambda form:
Alohomora.registerReplayHandler { request -> // Sign the request, send it through your client, return the response myClient.execute(request.sign()) }
OkHttpClient you give to Retrofit.Builder().client(...) into okHttpReplayHandler(). Retrofit delegates to OkHttp for actual HTTP calls, so this covers it. There is no separate Retrofit handler.
The desktop app connects to your device via ADB port forwarding and renders all captured data in a standalone window. Build it from source or download a pre-built package.
# Run directly ./gradlew :desktopApp:run # Package for distribution ./gradlew :desktopApp:packageDmg # macOS .dmg ./gradlew :desktopApp:packageMsi # Windows .msi ./gradlew :desktopApp:packageDeb # Linux .deb
The desktop app discovers connected devices over ADB and sets up TCP port forwarding automatically. Select a device from the launcher, and a per-device window opens with live data streaming.
The library ships as a static framework named AlohomoraKit.
Swift Package Manager (recommended): In Xcode, go to File → Add Package Dependencies and enter the repository URL:
https://github.com/yashkasera/Alohomora
Select the AlohomoraKit library product. SPM downloads the prebuilt XCFramework from the matching GitHub Release automatically. No manual framework embedding or build settings required.
Manual (from Gradle output): If your iOS app lives in the same repo, you can link the framework directly. Add a Run Script build phase before "Compile Sources":
cd "$SRCROOT/.." ./gradlew :alohomora:embedAndSignAppleFrameworkForXcode
Then add the output directory to your target's Framework Search Paths:
FRAMEWORK_SEARCH_PATHS = $(SRCROOT)/../alohomora/build/xcode-frameworks/$(CONFIGURATION)/$(SDK_NAME)
Unlike Android, iOS requires an explicit init call. Note that Kotlin's init() is exported to Swift as doInit() to avoid collision with Swift's initializer syntax.
import AlohomoraKit func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { Alohomora.shared.doInit() Alohomora.shared.startDevToolsServer(port: 53999) return true }
URLSession.shared cannot be intercepted. Use the provided configuration factory or wrap your existing configuration:
// Option A: use the provided configuration let session = URLSession(configuration: Alohomora.shared.alohomoraURLSessionConfiguration()) // Option B: wrap your existing configuration let config = URLSessionConfiguration.default // ... your customization ... let session = URLSession(configuration: Alohomora.shared.wrapConfiguration(config))
Shake-to-open is built in. To present the console programmatically, use MainKt.MainViewController() and present it as a sheet:
let vc = MainKt.MainViewController() // Present as a sheet with drag indicator vc.sheetPresentationController?.detents = [.large()] vc.sheetPresentationController?.prefersGrabberVisible = true present(vc, animated: true)
.prefersGrabberVisible? The Compose-based console has no native iOS navigation chrome. The drag indicator gives users a visible affordance to dismiss the sheet.
The Gradle plugin has no iOS counterpart. Instead, a shell script runs from an Xcode build phase and writes Git metadata into the app bundle as a JSON file that the library reads at init.
In Xcode, add a new Run Script phase after "Copy Bundle Resources":
"$SRCROOT/../scripts/alohomora-build-info.sh"
git, which the sandbox blocks.| Variable | Default | Description |
|---|---|---|
ALOHOMORA_MAX_COMMITS |
50 | Number of recent commits to embed in the bundle. |
ALOHOMORA_SLACK_WEBHOOK_URL |
none | Slack webhook for sharing from the console. Only included when CONFIGURATION is Debug. |
Bundle.main at runtime (CFBundleShortVersionString and CFBundleVersion), so there is no second source of truth to keep in sync.