flutter_dev_monitor

An in-app developer monitor for Flutter. Tracks API calls, FPS, RAM, and disk usage with a floating overlay and a full dashboard — framework-agnostic, works with GetX, Provider, Riverpod, or plain Flutter.

Features

  • Floating HUD — draggable overlay showing live FPS, GPU ms, build ms, RAM
  • API log — captures every Dio request: URL, method, status code, duration, caller function, and screen
  • FPS chart — per-screen frame-time history
  • Hardware grid — RAM / disk usage updated every 3 seconds
  • Phase detection — automatically separates init calls (first load) from refresh calls (pull-to-refresh, periodic polling)
  • Screen-aware — data is scoped per route; cleared when the screen is popped

Getting started

Add the package to your pubspec.yaml:

dependencies:
  flutter_dev_monitor: ^1.0.0
  dio: ^5.9.0        # required for MonitorInterceptor

Setup

1. Add the Dio interceptor

final dio = Dio()..interceptors.add(DevMonitor.interceptor);

All requests made through this Dio instance are automatically captured.

2. Configure MaterialApp

MaterialApp(
  navigatorObservers: [DevMonitor.observer],
  builder: DevMonitor.appBuilder,
  home: const HomeScreen(),
)
  • DevMonitor.observer tracks the active route so API logs are grouped by screen.
  • DevMonitor.appBuilder injects the draggable FPS/RAM overlay automatically — no need to wrap home with FpsOverlay.

3. Open the dashboard

Navigate to MonitorDashboardPage from anywhere — a button in your AppBar works well:

IconButton(
  icon: const Icon(Icons.bar_chart),
  onPressed: () => Navigator.push(
    context,
    MaterialPageRoute(
      settings: const RouteSettings(name: '/MonitorDashboardPage'),
      builder: (_) => const MonitorDashboardPage(
        initialScreen: '/HomeScreen',
      ),
    ),
  ),
)

Full example

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

final dio = Dio(BaseOptions(baseUrl: 'https://jsonplaceholder.typicode.com'))
  ..interceptors.add(DevMonitor.interceptor);

void main() => runApp(const MyApp());

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      navigatorObservers: [DevMonitor.observer],
      builder: DevMonitor.appBuilder,
      home: const HomeScreen(),
    );
  }
}

class HomeScreen extends StatefulWidget {
  const HomeScreen({super.key});

  @override
  State<HomeScreen> createState() => _HomeScreenState();
}

class _HomeScreenState extends State<HomeScreen> {
  @override
  void initState() {
    super.initState();
    dio.get('/posts');       // captured automatically
    dio.get('/users');       // captured automatically
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Home'),
        actions: [
          IconButton(
            icon: const Icon(Icons.bar_chart),
            onPressed: () => Navigator.push(
              context,
              MaterialPageRoute(
                settings: const RouteSettings(name: '/MonitorDashboardPage'),
                builder: (_) => const MonitorDashboardPage(
                  initialScreen: '/HomeScreen',
                ),
              ),
            ),
          ),
        ],
      ),
      body: const Center(child: Text('Your app content')),
    );
  }
}

A runnable example with multiple screens and refresh simulation is in the example/ directory.

Usage with state management

Provider / plain Flutter

// MonitorController.instance is a singleton ChangeNotifier.
final fps = MonitorController.instance.currentFps;

GetX

Get.put(MonitorController.instance);

Riverpod

final monitorProvider = ChangeNotifierProvider((_) => MonitorController.instance);

API reference

Class / Member Description
DevMonitor.interceptor Singleton MonitorInterceptor — add to your Dio instance
DevMonitor.observer Singleton MonitorNavigatorObserver — pass to navigatorObservers
DevMonitor.appBuilder TransitionBuilder — pass to MaterialApp.builder to inject the overlay
MonitorDashboardPage Full dashboard — push as a named route
MonitorController Singleton ChangeNotifier with all observable state
FpsOverlay Low-level overlay widget — use DevMonitor.appBuilder instead

FpsOverlay parameters

Parameter Type Default Description
child Widget required The widget tree to wrap
isShowing bool true Show or hide the overlay at runtime

MonitorDashboardPage parameters

Parameter Type Default Description
initialScreen String required Route name of the screen to show on open (e.g. '/HomeScreen')

Notes

  • Debug / profile only — wrap usage in kDebugMode or kProfileMode checks before releasing to production.
  • The package uses a MethodChannel for native RAM and disk data. Native implementations are included for Android (Kotlin) and iOS (Swift).
  • Supports Android and iOS only (not web or desktop).