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

retracted

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;
  String loadingState = 'idle';
  int? loadingProgress;
  bool useUrl = false;
  final _formKey = GlobalKey<FormState>();
  final _keyController = TextEditingController();
  final _valueController = TextEditingController();
  final _urlController = TextEditingController(text: 'https://example.com');
  final _scaffoldMessengerKey = GlobalKey<ScaffoldMessengerState>();

  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(
        enableCommunication: true,
        actionHandlers: {
          'updateText': (payload) {
            _scaffoldMessengerKey.currentState?.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']},
            );
          },
        },
        onJavaScriptError: (error) {
          setState(() {
            errorMessage = error;
          });
          _scaffoldMessengerKey.currentState?.showSnackBar(
            SnackBar(content: Text('JavaScript Error: $error')),
          );
        },
      );
    } 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 ScaffoldMessenger(
      key: _scaffoldMessengerKey,
      child: 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,
                  tooltip: 'Load URL',
                ),
              ),
              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: Column(
                      children: [
                        Text(
                            'Loading State: $loadingState${loadingProgress != null ? ' ($loadingProgress%)' : ''}'),
                        const SizedBox(height: 10),
                        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,
                                        );
                                        _scaffoldMessengerKey.currentState
                                            ?.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},
                                        );
                                        _scaffoldMessengerKey.currentState
                                            ?.showSnackBar(
                                          SnackBar(
                                            content: Text(
                                                'Removed: ${_keyController.text}'),
                                          ),
                                        );
                                        _keyController.clear();
                                        _valueController.clear();
                                      } else {
                                        _scaffoldMessengerKey.currentState
                                            ?.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,
                      userAgent: 'WebViewDemo/1.0',
                      csp: useUrl
                          ? null
                          : "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'",
                      onLoadingStateChanged: (state, progress, error) {
                        setState(() {
                          loadingState = state;
                          loadingProgress = progress;
                          if (error != null) {
                            errorMessage = error;
                          }
                        });
                      },
                    ),
                  ),
                  Padding(
                    padding: const EdgeInsets.all(16.0),
                    child: Wrap(
                      spacing: 8.0,
                      runSpacing: 8.0,
                      alignment: WrapAlignment.center,
                      children: [
                        ElevatedButton(
                          onPressed: () {
                            webViewPlugin.sendToWebView(
                              action: 'updateContent',
                              payload: {
                                'text':
                                    'Hello from Flutter at ${DateTime.now()}',
                              },
                            );
                          },
                          child: const Text('Send to WebView'),
                        ),
                        ElevatedButton(
                          onPressed: () async {
                            final storage =
                                await webViewPlugin.getLocalStorage();
                            _scaffoldMessengerKey.currentState?.showSnackBar(
                              SnackBar(
                                content: Text(
                                    'Local Storage: ${storage.toString()}'),
                              ),
                            );
                          },
                          child: const Text('Get Local Storage'),
                        ),
                        ElevatedButton(
                          onPressed: () async {
                            await webViewPlugin.clearWebViewData();
                            _scaffoldMessengerKey.currentState?.showSnackBar(
                              const SnackBar(
                                content: Text('Cleared WebView data'),
                              ),
                            );
                          },
                          child: const Text('Clear WebView Data'),
                        ),
                        ElevatedButton(
                          onPressed: () async {
                            await webViewPlugin.reload();
                            _scaffoldMessengerKey.currentState?.showSnackBar(
                              const SnackBar(
                                content: Text('Reloaded WebView'),
                              ),
                            );
                          },
                          child: const Text('Reload WebView'),
                        ),
                        ElevatedButton(
                          onPressed: () async {
                            final position =
                                await webViewPlugin.getScrollPosition();
                            _scaffoldMessengerKey.currentState?.showSnackBar(
                              SnackBar(
                                content: Text(
                                    'Scroll Position: x=${position['x']}, y=${position['y']}'),
                              ),
                            );
                          },
                          child: const Text('Get Scroll Position'),
                        ),
                      ],
                    ),
                  ),
                ],
              ),
      ),
    );
  }
}
4
likes
0
points
128
downloads

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

unknown (license)

Dependencies

flutter, webview_flutter, webview_flutter_android, webview_flutter_wkwebview

More

Packages that depend on flutter_webview_communication