flutter_blackbox 0.6.2 copy "flutter_blackbox: ^0.6.2" to clipboard
flutter_blackbox: ^0.6.2 copied to clipboard

All-in-one in-app debug overlay for Flutter. Network inspector, API mocking, live logs, FPS monitor, rebuild tracker, storage inspector, crash reports, and QA tools.

example/lib/main.dart

// ╔═══════════════════════════════════════════════════════════════════════════╗
// ║  Flutter BlackBox — Example App                                          ║
// ║                                                                          ║
// ║  This example demonstrates every major feature of flutter_blackbox.      ║
// ║  Run it, tap any button, and open the floating debug button to see       ║
// ║  everything in action.                                                   ║
// ║                                                                          ║
// ║  Adapter file generated by: dart run flutter_blackbox:init --generate    ║
// ╚═══════════════════════════════════════════════════════════════════════════╝

import 'package:flutter_blackbox/flutter_blackbox.dart';
import 'blackbox_adapters.dart'; // generated by CLI
import 'package:dio/dio.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';

// ─────────────────────────────────────────────────────────────────────────────
// Global Dio instance — BlackBox observes it silently via interceptor.
// Your API code stays 100% unchanged.
// ─────────────────────────────────────────────────────────────────────────────
final dio = Dio(BaseOptions(baseUrl: 'https://jsonplaceholder.typicode.com'));

void main() {
  // ─────────────────────────────────────────────────────────────────────────
  // STEP 1: Setup BlackBox
  //
  // This is the only setup code needed. Everything else is automatic.
  // Pass only the adapters you need — unused ones are never installed.
  // ─────────────────────────────────────────────────────────────────────────
  BlackBox.setup(
    // Network — observes all Dio requests/responses without touching your code.
    // Supports multiple adapters: [DioBlackBoxAdapter(dio), HttpBlackBoxAdapter()]
    httpAdapters: [DioBlackBoxAdapter(dio)],

    // Logging — auto-captures debugPrint() and print() output.
    // Shows in the Logs tab with level, tag, and timestamp.
    logAdapter: PrintLogAdapter(),

    // Storage — inspect SharedPreferences in the Storage tab.
    // Add multiple adapters for different stores:
    // storageAdapters: [SharedPrefsStorageAdapter(), GetStorageAdapter(box)]
    storageAdapters: [SharedPrefsStorageAdapter()],

    // Privacy — keys matching "password", "token", "secret", "jwt", etc.
    // are masked as "••••••••" and can't be copied/edited.
    // Set to false only for internal dev builds.
    redactSensitiveData: true,

    // Trigger — how to open the debug overlay.
    // Options: .floatingButton(), .shake(), .hotkey(LogicalKeyboardKey.f12)
    trigger: const BlackBoxTrigger.floatingButton(),

    // Ignore noisy widgets from Rebuild Tracker (e.g., theme wrappers).
    ignoredRebuildWidgets: const ['MyThemeWrapper'],

    // Only active in debug/profile mode — zero cost in release builds.
    enabled: kDebugMode,
  );

  // ─────────────────────────────────────────────────────────────────────────
  // STEP 2: Setup API Mocks (optional)
  //
  // Intercept any API call and return fake data — perfect for offline dev,
  // demos, or testing error states. Mocks are created in the Mocking tab
  // or programmatically here.
  // ─────────────────────────────────────────────────────────────────────────
  BlackBox.mock(
    pattern: '/api/v1/user/profile',
    method: 'GET',
    response: const MockResponse(
      statusCode: 200,
      body: {
        'id': 1,
        'name': 'Alice Johnson',
        'email': 'alice@example.com',
        'role': 'Admin',
      },
    ),
  );

  // Mock a 500 error to test error handling in your app
  BlackBox.mock(
    pattern: '/api/v1/checkout',
    method: 'POST',
    response: const MockResponse(
      statusCode: 500,
      body: {'error': 'Internal Server Error'},
    ),
  );

  // ─────────────────────────────────────────────────────────────────────────
  // STEP 3: Wrap your app with BlackBoxOverlay
  //
  // This adds the debug overlay on top of your app. The overlay renders
  // above your entire widget tree so it never interferes with your layout.
  // ─────────────────────────────────────────────────────────────────────────
  runApp(const BlackBoxOverlay(child: MyApp()));
}

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

  @override
  Widget build(BuildContext context) => MaterialApp(
        title: 'BlackBox Example',
        theme: ThemeData.dark(useMaterial3: true),

        // ── Journey Tracking ──────────────────────────────────────────
        // Add BlackBox.journeyObserver to navigatorObservers to track
        // all route pushes/pops in the Journey tab. This helps reconstruct
        // what the user did before a crash or bug.
        navigatorObservers: [BlackBox.journeyObserver],
        home: const HomeScreen(),
      );
}

// ═════════════════════════════════════════════════════════════════════════════
// HOME SCREEN — Demo buttons for every BlackBox feature
// ═════════════════════════════════════════════════════════════════════════════

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('BlackBox Example')),
      body: ListView(
        padding: const EdgeInsets.all(16),
        children: [
          // ── 1. LOGGING ───────────────────────────────────────────────
          // BlackBox.log() lets you log messages with levels (info, warning,
          // error, debug) and optional tags + data. All logs appear in the
          // Logs tab with color-coded left borders by level.
          //
          // debugPrint() and print() are also auto-captured — no manual
          // logging needed for those.
          const _Section('📋 Logging'),
          _Tile(
            'Log info message',
            Icons.info_outline,
            () => BlackBox.log(
              'User opened home screen',
              level: LogLevel.info,
              tag: 'Navigation',
            ),
          ),
          _Tile(
            'Log warning',
            Icons.warning_amber,
            () => BlackBox.log(
              'Cache miss for key "user_profile"',
              level: LogLevel.warning,
              tag: 'Cache',
            ),
          ),
          _Tile(
            'Log error with data',
            Icons.error_outline,
            () => BlackBox.log(
              'Payment failed',
              level: LogLevel.error,
              tag: 'Payment',
              // Attach any Map data to the log entry — viewable in detail
              data: {
                'orderId': 'ORD-12345',
                'amount': 99.99,
                'currency': 'USD',
                'errorCode': 'CARD_DECLINED',
              },
            ),
          ),
          _Tile(
            'debugPrint (auto-captured)',
            Icons.print,
            () => debugPrint('[Auth] token refreshed at ${DateTime.now()}'),
          ),

          // ── 2. NETWORK ───────────────────────────────────────────────
          // Every Dio request is automatically logged in the Network tab.
          // You can see: method, URL, status code, duration, headers,
          // request/response bodies, timing bars, and copy as cURL.
          //
          // Swipe left-to-right on any entry to dismiss it.
          // Pull down to refresh. Scroll down and tap ↑ to jump to top.
          const SizedBox(height: 16),
          const _Section('🌐 Network'),
          _Tile(
            'GET /posts (real API call)',
            Icons.cloud_download,
            () async {
              try {
                // This hits jsonplaceholder.typicode.com — a real API.
                // Open Network tab to see the request, response, timing,
                // and status code with a color-coded left accent border.
                await dio.get<dynamic>('/posts?_limit=5');
                debugPrint('✅ GET /posts succeeded');
              } catch (e) {
                debugPrint('❌ GET /posts failed: $e');
              }
            },
          ),
          _Tile(
            'GET /users (real API call)',
            Icons.people,
            () async {
              try {
                await dio.get<dynamic>('/users?_limit=3');
                debugPrint('✅ GET /users succeeded');
              } catch (e) {
                debugPrint('❌ GET /users failed: $e');
              }
            },
          ),
          _Tile(
            'POST /posts (create)',
            Icons.cloud_upload,
            () async {
              try {
                // POST requests show the request body in the Network detail.
                await dio.post<dynamic>('/posts', data: {
                  'title': 'BlackBox Test',
                  'body': 'Testing POST request capture',
                  'userId': 1,
                });
                debugPrint('✅ POST /posts succeeded');
              } catch (e) {
                debugPrint('❌ POST failed: $e');
              }
            },
          ),
          _Tile(
            'GET /api/v1/user/profile (mocked)',
            Icons.person_pin,
            () async {
              try {
                // This URL matches the mock we registered in main().
                // The response comes from the MockResponse, not the network.
                // The Network tab shows it as a normal response.
                final res = await dio.get<dynamic>('/api/v1/user/profile');
                debugPrint('🎭 Mocked response: ${res.data}');
              } catch (_) {}
            },
          ),
          _Tile(
            'POST /api/v1/checkout (mocked 500)',
            Icons.error,
            () async {
              try {
                // This mock returns a 500 error — useful for testing
                // your app's error handling without a real server.
                await dio.post<dynamic>('/api/v1/checkout', data: {'items': 3});
              } catch (e) {
                debugPrint('🎭 Mocked 500 error: $e');
              }
            },
          ),

          // ── 3. STORAGE ───────────────────────────────────────────────
          // The Storage tab shows all key-value pairs from your registered
          // adapters. You can search, edit values inline, delete keys,
          // and add new entries. Sensitive keys are auto-redacted.
          const SizedBox(height: 16),
          const _Section('💾 Storage'),
          _Tile(
            'Write sample preferences',
            Icons.save,
            () async {
              final prefs = await SharedPreferences.getInstance();
              // These will appear in the Storage tab immediately
              await prefs.setString('username', 'john_doe');
              await prefs.setBool('dark_mode', true);
              await prefs.setInt('login_count', 42);
              await prefs.setString('app_version', '2.1.0');
              // These sensitive keys will be auto-redacted (shown as ••••••••)
              await prefs.setString(
                  'auth_token', 'eyJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lk...');
              await prefs.setString('user_password_hash', 'bcrypt\$2b\$12...');
              await prefs.setString('api_secret', 'sk-1234567890abcdef');
              debugPrint('✅ Sample preferences written — check Storage tab');
            },
          ),

          // ── 4. REBUILD TRACKING ──────────────────────────────────────
          // The Rebuild tab shows which widgets rebuild the most often.
          // Two modes:
          //
          // Automatic: Toggle "AUTO ON" in the Rebuild tab or call
          //   BlackBox.startRebuildTracking(). Tracks ALL widget rebuilds
          //   using Flutter's debugPrintRebuildDirtyWidgets hook.
          //
          // Manual: Wrap specific widgets with RebuildTracker(label, child).
          //   Zero cost in release builds (uses kDebugMode).
          //
          // Pull down on the Rebuild tab to reset all counts.
          const SizedBox(height: 16),
          const _Section('🔄 Rebuild Tracking'),
          const _Tile(
            'Start auto-tracking',
            Icons.visibility,
            BlackBox.startRebuildTracking,
          ),
          const _Tile(
            'Stop auto-tracking',
            Icons.visibility_off,
            BlackBox.stopRebuildTracking,
          ),
          // ── Manual RebuildTracker wrapper example ──
          // This widget's rebuild count appears in the Rebuild tab
          // under the label "ExampleCard".
          RebuildTracker(
            label: 'ExampleCard',
            child: _Tile(
              'I am tracked (tap to force rebuild)',
              Icons.refresh,
              () => (context as Element).markNeedsBuild(),
            ),
          ),

          // ── 5. CRASH HANDLING ────────────────────────────────────────
          // BlackBox auto-catches:
          //   • Flutter framework errors (e.g., RenderBox overflow)
          //   • Unhandled async exceptions
          //   • Zone errors
          // All appear in the Crashes tab with stack traces.
          // You can also throw manually to test:
          const SizedBox(height: 16),
          const _Section('🐛 Crashes'),
          _Tile(
            'Trigger a test exception',
            Icons.bug_report,
            () {
              // This will be caught by BlackBox and shown in the Crashes tab.
              // Your app won't crash — BlackBox handles it gracefully.
              try {
                throw Exception('Test crash from example app');
              } catch (e, s) {
                FlutterError.reportError(FlutterErrorDetails(
                  exception: e,
                  stack: s,
                  library: 'example app',
                  context: ErrorDescription('testing crash capture'),
                ));
                debugPrint('💥 Exception reported — check Crashes tab');
              }
            },
          ),

          // ── 6. OVERLAY CONTROL ───────────────────────────────────────
          // You can open/close/toggle the overlay programmatically.
          // Useful for: custom trigger buttons, automated testing,
          // or opening after a specific event.
          const SizedBox(height: 16),
          const _Section('🎮 Overlay Control'),
          const _Tile('Open BlackBox overlay', Icons.bug_report, BlackBox.open),
          const _Tile('Close BlackBox overlay', Icons.close, BlackBox.close),

          // ── 7. TIPS ──────────────────────────────────────────────────
          const SizedBox(height: 24),
          Container(
            padding: const EdgeInsets.all(12),
            decoration: BoxDecoration(
              color: Colors.white.withValues(alpha: 0.05),
              borderRadius: BorderRadius.circular(8),
              border: Border.all(color: Colors.white.withValues(alpha: 0.1)),
            ),
            child: const Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                Text('💡 Tips',
                    style:
                        TextStyle(fontWeight: FontWeight.w700, fontSize: 13)),
                SizedBox(height: 8),
                Text(
                  '• Tap the floating 🐞 button to open the overlay\n'
                  '• Drag the button to bottom edge → Mini HUD mode\n'
                  '• Drag the top handle to resize the panel\n'
                  '• Double-tap the handle to snap between 50%/85%\n'
                  '• Swipe left-to-right on logs/network to dismiss\n'
                  '• Long-press any log entry to copy it\n'
                  '• Pull down on any list to refresh\n'
                  '• Use the QA tab to generate bug reports with screenshots',
                  style: TextStyle(
                      fontSize: 12, color: Colors.white54, height: 1.6),
                ),
              ],
            ),
          ),
          const SizedBox(height: 16),
        ],
      ),
    );
  }
}

// ─────────────────────────────────────────────────────────────────────────────
// UI Components (not part of BlackBox — just for this example app)
// ─────────────────────────────────────────────────────────────────────────────

class _Section extends StatelessWidget {
  const _Section(this.title);
  final String title;
  @override
  Widget build(BuildContext context) => Padding(
        padding: const EdgeInsets.only(bottom: 8),
        child: Text(
          title,
          style: TextStyle(
            fontSize: 13,
            fontWeight: FontWeight.w700,
            color: Colors.white.withValues(alpha: 0.4),
            letterSpacing: 1.2,
          ),
        ),
      );
}

class _Tile extends StatelessWidget {
  const _Tile(this.title, this.icon, this.onTap);
  final String title;
  final IconData icon;
  final VoidCallback onTap;
  @override
  Widget build(BuildContext context) => Card(
        margin: const EdgeInsets.only(bottom: 6),
        child: ListTile(
          leading: Icon(icon, size: 20),
          title: Text(title, style: const TextStyle(fontSize: 13)),
          trailing: const Icon(Icons.chevron_right, size: 16),
          onTap: onTap,
          dense: true,
        ),
      );
}
31
likes
160
points
510
downloads

Documentation

API reference

Publisher

unverified uploader

Weekly Downloads

All-in-one in-app debug overlay for Flutter. Network inspector, API mocking, live logs, FPS monitor, rebuild tracker, storage inspector, crash reports, and QA tools.

Repository (GitHub)
View/report issues
Contributing

Topics

#debug #developer-tools #inspector #network #logging

Funding

Consider supporting this project:

github.com

License

MIT (license)

Dependencies

connectivity_plus, device_info_plus, flutter, package_info_plus, yaml

More

Packages that depend on flutter_blackbox