0000 70 6f 72 74 68 6f 6c 65 |porthole|
An in-app network inspector for iOS & macOS. no proxy · no certificates · no desktop app · just a SwiftUI viewer compiled into your build.
0000 6e 6f 20 70 72 6f 78 79 2e 20 6e 6f 20 63 65 72 |no proxy. no cer| 0010 74 2e |t.|
Porthole hooks your app’s URLSession traffic and records every request, response, and WebSocket frame in memory, then renders them in a native SwiftUI viewer you drop anywhere. Interception happens in-process, so there is nothing to configure on the network.
A fork of Proxyman / Atlantis. Removes the Bonjour transport and desktop-app dependency, replaced by an on-device viewer.
GET api.acme.io/v1/user 200 142 ms POST api.acme.io/v1/login 201 318 ms GET cdn.acme.io/feed.json 304 11 ms WS socket.acme.io/live ↑↓ open GET cdn.acme.io/avatar.png 500 902 ms
Every feature, laid out as header fields. Read it like a packet.
0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
0000 73 77 69 66 74 20 70 61 63 6b 61 67 65 20 61 64 |swift package ad| 0010 64 |d|
Add via Swift Package Manager: File › Add Package Dependencies…, or in Package.swift:
// Package.swift dependencies: [ .package( url: "https://github.com/sohandotgit/Porthole.git", branch: "main" ) ]
Begin capture once, early in the app lifecycle, guarded to debug builds.
import SwiftUI #if DEBUG import Atlantis #endif @main struct MyApp: App { init() { #if DEBUG Atlantis.start() #endif } var body: some Scene { WindowGroup { ContentView() } } }
Present the built-in viewer anywhere: a sheet, a tab, or a shake-gesture overlay.
import Atlantis struct DebugMenu: View { @State private var showTraffic = false var body: some View { Button("Network Log") { showTraffic = true } .sheet(isPresented: $showTraffic) { NavigationStack { AtlantisTrafficListView() } } } }
The shared TrafficStore exposes runtime controls.
| MEMBER | TYPE | DESCRIPTION |
|---|---|---|
| clear() | func | Empties the ring buffer and removes all recorded traffic. |
| isPaused | Bool | When true, new requests are ignored until resumed. |
| capacity | Int | Maximum entries retained; oldest are evicted first. Default 500. |
iOS 16.0+ · macOS 11+ · Mac Catalyst 13.0+ · tvOS 13.0+ · watchOS 10.0+ · Xcode 14+ · Swift 5.0+. No third-party dependencies.
Capture is memory-only: traffic lives in a bounded in-memory store for the process lifetime and is never written to disk or sent off-device. Debugging tools like Map Local, Breakpoint, and Scripting aren't supported; use a normal proxy for those. Keep Atlantis.start() behind #if DEBUG so no interception ships in release.
0000 6d 65 6d 6f 72 79 20 6f 6e 6c 79 |memory only|