8

I have a Flutter project and I am using the webview_flutter package to create a Webview widget.

This is my main.dart file:

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:webview_flutter/webview_flutter.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Communication Bridge',
      theme: ThemeData(
        primarySwatch: Colors.blue,
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      home: MyHomePage(title: 'Native - JS Communication Bridge'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);

  final String title;

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

class _MyHomePageState extends State<MyHomePage> {

  WebViewController _controller;
  final GlobalKey<ScaffoldState> _scaffoldKey = new GlobalKey<ScaffoldState>();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      key: _scaffoldKey,
      appBar: AppBar(title: Text('Webview')),
      body: WebView(
        initialUrl: 'about:blank',
        javascriptMode: JavascriptMode.unrestricted,
        javascriptChannels: Set.from([
          JavascriptChannel(
              name: 'messageHandler',
              onMessageReceived: (JavascriptMessage message) {
                _scaffoldKey.currentState.showSnackBar(
                    SnackBar(
                        content: Text(
                            message.message)
                    )
                );
              })
        ]),
        onWebViewCreated: (WebViewController webviewController) {
          _controller = webviewController;
          _loadHtmlFromAssets();
        },
      ),
      floatingActionButton: FloatingActionButton(
        child: const Icon(Icons.arrow_upward),
        onPressed: () {
          _controller.evaluateJavascript('foo("message")');
        },
      ),
    );

  }

  _loadHtmlFromAssets() async {
    String file = await rootBundle.loadString('assets/index.html');
    _controller.loadUrl(Uri.dataFromString(
        file,
        mimeType: 'text/html',
        encoding: Encoding.getByName('utf-8')).toString());
  }

}

As you can see, I am loading a local html file into the webview (_loadHtmlFromAssets).

The html file has the following markup:

   <html>

    <head>
        <title>My Local HTML File</title>
    </head>

    <body>
        <script type="text/javascript">
            function foo(msg) {
               //Code
            }
        </script>
    </body>
</html>

When the html contains the javascript like the code above, I have no problems and am able to communicate from the application to the webview.

I want to have the javascript code in a separate file, and not inside the html file.

 <html>
    
        <head>
            <title>My Local HTML File</title>
        </head>
    
        <body>
            <script src="script.js"></script> // <-------
        </body>
    </html>

When I tried doing this, I get the following error (where it's trying to reference methods defined in the javascript file):

I/chromium(15188): [INFO:CONSOLE(1)] "Uncaught ReferenceError: foo is not defined

I have added the file in my pubspec.yaml under assets, so that is not the issue.

I have seen this question on SO, but the solution there does not help.

1 Answer 1

4

You can copy paste run 4 full code main.dart, index.html, script.js, style.css below
And add android:usesCleartextTraffic="true" in AndroidManifest.xml
You can use package https://pub.dev/packages/webview_flutter_plus
webview_flutter_plus is a powerful extension of webview_flutter. This package helps to load Local HTML, CSS and Javascript content from Assets or Strings. This inherits all features of webview_flutter with minor API changes.

You can directly download full example code from https://github.com/shah-xad/webview_flutter_plus and test it

code snippet

WebViewPlus(
      initialUrl: 'assets/index.html',
      onWebViewCreated: (controller) {
        this._controller = controller;
      },
      onPageFinished: (url) {
        _controller.getHeight().then((double height) {
          print("Height: " + height.toString());
          setState(() {
            _height = height;
          });
        });
      },
      javascriptMode: JavascriptMode.unrestricted,
    ),

setting of assets

enter image description here

working demo of example code

enter image description here

full code of main.dart

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

void main() {
  runApp(WebViewPlusExample());
}

class WebViewPlusExample extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: WebViewPlusExampleMainPage(),
    );
  }
}

class WebViewPlusExampleMainPage extends StatefulWidget {
  @override
  _WebViewPlusExampleMainPageState createState() =>
      _WebViewPlusExampleMainPageState();
}

class _WebViewPlusExampleMainPageState
    extends State<WebViewPlusExampleMainPage> {
  WebViewPlusController _controller;
  double _height = 1000;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('webview_flutter_plus Example'),
      ),
      body: ListView(
        children: [
          SizedBox(
            height: 500,
            child: WebViewPlus(
              initialUrl: 'assets/index.html',
              onWebViewCreated: (controller) {
                this._controller = controller;
              },
              onPageFinished: (url) {
                _controller.getHeight().then((double height) {
                  print("Height: " + height.toString());
                  setState(() {
                    _height = height;
                  });
                });
              },
              javascriptMode: JavascriptMode.unrestricted,
            ),
          )
        ],
      ),
    );
  }
}

full code of index.html

<!DOCTYPE HTML>
<html>
<head>
    <title>webview_flutter_plus</title>
    <link crossorigin="anonymous" href="style.css" rel="stylesheet">
</head>
<body>
<div id="testDiv">
    webview_flutter_plus is an extension of webview_flutter to load HTML, CSS and Javascript even from Assets or String.
    <br>
    <br>
    <br>
    Please tap the text to see Javascript execution.
</div>
<script src="script.js"></script>
</body>

full code of script.js

var testDiv = document.getElementById("testDiv");
testDiv.addEventListener('click', function f(e) {
    testDiv.setAttribute('style', 'background:red;')
    console.log("style changed");
})

full code of style.css

#testDiv {
    background: green;
    color: white;
}
Sign up to request clarification or add additional context in comments.

3 Comments

Thanks for the answer. Are you saying the scenario I asked s not possible using the webview_flutter package?
There is actually a pull request github.com/flutter/plugins/pull/1247 , long time ago, still not merged.
I suggest you can use this extension if you have deadline. because it's inherits all features of webview_flutter with minor API changes

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.