Dartmole

Getting started

Dartmole has two parts: the Dartmole app on your Mac, which shows the traffic, and dartmole_plugin in your Flutter app, which sends the traffic there. This page sets up both and gets the first call on screen.

You need:

1. Install Dartmole

Download Dartmole, open the DMG, and drag Dartmole to Applications. When you open it, it starts its proxy on port 8080. If something else has that port, Settings → Proxy says what, and lets you pick another.

Dartmole updates itself: it checks for a new version once a day, and Dartmole → Check for Updates… checks right away.

2. Add the plugin

In your app's pubspec.yaml:

YAML
dependencies:
  dartmole_plugin: ^0.1.0

Or run flutter pub add dartmole_plugin.

iOS

Pairing scans a QR code, so the app needs the camera, and it reaches your Mac over the local network. Add both keys to ios/Runner/Info.plist:

XML
<key>NSCameraUsageDescription</key>
<string>Scans the QR code in Dartmole to pair with it.</string>
<key>NSLocalNetworkUsageDescription</key>
<string>Connects to Dartmole on this network to inspect the app's traffic.</string>

Without the camera key, iOS closes the app as soon as the scanner opens.

Android

Debug builds can already reach the network. For a release build that should pair too, such as an internal build for testers, add this to android/app/src/main/AndroidManifest.xml:

XML
<uses-permission android:name="android.permission.INTERNET"/>

3. Send your HTTP through it

Dartmole().createHttpClient() returns a dart:io HttpClient. Until the app is paired and interception is on, it is an ordinary client, so it is safe to use everywhere.

HTTP libraries create their client once and keep it, so swap it when the pairing changes: Dartmole() is a ChangeNotifier.

With Dio:

Dart
import 'package:dartmole_plugin/dartmole_plugin.dart';
import 'package:dio/dio.dart';
import 'package:dio/io.dart';
import 'package:flutter/widgets.dart';

final dio = Dio();

void main() {
  WidgetsFlutterBinding.ensureInitialized();
  _useDartmole();
  Dartmole().addListener(_useDartmole);
  runApp(const MyApp());
}

void _useDartmole() {
  dio.httpClientAdapter = IOHttpClientAdapter(
    createHttpClient: Dartmole().createHttpClient,
  );
}

With package:http:

Dart
import 'package:dartmole_plugin/dartmole_plugin.dart';
import 'package:flutter/widgets.dart';
import 'package:http/http.dart' as http;
import 'package:http/io_client.dart';

http.Client client = IOClient(Dartmole().createHttpClient());

void main() {
  WidgetsFlutterBinding.ensureInitialized();
  Dartmole().addListener(() {
    client.close();
    client = IOClient(Dartmole().createHttpClient());
  });
  runApp(const MyApp());
}

Read client at the moment of each call rather than keeping a copy, so calls pick up the new one. With a plain HttpClient, create one with Dartmole().createHttpClient() wherever you would write HttpClient().

4. Add the pairing panel

DartmoleSettings pairs the device, shows which Mac it is paired with, and switches interception on and off. Put it where testers can reach it and store users cannot, such as a debug menu:

Dart
Scaffold(
  appBar: AppBar(title: const Text('Dartmole')),
  body: const SingleChildScrollView(
    padding: EdgeInsets.all(24),
    child: DartmoleSettings(),
  ),
);

5. Pair and watch

  1. In Dartmole, open the Devices tab. It shows a QR code.
  2. In your app, open the pairing panel and tap Scan QR code. On a simulator, or a device without a camera, type the host and port Dartmole shows instead.
  3. Use your app. Every call it makes appears on Dartmole's Proxy tab, with its headers and body.

TLS stays on throughout: the plugin trusts Dartmole's certificate authority for its own client only, and never switches certificate checks off.

Next: mock a call

Mocks are files in the repository of the app you are debugging, in .dartmole/mocks/, so they are reviewed and shared like the rest of your code.

  1. On the Mocks tab, choose Import project and pick your app's folder.
  2. On the Proxy tab, select a call and choose Save as mock. Change the response, the status or a delay, and save.
  3. Switch the mock on. The next matching call gets the mock's response, and the backend never sees it.

Mocks arrive switched off. Whether one is on is remembered on your Mac and never changes the files, so pulling someone's mocks cannot change your traffic by surprise.

When nothing shows up

The dartmole_plugin page on pub.dev has the full reference: remembering a pairing across launches, native traffic, and checking that interception works.