flutter_webview_communication 0.1.3 copy "flutter_webview_communication: ^0.1.3" to clipboard
flutter_webview_communication: ^0.1.3 copied to clipboard

A Flutter plugin for bi-directional communication between WebView and Flutter with HTML, CSS, and script support.

example/lib/main.dart

// Copyright (c) 2025 [IGIHOZO Jean Christian]. All rights reserved.
// Licensed under the MIT License. See LICENSE file in the project root.

import 'package:flutter/material.dart';
import 'package:flutter_webview_communication/flutter_webview_communication.dart';

void main() {
  runApp(const MyApp());
}

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

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      home: WebViewDemo(),
    );
  }
}

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

  @override
  _WebViewDemoState createState() => _WebViewDemoState();
}

class _WebViewDemoState extends State<WebViewDemo> {
  late WebViewPlugin webViewPlugin;
  String? errorMessage;
  bool useUrl = false;
  final _formKey = GlobalKey<FormState>();
  final _keyController = TextEditingController();
  final _valueController = TextEditingController();
  final _urlController = TextEditingController(text: 'https://example.com');

  final String sampleHtml = '''
    <div class="container">
      <h1>WebView Demo</h1>
      <p id="message">Waiting for data...</p>
      <button onclick="sendToFlutter('updateText', {text: 'Hello from WebView'})">
        Send to Flutter
      </button>
      <button onclick="sendToFlutter('getStorage', {key: 'userData'})">
        Get Local Storage
      </button>
    </div>
  ''';

  final String sampleCss = '''
    <style>
      .container {
        padding: 20px;
        text-align: center;
        overflow-y: auto;
        scroll-behavior: smooth;
      }
      h1 {
        color: #333;
      }
      button {
        padding: 10px 20px;
        background-color: #007bff;
        color: white;
        border: none;
        border-radius: 5px;
        cursor: pointer;
        margin: 5px;
      }
    </style>
  ''';

  final String sampleScript = '''
    window.addEventListener('flutterData', (event) => {
      const data = event.detail;
      if (data.action === 'updateContent') {
        const p = document.createElement('p');
        p.textContent = data.payload.text || 'No text provided';
        document.body.appendChild(p);
      }
    });
    window.addEventListener('flutterData', (event) => {
      const data = event.detail;
      if (data.action === 'saveResponse') {
        const storedData = localStorage.getItem(data.payload.key) || 'No data';
        const p = document.createElement('p');
        p.textContent = 'Stored: ' + storedData;
        document.body.appendChild(p);
      }
    });
    window.addEventListener('flutterData', (event) => {
      const data = event.detail;
      if (data.action === 'removeResponse') {
        const p = document.createElement('p');
        p.textContent = 'Removed key: ' + data.payload.key;
        document.body.appendChild(p);
      }
    });
  ''';

  String get currentUrl => _urlController.text;

  @override
  void initState() {
    super.initState();
    try {
      webViewPlugin = WebViewPlugin(
        actionHandlers: {
          'updateText': (payload) {
            ScaffoldMessenger.of(context).showSnackBar(
              SnackBar(content: Text('Received: ${payload['text']}')),
            );
            webViewPlugin.sendToWebView(
              action: 'updateContent',
              payload: {'text': 'Updated from Flutter: ${payload['text']}'},
            );
          },
          'getStorage': (payload) async {
            await webViewPlugin.saveToLocalStorage(
              key: payload['key'],
              value: 'Sample Data at ${DateTime.now()}',
            );
            webViewPlugin.sendToWebView(
              action: 'saveResponse',
              payload: {'key': payload['key']},
            );
          },
        },
      );
    } catch (e) {
      setState(() {
        errorMessage = e.toString();
      });
    }
  }

  @override
  void dispose() {
    _keyController.dispose();
    _valueController.dispose();
    _urlController.dispose();
    super.dispose();
  }

  void _loadUrl() {
    setState(() {
      useUrl = true;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: SizedBox(
          height: 40,
          child: TextField(
            controller: _urlController,
            decoration: InputDecoration(
              hintText: 'Enter URL',
              border: OutlineInputBorder(
                borderRadius: BorderRadius.circular(8.0),
              ),
              contentPadding: const EdgeInsets.symmetric(horizontal: 10),
              suffixIcon: IconButton(
                icon: const Icon(Icons.send),
                onPressed: _loadUrl,
              ),
            ),
            onSubmitted: (value) => _loadUrl(),
            enabled: errorMessage == null,
          ),
        ),
        actions: [
          IconButton(
            icon: Icon(useUrl ? Icons.code : Icons.web),
            onPressed: () {
              setState(() {
                useUrl = !useUrl;
              });
            },
            tooltip: 'Toggle URL/HTML',
          ),
        ],
      ),
      body: errorMessage != null
          ? Center(child: Text(errorMessage!))
          : Column(
              children: [
                Padding(
                  padding: const EdgeInsets.all(16.0),
                  child: Form(
                    key: _formKey,
                    child: Column(
                      children: [
                        TextFormField(
                          controller: _keyController,
                          decoration: const InputDecoration(
                            labelText: 'Key',
                            border: OutlineInputBorder(),
                          ),
                          validator: (value) {
                            if (value == null || value.isEmpty) {
                              return 'Please enter a key';
                            }
                            return null;
                          },
                        ),
                        const SizedBox(height: 10),
                        TextFormField(
                          controller: _valueController,
                          decoration: const InputDecoration(
                            labelText: 'Value',
                            border: OutlineInputBorder(),
                          ),
                          validator: (value) {
                            if (value == null || value.isEmpty) {
                              return 'Please enter a value';
                            }
                            return null;
                          },
                        ),
                        const SizedBox(height: 10),
                        Row(
                          mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                          children: [
                            ElevatedButton(
                              onPressed: () async {
                                if (_formKey.currentState!.validate()) {
                                  await webViewPlugin.saveToLocalStorage(
                                    key: _keyController.text,
                                    value: _valueController.text,
                                  );
                                  ScaffoldMessenger.of(context).showSnackBar(
                                    SnackBar(
                                      content: Text(
                                          'Saved: ${_keyController.text} = ${_valueController.text}'),
                                    ),
                                  );
                                  _keyController.clear();
                                  _valueController.clear();
                                }
                              },
                              child: const Text('Save to Local Storage'),
                            ),
                            ElevatedButton(
                              onPressed: () async {
                                if (_keyController.text.isNotEmpty) {
                                  await webViewPlugin.removeFromLocalStorage(
                                    key: _keyController.text,
                                  );
                                  webViewPlugin.sendToWebView(
                                    action: 'removeResponse',
                                    payload: {'key': _keyController.text},
                                  );
                                  ScaffoldMessenger.of(context).showSnackBar(
                                    SnackBar(
                                      content: Text(
                                          'Removed: ${_keyController.text}'),
                                    ),
                                  );
                                  _keyController.clear();
                                  _valueController.clear();
                                } else {
                                  ScaffoldMessenger.of(context).showSnackBar(
                                    const SnackBar(
                                      content:
                                          Text('Please enter a key to remove'),
                                    ),
                                  );
                                }
                              },
                              child: const Text('Remove from Local Storage'),
                            ),
                          ],
                        ),
                      ],
                    ),
                  ),
                ),
                Expanded(
                  child: webViewPlugin.buildWebView(
                    content: useUrl ? currentUrl : sampleHtml,
                    isUrl: useUrl,
                    cssContent: useUrl ? null : sampleCss,
                    scriptContent: sampleScript,
                  ),
                ),
                Padding(
                  padding: const EdgeInsets.all(16.0),
                  child: ElevatedButton(
                    onPressed: () {
                      webViewPlugin.sendToWebView(
                        action: 'updateContent',
                        payload: {
                          'text': 'Hello from Flutter at ${DateTime.now()}',
                        },
                      );
                    },
                    child: const Text('Send to WebView'),
                  ),
                ),
              ],
            ),
    );
  }
}
4
likes
120
points
128
downloads

Documentation

API reference

Publisher

unverified uploader

Weekly Downloads

A Flutter plugin for bi-directional communication between WebView and Flutter with HTML, CSS, and script support.

Repository (GitHub)
View/report issues

License

MIT (license)

Dependencies

flutter, webview_flutter, webview_flutter_android, webview_flutter_wkwebview

More

Packages that depend on flutter_webview_communication