This sample shows how to route Flutter HTTP traffic through Rockxy while keeping certificate and proxy changes limited to debug builds.
Flutter apps do not always inherit a system proxy automatically. The reliable manual path is:
- choose the Rockxy proxy host for the runtime running the app;
- copy Rockxy's active proxy port from the Rockxy app into the Flutter client;
- run the local demo API on this Mac;
- send one known request and confirm it appears in Rockxy.
For HTTPS inspection, complete the iOS or Android certificate trust path after the HTTP capture path is working.
| Runtime | Host value |
|---|---|
| iOS Simulator | 127.0.0.1:<Rockxy port> |
| macOS desktop Flutter | 127.0.0.1:<Rockxy port> |
| Android Emulator | 10.0.2.2:<Rockxy port> |
| Physical iPhone, iPad, or Android device | <Device Proxy LAN host>:<Rockxy port> |
The active Rockxy port is shown in the Rockxy toolbar. For physical devices, use the Device Proxy LAN host shown in Developer Setup Hub and keep the device on the same local network as the Mac.
Only choose Android Emulator when the Flutter app itself is running inside an
Android emulator. If you run this sample as a macOS desktop app, choose
iOS Simulator / macOS desktop; 10.0.2.2 is an Android-emulator-only route
back to the Mac.
- Start Rockxy and keep capture enabled.
- Open Developer Setup Hub > Flutter.
- Pick the runtime that matches where the Flutter app is running.
- Copy the active Rockxy proxy port from the Rockxy toolbar.
- Paste that value into the sample app's
Rockxy portfield. - Set the
Demo API base URLseparately from the Rockxy proxy target. - Run the local demo API:
fvm dart run tool/rockxy_demo_api.dart --port 43210- Run the Flutter sample and run
Known-good app startup. - Confirm Rockxy captures requests with
X-Rockxy-Lab-Run-Id,X-Rockxy-Scenario-Id, andX-Rockxy-Step-Idheaders.
For HTTPS app traffic, also install and trust the Rockxy certificate for that runtime:
- iOS Simulator: install/trust the certificate in the simulator.
- Physical iPhone or iPad: install the certificate profile and enable full trust in iOS settings.
- Android Emulator: install the user certificate and run a debug build that trusts user CAs.
- Physical Android device: set the Wi-Fi proxy to the Device Proxy LAN host, install the user certificate, and run a debug build that trusts user CAs.
Install FVM once, then run the sample through the project-pinned Flutter SDK:
brew install fvm
git clone https://github.com/RockxyApp/Rockxy-Flutter-Sample-Guidance.git
cd Rockxy-Flutter-Sample-Guidance
fvm use stable
fvm flutter pub get
fvm dart run tool/rockxy_demo_api.dart --port 43210In another terminal, run the Flutter app:
fvm flutter runIf you want to target a specific runtime, start the simulator or emulator first, then choose the matching Flutter device:
List the devices Flutter can see:
fvm flutter devicesRun the sample as a macOS desktop app:
fvm flutter run -d macosRun the sample in iOS Simulator:
open -a Simulator
fvm flutter run -d iosIf -d ios is not specific enough on your machine, pick the simulator ID from
fvm flutter devices and run with that device ID instead.
Run the sample in Android Emulator:
fvm flutter emulators
fvm flutter emulators --launch <android_emulator_id>
fvm flutter run -d emulator-5554If you prefer the Android SDK emulator command directly, start an AVD first and then run Flutter on the connected emulator:
emulator -avd <avd_name>
fvm flutter run -d emulator-5554Choose the matching runtime inside the sample app after it launches:
- macOS desktop:
iOS Simulator / macOS desktop - iOS Simulator:
iOS Simulator / macOS desktop - Android Emulator:
Android Emulator - Physical device:
Physical device
Before pressing Run Scenario, copy the active proxy port from Rockxy and paste
it into the sample app's Rockxy port field. Do not assume 9090; Rockxy can
run on another configured or fallback port, such as 8888.
The repository tracks .fvmrc, so you can switch versions later without
changing global Flutter:
fvm use 3.32.8
fvm flutter doctor
fvm flutter testThe generated Android debug target already includes the same debug-only trust
configuration shown in snippets/android/app/src/debug.
Use harmless, clearly fake data when recording a Rockxy demo. The sample app now runs scenario groups instead of a single request. Each step emits correlation headers so you can search and filter in Rockxy:
X-Rockxy-LabX-Rockxy-Lab-Run-IdX-Rockxy-Scenario-IdX-Rockxy-Step-IdX-Rockxy-ClientX-Rockxy-RuntimeX-Request-ID
Rockxy can capture this loopback demo when the Flutter client explicitly routes
the request through Rockxy. Do not rely on the operating system proxy alone for
localhost traffic because system bypass settings commonly exclude localhost
and 127.0.0.1.
Use these scenario groups to demonstrate Rockxy features together:
Known-good app startup: baseline capture, headers, response body, timing.Wrong backend environment: use Map Remote to rewrite environment traffic.Expired token and retry: inspect auth headers, modify headers, and replay.Checkout body and response contract: inspect POST bodies and schema mismatch.Slow and failed network calls: use status filters, Block List, and latency.Scripted response mutation: use scripting when static rules are not enough.
Run one scenario first, then use Run All when you want a full capture timeline.
In Rockxy, filter by the run ID shown in the app.
Use the sample as a guided debugging workbook. Move from the easy cases to the harder ones so each step has a known baseline:
| Case | Sample step | Rockxy feature | Evidence to collect |
|---|---|---|---|
| 0 | app-startup/bootstrap |
Capture and inspector | URL, method, headers, 200 JSON body, timing |
| 1 | app-startup/runtime-diagnostic |
Runtime proxy setup | 127.0.0.1, 10.0.2.2, or LAN host matches the runtime |
| 2 | Run All | Filters and Allow List | Rows isolated by X-Rockxy-Lab-Run-Id and scenario headers |
| 3 | Custom HTTPS probe | SSL Proxying | Decrypted HTTPS headers and body for an included trusted host |
| 4 | wrong-environment/production-config |
Map Remote | Wrong environment marker rewritten to the intended upstream |
| 5 | auth-recovery/* |
Header inspection, Modify Header, Breakpoints | Expired token, refresh response, successful retry |
| 6 | checkout-contract/checkout-mismatch |
Replay, Edit-and-Repeat, Compose | Edited POST body changes backend result |
| 7 | checkout-contract/shape-mismatch |
Map Local | Fixture response replaces malformed backend payload |
| 8 | network-failure/analytics |
Block List | Optional endpoint can return 403 or drop without breaking the flow |
| 9 | network-failure/slow-checkout |
Network Conditions | Request duration increases by configured latency |
| 10 | network-failure/server-error |
Status filtering and response inspector | 500 payload is visible and attributable |
| 11 | scripted-mock/pricing-experiment |
Scripting | Response body can be mutated for an experiment/mock case |
| 12 | Repeat cases with Dio | Dio proxy debugging | Same scenario IDs appear with X-Rockxy-Client: dio-5 |
If a case fails, keep the failed capture. The case number and correlation headers make it easier to decide whether the next fix belongs in the sample, the Flutter app code, Rockxy's setup UX, a rule behavior, or the backend contract.
The fixtures/rockxy_demo directory contains deterministic JSON responses for
Map Local:
profile.jsonproducts.jsoncart.jsoncheckout.jsonerrors.json
Map /rockxy-demo/schema-mismatch to one of these fixtures to prove whether the
Flutter UI handles the expected response contract.
Keep demo values descriptive and fake. Prefer IDs such as demo-user-001,
demo-cart-2026, and sandbox_card instead of names, email addresses, access
tokens, session cookies, or production identifiers.
final demoUrl = Uri.http(
'127.0.0.1:43210',
'/rockxy-demo/products',
{
'category': 'coffee',
'currency': 'USD',
'page': '1',
'source': 'flutter_debug_sample',
},
);Then paste demoUrl.toString() into the Advanced custom probe field or pass it
directly to the client code in lib/rockxy_debug_proxy.dart.
The reusable code lives in lib/rockxy_debug_proxy.dart. Copy that file into a
debug-only area of your app, choose the runtime, then create the client that your
app already uses.
final settings = RockxyDebugProxySettings(
runtime: RockxyRuntime.localAppleRuntime,
// Replace this with the active proxy port copied from Rockxy.
port: 8888,
physicalDeviceHost: '',
);
final client = settings.createHttpClient();
final request = await client.getUrl(
Uri.parse('http://127.0.0.1:43210/rockxy-demo/bootstrap'),
);
final response = await request.close();
client.close(force: true);final settings = RockxyDebugProxySettings(
runtime: RockxyRuntime.androidEmulator,
// Replace this with the active proxy port copied from Rockxy.
port: 8888,
physicalDeviceHost: '',
);
final client = settings.createPackageHttpClient();
final response = await client.get(
Uri.parse('http://127.0.0.1:43210/rockxy-demo/bootstrap'),
);
client.close();final settings = RockxyDebugProxySettings(
runtime: RockxyRuntime.physicalDevice,
// Replace this with the active proxy port copied from Rockxy.
port: 8888,
physicalDeviceHost: '192.168.1.10',
);
final dio = settings.createDio();
final response = await dio.getUri(
Uri.parse('http://127.0.0.1:43210/rockxy-demo/bootstrap'),
);
dio.close(force: true);The app has a scenario lab where you can choose:
- runtime: local Apple runtime, Android Emulator, or physical device;
- Rockxy port copied from the active Rockxy app;
- Device Proxy LAN host for physical devices;
- Demo API base URL, kept separate from the Rockxy proxy target;
- client type: Dart
HttpClient,package:http, or Dio 5. - scenario group, run selected, run all, or send a custom GET probe.
The reusable implementation lives in:
lib/rockxy_debug_proxy.dartlib/rockxy_lab_contract.dartlib/rockxy_lab_scenarios.dartlib/rockxy_lab_runner.dartlib/rockxy_lab_screen.dart
This sample intentionally uses debug-only certificate bypass code so Rockxy can inspect HTTPS while you are learning the setup path.
Do not ship release builds with:
badCertificateCallback;- Dio
validateCertificatereturningtrue; - Android user-CA trust in release manifests.
For Android, keep user-CA trust under app/src/debug, not app/src/main.
- Start Rockxy and keep capture running.
- Open Developer Setup Hub > Flutter.
- Pick the same runtime host shown in this sample.
- Copy the active Rockxy proxy port into the sample app.
- Run
Known-good app startup. - Confirm Rockxy captures the request.
- Filter by the displayed
X-Rockxy-Lab-Run-Id.
Rockxy validation confirms that the request reached Rockxy through the proxy. It does not prove which device, simulator, emulator, Dart isolate, app, or process emitted the traffic.
If the app shows an error like:
Rockxy proxy is not reachable at 127.0.0.1:<copied Rockxy port>.
use the Rockxy proxy is not reachable at ... line as the attempted proxy
endpoint. Raw Dart SocketException details can include an OS-assigned local
socket port, so do not copy that raw port into the Rockxy port field.
When Proxy through Rockxy is enabled, this usually means the Rockxy proxy is
not listening on the port entered in the sample app.
Check these in order:
- Start capture in Rockxy.
- Copy the active Rockxy port from the Rockxy toolbar.
- Paste that value into the sample app's
Rockxy portfield. - Keep the runtime set to
iOS Simulator / macOS desktopwhen running on macOS. - Keep the local demo API running in a separate terminal:
fvm dart run tool/rockxy_demo_api.dart --port 43210For the default local demo, Rockxy and the sample should use two different ports:
- Rockxy proxy: the active port shown in Rockxy, for example
8888or9090. - Demo API:
43210.
Do not put the demo API port into the Rockxy port field.
If the app shows:
Rockxy proxy is not reachable at 10.0.2.2:<copied Rockxy port>.
Raw socket error: No route to host
the sample is probably running on macOS while Android Emulator is selected.
10.0.2.2 only works from inside an Android emulator.
Fix it one of two ways:
- If you are running the Flutter app on macOS, select
iOS Simulator / macOS desktop. - If you want to test Android Emulator routing, start an Android emulator and
run the app on that emulator with
fvm flutter run.
