building-flutter-network-inspector.md
Markdown PreviewRead-only
ARTICLEMarch 15, 20242 min read315 words
Summary

How we captured all Dart HTTP/Dio traffic in a production-safe, shake-activated Flutter debugging overlay.

Building an In-App Network Inspector SDK for Flutter#

Debugging network payloads in production or staging Flutter apps is often a headache. Teams rely on Charles Proxy or Proxyman, which requires installing custom SSL certificates, configuring device Wi-Fi proxies, and dealing with certificate pinning headaches.

When building Interceptly, my goal was simple: Zero external proxies. Shake the device, and inspect every HTTP request, header, response, and duration directly on the screen.


1. How Dart Handles Global HTTP: HttpOverrides#

In Dart, all standard HTTP requests initiated via dart:io's HttpClient flow through a factory method. Dart exposes a powerful hook:

dart
class InterceptlyHttpOverrides extends HttpOverrides {
  final NetworkCallback onTraffic;
  InterceptlyHttpOverrides({required this.onTraffic});

  @override
  HttpClient createHttpClient(SecurityContext? context) {
    final client = super.createHttpClient(context);
    return InterceptedHttpClient(client, onTraffic);
  }
}

By calling HttpOverrides.global = InterceptlyHttpOverrides(...) during app bootstrapping, every single HTTP call in the app (including libraries like Dio, http, or image loaders) is routed through our custom client!


2. The Non-Destructive Stream Splitting Problem#

When an HTTP response arrives as a Stream<List<int>>, reading the byte stream to log it consumes it. If your logging layer reads the stream, the UI caller will get an empty body or StateError: Stream already listened to.

To solve this, we implemented a custom byte-stream teeing transformer:

dart
Stream<List<int>> splitStream(Stream<List<int>> source, Function(List<int>) onChunk) {
  return source.map((chunk) {
    onChunk(chunk); // Record chunk for Interceptly
    return chunk;   // Pass chunk along untouched to the consumer
  });
}

3. Designing the Shake-to-Open Overlay#

To make it completely zero-configuration for QA and testers:

  • We subscribed to accelerometer events from the device sensors.
  • When an acceleration threshold exceeds \(15 m/s^2\), an overlay entry is inserted into Flutter's Navigator.overlay.
  • The overlay renders a sleek, dark-themed inspector with search, status-code filtering, and one-tap Copy as cURL.

4. Packaging and Publishing on pub.dev#

Publishing an open-source package requires rigorous code quality:

  1. Zero runtime overhead in release mode: Providing an empty no-op stub implementation when kReleaseMode is active.
  2. Exhaustive documentation: 100% pub points on pub.dev with thorough API docs and an example project.
  3. Automated CI: Continuous testing via GitHub Actions across stable and beta Flutter channels.

Check out the package live on pub.dev/packages/interceptly!