dio_capture_viewer 0.1.1 copy "dio_capture_viewer: ^0.1.1" to clipboard
dio_capture_viewer: ^0.1.1 copied to clipboard

A lightweight in-app Dio request capture viewer with a floating Flutter UI for debug and QA builds.

dio_capture_viewer #

pub package

中文文档

A lightweight in-app network capture viewer for Flutter apps that use Dio.

It adds one Dio interceptor and a floating Material UI panel where you can inspect request headers, query parameters, request bodies, response payloads, errors, status codes, request durations, SSE events, and WebSocket messages.

Features #

  • Floating draggable viewer with compact, docked, and full-screen modes.
  • Dio interceptor for request, response, error, duration, and payload capture.
  • Protocol support for HTTP/Dio, manually reported SSE, and manually reported WebSocket sessions.
  • Header redaction for authorization, cookies, and token-like fields.
  • Filterable request list, payload copy actions, and protocol-aware Copy To Curl command generation.
  • Optional toast callback for viewer actions such as copy, clear, and hide.
  • File-like payloads such as images, videos, audio, PDFs, archives, and binary attachments are summarized as placeholders with format and size instead of rendering raw content.
  • Settings entry callback and optional persistence bridge.

Preview #

[Capture viewer preview 1] [Capture viewer preview 2] [Capture viewer preview 3] [Capture viewer preview 4] [Capture viewer preview animation]

Usage #

Create one DioCaptureViewerController, attach its interceptor to Dio, then place the overlay above your app content.

import 'package:dio/dio.dart';
import 'package:dio_capture_viewer/dio_capture_viewer.dart';
import 'package:flutter/material.dart';

const apiHost = 'https://api.example.com';

final navigatorKey = GlobalKey<NavigatorState>();

final captureController = DioCaptureViewerController.init(
  enabled: true,
  showPanel: true,
  navigatorKey: navigatorKey,
  host: apiHost,
  onSettingsTap: (context, store) {
    Navigator.of(context).push(
      MaterialPageRoute<void>(
        builder: (_) => YourCaptureSettingsPage(store: store),
      ),
    );
  },
  onCloseTap: (context, store) async {
    return await confirmHideCaptureViewer(context);
  },
  // Optional. Leave this unset if you do not want action toasts.
  toast: (context, message) {
    showYourToast(message);
  },
);

final dio = Dio(BaseOptions(baseUrl: apiHost))
  ..interceptors.add(captureController.createInterceptor());

class App extends StatelessWidget {
  const App({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      // Use the same key passed to DioCaptureViewerController.
      navigatorKey: navigatorKey,
      builder: (context, child) {
        return DioCaptureViewerOverlay(
          controller: captureController,
          child: child ?? const SizedBox.shrink(),
        );
      },
      home: const HomePage(),
    );
  }
}

The navigatorKey is optional if you do not open routes from viewer buttons. When you use onSettingsTap or show dialogs from onCloseTap, pass the same key to both DioCaptureViewerController and MaterialApp.

toast is optional. When it is not provided, the viewer does not show any built-in toast or snackbar. When provided, copy, curl copy, clear, search-clear, and hide actions call it with a short message.

CaptureStore exposes the settings you can place in your own capture settings page:

captureController.store.setEnabled(true);
captureController.store.setMaxCacheSize(200);

final enabled = captureController.store.isEnabled;
final maxCacheSize = captureController.store.maxCacheSize;

If your app has its own persistence layer, implement CapturePreferences and pass it into CaptureStore(preferences: yourPreferences), then call captureStore.restore() during startup.

The package does not export a settings page. It only provides the setting entry callback, the floating viewer modes, the capture store, and the Dio interceptor.

Advanced Configuration #

SSE and WebSocket capture #

SSE and WebSocket capture is manual and dependency-free. Create a stream session, then report inbound, outbound, close, and error events from whichever client your app already uses.

Stream message UI refreshes are throttled to 2 seconds by default. Pass streamNotifyInterval: Duration.zero to DioCaptureViewerController.init or CaptureStore to refresh immediately on every message.

final socketCapture = captureController.store.startStreamCapture(
  protocol: CaptureProtocol.webSocket,
  url: 'wss://example.com/socket',
);

// Example shape for a WebSocketChannel-like client.
channel.stream.listen(
  socketCapture.addInbound,
  onError: socketCapture.fail,
  onDone: socketCapture.close,
);

void sendSocketMessage(Object message) {
  socketCapture.addOutbound(message);
  channel.sink.add(message);
}
final sseCapture = captureController.store.startStreamCapture(
  protocol: CaptureProtocol.sse,
  url: 'https://example.com/events',
);

// Example shape for an EventSource/SSE stream.
eventStream.listen(
  (event) => sseCapture.addEvent(
    {'event': event.event, 'data': event.data},
    label: event.event,
  ),
  onError: sseCapture.fail,
  onDone: sseCapture.close,
);

If a captured stream entry is manually deleted or all entries are cleared, updates from the old session are ignored. Open SSE/WebSocket entries are also protected from automatic cache cleanup; ordinary HTTP entries and closed streams are removed first when the cache exceeds maxCacheSize.

Copy as curl #

The Overview tab includes Copy All and Copy To Curl actions. Copy To Curl uses the captured method, URL, headers, query parameters, and request body to build a shell-ready curl command.

HTTP requests include request bodies with --data-raw; JSON-like payloads add Content-Type: application/json when the captured request does not already have one. Captured FormData fields are emitted with --form-string, while file fields are emitted as placeholders such as field=@avatar.png.

SSE entries generate a streaming HTTP command with -N and Accept: text/event-stream. WebSocket entries generate a ws:// or wss:// curl command with -N and the captured application headers. Hop-by-hop WebSocket handshake headers generated by the client are skipped.

File payload display #

Images, videos, audio files, PDFs, archives, application/octet-stream responses, and uploaded files are not displayed as raw content in the viewer. They are shown as placeholders such as [avatar.png, image/png, 24.0KB] or [video/mp4, 2.4MB].

Future #

The next version plans to add attachment export so captured file-like payloads can be saved outside the viewer when needed.

Notes #

This package is meant for development, QA, and internal debug builds. Avoid showing captured production traffic to end users.

2
likes
0
points
44
downloads

Publisher

unverified uploader

Weekly Downloads

A lightweight in-app Dio request capture viewer with a floating Flutter UI for debug and QA builds.

Repository (GitHub)
View/report issues

Topics

#dio #network #debugging #inspector #flutter

License

unknown (license)

Dependencies

dio, flutter

More

Packages that depend on dio_capture_viewer