Load Local Javascript file In Flutter

3,967

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;
}
Share:
3,967
tomerpacific
Author by

tomerpacific

Updated on December 26, 2022

Comments

  • tomerpacific
    tomerpacific over 1 year

    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.

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