InAppWebView Inspector 🔍

Pub Version License: MIT

A powerful WebView inspector and debugging tool for flutter_inappwebview. Provides real-time console monitoring, JavaScript execution, and script history management with a draggable overlay interface.

🤖 Developed with Claude: This Flutter library was developed using Vibe coding methodology in collaboration with Claude AI, showcasing the power of AI-assisted development and human-AI collaborative programming.

🌍 Multi-language Documentation

✨ Features

🚀 Zero Setup Auto UI Injection (New!)

  • No Manual Widget Placement: Inspector UI automatically injects as overlay when show() is called
  • Smart Context Discovery: Automatic BuildContext discovery via WidgetsBinding and NavigatorKey fallback
  • Developer-Controlled: User controls when auto-injection is enabled via debug mode initialization
  • Hot Reload Compatible: Robust overlay system that works seamlessly with Flutter's hot reload
  • Performance Optimized: Optional NavigatorKey integration for instant context access
  • Zero Configuration: Just call toggle() and the UI appears - no Stack widgets or manual placement needed

🖥️ Real-time Console Monitoring

  • Live Console Output: Monitor all JavaScript console messages (log, warn, error, debug) in real-time
  • Color-coded Messages: Different colors for different log levels for easy identification
  • Timestamp Display: Each message includes precise timestamp information
  • Multi-line Support: Full support for long messages and multi-line output
  • Clean Interface: Removed unnecessary labels for streamlined debugging experience

🚀 Enhanced JavaScript Execution

  • Interactive Console: Execute JavaScript code directly in your WebView with intelligent result handling
  • Smart DOM Object Processing:
    • document.querySelector("h1") → Shows element details (tag, id, class, text content)
    • document.querySelectorAll("p") → Lists all matching elements with comprehensive information
    • document.body.classList → Automatically converts to readable array format
    • Functions and complex objects → Displays in developer-friendly format
  • Enhanced Error Handling: Comprehensive error messages with helpful suggestions for common DOM operations
  • Unicode & Base64 Support: Advanced script encoding options for complex scenarios

📚 Intelligent Script History System

  • Pre-loaded Scripts: 15+ commonly used JavaScript snippets ready to use immediately
  • Frequency-based Sorting: Most-used scripts automatically appear first
  • Memory-based Storage: Fast, lightweight history management without file I/O
  • Smart Suggestions: Context-aware script recommendations
  • Usage Tracking: Automatically tracks and prioritizes frequently used scripts

🎯 Multi-WebView Management

  • Multiple WebView Support: Handle unlimited WebViews in a single application
  • Easy Switching: Quick dropdown to switch between registered WebViews
  • Individual Monitoring: Each WebView maintains its own console and execution context
  • Automatic Registration: Simple API to register and manage WebView instances

🌍 Comprehensive Internationalization

  • 8 Languages Supported: English, Korean, Japanese, Spanish, French, German, Chinese (Simplified), Portuguese
  • Auto-detection: Automatic language detection from system locale
  • Easy Localization: Simple API to set preferred language
  • Consistent UI: All interface elements properly localized

🎨 Advanced User Interface

  • Draggable Overlay: Move the inspector anywhere on screen with smooth drag interactions
  • Resizable Interface: Switch between compact and maximized modes for different use cases
  • SafeArea Aware: Automatically adjusts to device screen constraints and notches
  • Stack-based Architecture: Stable popup system without overlay conflicts
  • Clean Design: Minimal, developer-focused interface optimized for productivity

Installation

Add this to your package's pubspec.yaml file:

dependencies:
  inappwebview_inspector: ^0.2.1
  flutter_inappwebview: ^6.1.5

Then run:

$ flutter pub get

🚀 Quick Start

1. Initialize the Inspector

Add this to your main() function:

import 'package:flutter/foundation.dart';
import 'package:inappwebview_inspector/inappwebview_inspector.dart';

void main() {
  // Zero setup initialization - show() will auto-inject UI
  if (kDebugMode) {
    InAppWebViewInspector.initializeDevelopment(
      enableScriptHistory: true,
      maxScriptHistoryCount: 25,
      localizations: InAppWebViewInspectorLocalizations.english, // Change as needed
      onScriptExecuted: (script, webViewId) {
        print('Executed: $script on $webViewId');
      },
      onConsoleLog: (log) {
        print('Console [${log.levelText}]: ${log.message}');
      },
    );
  }
  
  runApp(MyApp());
}
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'WebView Inspector Demo',
      // Add navigatorKey for optimal auto UI injection performance
      navigatorKey: InAppWebViewInspector.navigatorKey,
      home: MyWebViewPage(),
    );
  }
}

3. Simple WebView Setup - Zero Manual UI Placement

✨ New: Zero Setup Auto UI Injection - No need to manually add widgets to your UI!

import 'package:flutter/material.dart';
import 'package:flutter_inappwebview/flutter_inappwebview.dart';
import 'package:inappwebview_inspector/inappwebview_inspector.dart';

class MyWebViewPage extends StatefulWidget {
  @override
  _MyWebViewPageState createState() => _MyWebViewPageState();
}

class _MyWebViewPageState extends State<MyWebViewPage> {
  InAppWebViewController? webViewController;
  final String webViewId = 'main_webview';

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('WebView with Inspector'),
        actions: [
          // Toggle button - UI will auto-inject when pressed!
          IconButton(
            icon: Icon(Icons.bug_report),
            onPressed: InAppWebViewInspector.toggle,
            tooltip: 'Toggle Inspector\n(Zero Setup - UI Auto-Injected!)',
          ),
        ],
      ),
      // ✨ No Stack needed! Inspector UI auto-injects as overlay
      body: Column(
        children: [
          // Your main WebView - Inspector UI auto-injects when show() is called
          Expanded(
            child: InAppWebView(
              initialUrlRequest: URLRequest(
                url: WebUri('https://flutter.dev'),
              ),
              onWebViewCreated: (controller) {
                webViewController = controller;
                
                // Register WebView with inspector
                InAppWebViewInspector.registerWebView(
                  webViewId,
                  controller,
                  'https://flutter.dev',
                );
              },
              onLoadStop: (controller, url) {
                // Update URL in inspector when navigation occurs
                if (url != null) {
                  InAppWebViewInspector.updateWebViewUrl(
                    webViewId,
                    url.toString(),
                  );
                }
              },
              onConsoleMessage: (controller, consoleMessage) {
                // Forward console messages to inspector
                InAppWebViewInspector.addConsoleLog(
                  webViewId,
                  consoleMessage,
                );
              },
              initialSettings: InAppWebViewSettings(
                isInspectable: true, // Enable debugging
                javaScriptEnabled: true,
                domStorageEnabled: true,
              ),
            ),
          ),
        ],
      ),
    );
  }

  @override
  void dispose() {
    // Clean up when page is disposed
    InAppWebViewInspector.unregisterWebView(webViewId);
    super.dispose();
  }
}

4. Control Inspector Visibility

// Show/hide inspector - UI automatically injects as overlay!
InAppWebViewInspector.show();    // ✨ Auto-injects UI overlay
InAppWebViewInspector.hide();    // Removes overlay
InAppWebViewInspector.toggle();  // ✨ Toggle with auto-injection

// Enable/disable inspector
InAppWebViewInspector.enable();
InAppWebViewInspector.disable();

// Check status
bool isVisible = InAppWebViewInspector.isVisible;
bool isEnabled = InAppWebViewInspector.isEnabled;

⚙️ Configuration Options

// Zero setup - show() always auto-injects UI
if (kDebugMode) {
  InAppWebViewInspector.initializeDevelopment(
    enableScriptHistory: true,
    maxScriptHistoryCount: 25,
    maxConsoleLogCount: 500,
    localizations: InAppWebViewInspectorLocalizations.english,
    onScriptExecuted: (script, webViewId) {
      print('Script executed on $webViewId: $script');
    },
    onConsoleLog: (log) {
      print('Console [${log.levelText}]: ${log.message}');
    },
  );
}

Production Mode (Minimal Impact)

// Only initialize in production if needed
if (!kReleaseMode) {
  InAppWebViewInspector.initializeProduction(
    maxConsoleLogCount: 50,
    enableAutoResultLogging: false,
    enableScriptHistory: false,
    localizations: InAppWebViewInspectorLocalizations.english,
  );
}

Advanced Custom Configuration

// Advanced configuration with auto UI injection
if (kDebugMode) {
  InAppWebViewInspector.initializeWithConfig(
    InAppWebViewInspectorConfig(
      debugMode: true,
      maxConsoleLogCount: 1000,
      enableAutoResultLogging: true,
      enableUnicodeQuoteNormalization: true,
      enableBase64ScriptEncoding: true,
      enableScriptHistory: true,
      maxScriptHistoryCount: 30,
      localizations: InAppWebViewInspectorLocalizations.korean, // Multi-language support
      onScriptExecuted: (script, webViewId) {
        // Custom script execution callback
        analytics.logEvent('script_executed', {'webview_id': webViewId});
      },
      onConsoleLog: (log) {
        // Custom console logging
        if (log.level == ConsoleMessageLevel.ERROR) {
          crashlytics.recordError(log.message, null);
        }
      },
      onError: (error, webViewId) {
        // Error handling callback
        print('Inspector error in $webViewId: $error');
      },
    ),
  );
}

Language Configuration

// Available localizations
InAppWebViewInspectorLocalizations.english
InAppWebViewInspectorLocalizations.korean
InAppWebViewInspectorLocalizations.japanese
InAppWebViewInspectorLocalizations.spanish
InAppWebViewInspectorLocalizations.french
InAppWebViewInspectorLocalizations.german
InAppWebViewInspectorLocalizations.chineseSimplified
InAppWebViewInspectorLocalizations.portuguese

// Auto-detect from system locale
final localization = InAppWebViewInspectorLocalizations.getByLanguageCode(
  Localizations.localeOf(context).languageCode
);

🎯 Advanced Usage Examples

Multiple WebViews Management

class MultiWebViewExample extends StatefulWidget {
  @override
  _MultiWebViewExampleState createState() => _MultiWebViewExampleState();
}

class _MultiWebViewExampleState extends State<MultiWebViewExample> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Multiple WebViews'),
        actions: [
          // Single toggle button for all WebViews - UI auto-injects!
          IconButton(
            icon: Icon(Icons.bug_report),
            onPressed: InAppWebViewInspector.toggle,
            tooltip: 'Toggle Inspector\n(Zero Setup Auto UI)',
          ),
        ],
      ),
      // ✨ No Stack needed! Inspector UI auto-injects as overlay
      body: Column(
        children: [
          // First WebView
          Expanded(
            child: InAppWebView(
              onWebViewCreated: (controller) {
                InAppWebViewInspector.registerWebView(
                  'webview_1',
                  controller,
                  'https://flutter.dev',
                );
              },
              onConsoleMessage: (controller, consoleMessage) {
                InAppWebViewInspector.addConsoleLog('webview_1', consoleMessage);
              },
              initialSettings: InAppWebViewSettings(
                isInspectable: true,
                javaScriptEnabled: true,
              ),
            ),
          ),
          // Second WebView  
          Expanded(
            child: InAppWebView(
              onWebViewCreated: (controller) {
                InAppWebViewInspector.registerWebView(
                  'webview_2', 
                  controller,
                  'https://dart.dev',
                );
              },
              onConsoleMessage: (controller, consoleMessage) {
                InAppWebViewInspector.addConsoleLog('webview_2', consoleMessage);
              },
              initialSettings: InAppWebViewSettings(
                isInspectable: true,
                javaScriptEnabled: true,
              ),
            ),
          ),
        ],
      ),
    );
  }
}

Custom Console Messages

// Add custom messages from Flutter
InAppWebViewInspector.instance.addCustomConsoleLog(
  InAppWebViewInspectorConsoleMessage(
    webViewId: 'main',
    level: ConsoleMessageLevel.WARNING,
    message: 'Custom warning from Flutter side',
    source: null, // Clean interface without source labels
    line: null,
    timestamp: DateTime.now(),
  ),
);

// Add development debug messages
InAppWebViewInspector.instance.addCustomConsoleLog(
  InAppWebViewInspectorConsoleMessage(
    webViewId: 'main',
    level: ConsoleMessageLevel.LOG,
    message: 'Flutter lifecycle: App resumed',
    source: null,
    line: null,
    timestamp: DateTime.now(),
  ),
);

Programmatic Script Execution

// Execute custom scripts programmatically
void executeCustomScripts() {
  final inspector = InAppWebViewInspector.instance;
  
  // Simple value retrieval
  inspector.executeScript('document.title');
  
  // Complex DOM operations  
  inspector.executeScript('''
    const links = document.querySelectorAll('a');
    Array.from(links).map(link => ({
      text: link.textContent?.trim(),
      href: link.href,
      className: link.className
    }));
  ''');
  
  // Error handling example
  inspector.executeScript('''
    try {
      const result = performComplexOperation();
      console.log('Operation successful:', result);
      return result;
    } catch (error) {
      console.error('Operation failed:', error.message);
      return { error: error.message, stack: error.stack };
    }
  ''');
}

🛠️ Pre-loaded Utility Scripts

The inspector comes with 15+ ready-to-use JavaScript snippets:

Page Information

  • document.title - Get current page title
  • window.location.href - Get current URL
  • document.readyState - Check page load state
  • document.getElementsByTagName("*").length - Count all elements

DOM Manipulation

  • document.querySelector("selector") - Find single element with details
  • document.querySelectorAll("selector") - Find all matching elements
  • document.body.innerHTML - Get page HTML content
  • document.cookie - View all cookies

Browser & Performance

  • navigator.userAgent - Get browser information
  • window.innerWidth + "x" + window.innerHeight - Get viewport size
  • performance.now() - High-precision timing
  • Object.keys(window) - List global variables

Storage Access

  • localStorage.getItem("key") - Access local storage
  • sessionStorage.getItem("key") - Access session storage

Development Utilities

  • console.log("Hello World"); - Basic console logging

📸 Screenshots

iOS Inspector Interface

iOS WebView Inspector Demo

The inspector running on iOS showing the draggable overlay interface

Android Inspector Interface

Android WebView Inspector Demo

The inspector running on Android with the same powerful debugging features

Key Interface Features Shown:

  • 🖱️ Draggable Overlay: Move the inspector anywhere on screen
  • 📱 Responsive Design: Adapts to different screen sizes and orientations
  • 🎯 WebView Selector: Dropdown to switch between multiple WebViews
  • ⌨️ Interactive Console: JavaScript input field with history dropdown
  • 📋 Real-time Logs: Color-coded console output with timestamps
  • 🔄 Resizable Interface: Toggle between compact and maximized modes

🔄 Migration Guide: v0.1.x → v0.2.0

✨ What's New in v0.2.0

Major Feature: Zero Setup Auto UI Injection

  • No more manual widget placement required
  • Automatic context discovery and overlay injection
  • Simplified integration with just toggle() calls

🚨 Breaking Changes

1. Widget Placement No Longer Required (Simplified - Not Breaking)

Before (v0.1.x): Manual Stack placement required

// ❌ Old way - Still works but not needed
Scaffold(
  body: Stack(
    children: [
      YourContent(),
      const InAppWebViewInspectorWidget(), // Manual placement
    ],
  ),
)

After (v0.2.0): Zero setup auto-injection (Recommended)

// ✅ New way - UI auto-injects as overlay
Scaffold(
  body: YourContent(), // No Stack needed!
)

// Just call toggle - UI appears automatically
InAppWebViewInspector.toggle();

2. NavigatorKey Integration (New Recommendation)

For optimal performance, add NavigatorKey to your MaterialApp:

// ✅ Recommended for v0.2.0
MaterialApp(
  navigatorKey: InAppWebViewInspector.navigatorKey, // New
  home: YourHomePage(),
)

📋 Migration Steps

Step 1: Update Dependencies

dependencies:
  inappwebview_inspector: ^0.2.1  # Updated
  flutter_inappwebview: ^6.1.5
MaterialApp(
  navigatorKey: InAppWebViewInspector.navigatorKey, // Add this line
  home: YourHomePage(),
)

Step 3: Simplify UI (Optional)

You can now remove manual Stack placement:

// Before: Required Stack
Scaffold(
  body: Stack(
    children: [
      YourContent(),
      const InAppWebViewInspectorWidget(),
    ],
  ),
)

// After: Simple layout - Inspector auto-injects
Scaffold(
  body: YourContent(),
)

Step 4: Test Auto-Injection

// Inspector UI will auto-inject when you call:
InAppWebViewInspector.show();
InAppWebViewInspector.toggle();

⚡ Performance Improvements

  • Faster Context Discovery: NavigatorKey provides instant context access
  • Reduced Widget Tree: No manual Stack widgets needed
  • Hot Reload Friendly: Robust overlay system works seamlessly with Flutter's hot reload

🔧 Troubleshooting Migration Issues

  1. Inspector not appearing: Add navigatorKey: InAppWebViewInspector.navigatorKey to MaterialApp
  2. "No Overlay widget found": Ensure you're calling toggle() after initialization
  3. Layout issues: Remove manual Stack placement - auto-injection handles positioning

🆕 New Features in v0.2.0

  • Automatic UI Injection: Zero setup overlay system
  • Smart Context Discovery: Automatic BuildContext discovery
  • NavigatorKey Integration: Optional performance optimization
  • Enhanced Error Recovery: Better fallback mechanisms
  • Hot Reload Compatibility: Improved development experience

⚠️ Important Implementation Notes

✨ Zero Setup Auto UI Injection

New Simplified Approach: No manual widget placement required!

New Zero Setup Method: Auto UI injection (Recommended)

// 1. Add NavigatorKey for optimal performance
MaterialApp(
  navigatorKey: InAppWebViewInspector.navigatorKey, // ✅ Optimal setup
  home: MyWebViewPage(),
)

// 2. Simple UI with no Stack needed
Scaffold(
  body: Column(  // ✅ Simple layout
    children: [
      Expanded(
        child: InAppWebView(
          // Register WebView and inspector auto-injects UI
          onWebViewCreated: (controller) {
            InAppWebViewInspector.registerWebView('main', controller, url);
          },
        ),
      ),
    ],
  ),
)

// 3. Toggle inspector - UI auto-appears as overlay!
InAppWebViewInspector.toggle(); // ✅ Zero manual UI work

Legacy Manual Widget Placement (Still Supported)

For advanced use cases, you can still manually place the widget:

Scaffold(
  body: Stack(
    children: [
      YourMainContent(),
      const InAppWebViewInspectorWidget(), // Manual placement
    ],
  ),
)

Common Issues & Solutions

  1. Inspector not appearing: Ensure NavigatorKey is added to MaterialApp for optimal context discovery
  2. Auto UI injection fails: Check that you're in debug mode and inspector is properly initialized
  3. "No Overlay widget found": Add navigatorKey: InAppWebViewInspector.navigatorKey to your MaterialApp
  4. Dependency conflict with git-sourced flutter_inappwebview: Add dependency override

If your app uses flutter_inappwebview from git source:

dependencies:
  inappwebview_inspector: ^0.2.1
  flutter_inappwebview:
    git:
      url: https://github.com/pichillilorenzo/flutter_inappwebview.git
      ref: master
      path: flutter_inappwebview

dependency_overrides:
  flutter_inappwebview:
    git:
      url: https://github.com/pichillilorenzo/flutter_inappwebview.git
      ref: master
      path: flutter_inappwebview

Development vs Production

Development Build with Auto UI Injection:

if (kDebugMode) {
  InAppWebViewInspector.initializeDevelopment(
    enableScriptHistory: true,
    maxConsoleLogCount: 500,
  );
}

Production Build (Optional):

if (!kReleaseMode) {
  InAppWebViewInspector.initializeProduction(
    maxConsoleLogCount: 50,
    enableScriptHistory: false,
  );
}

📱 Example App

The example app demonstrates:

  • ✅ Complete WebView integration with inspector
  • ✅ Multi-language support demonstration
  • ✅ Pre-loaded script usage
  • ✅ Enhanced DOM object handling
  • ✅ Multiple WebView management
  • ✅ Custom script execution examples

Run the example:

cd example && flutter run

📋 Requirements

  • Flutter: >= 3.24.0
  • Dart: >= 3.5.0
  • flutter_inappwebview: >= 6.1.5

🌐 Platform Support

Platform Status Notes
Android ✅ Full Support All features available
iOS ✅ Full Support All features available

🤝 Contributing

This project demonstrates the power of AI-assisted development using Claude and Vibe coding methodology. Contributions are welcome!

How to Contribute

  1. Fork the repository
  2. Create your feature branch (git checkout -b feature/amazing-feature)
  3. Test your changes thoroughly
  4. Commit your changes (git commit -m 'Add amazing feature')
  5. Push to the branch (git push origin feature/amazing-feature)
  6. Open a Pull Request

Development Setup

# Clone the repository
git clone https://github.com/baccusf/inappwebview_inspector.git
cd inappwebview_inspector

# Install dependencies  
flutter pub get

# Run tests
flutter test

# Run example
cd example && flutter run

📄 License

This project is licensed under the MIT License - see the LICENSE file for details.

🙏 Acknowledgments

  • 🤖 Claude AI: This library was developed through AI-human collaborative programming using Claude
  • ⚡ Vibe Coding: Demonstrated the effectiveness of AI-assisted development methodology
  • 💙 Flutter Community: For providing the amazing Flutter framework
  • 🌐 flutter_inappwebview: For the excellent WebView foundation

📞 Support & Community


Happy debugging with AI-assisted development! 🐛✨🤖