Flutter load local assets for HTML
Asked Answered
B

2

10

I am loading a local HTML file into a Widget using flutter_webview package in the following way:

FutureBuilder<String>(
  future: LocalLoader().loadLocal(),
  builder: (context, snapshot) {
    if (snapshot.hasData) {
//      return Text("${snapshot.data}");
      return WebView(
        initialUrl: new Uri.dataFromString(snapshot.data, mimeType: 'text/html').toString(),
        javascriptMode: JavascriptMode.unrestricted,
      );

    } else if (snapshot.hasError) {
      return Text("${snapshot.error}");
    }
    return CircularProgressIndicator();
  }
)

It loads the HTML just fine but if the tags point to other resources (such as a CSS file at the same location or other local images), they will not be displayed in the webview.

These assets (CSS and the images files) are added to the project at the location specified path from the HTML (relative local path) and also in the pubspec.

For example one of the HTML files contains this element:

<link rel=stylesheet href=styles/main.css>

When the HTML file loads in the webview, the CSS will not reflect its style for that page. If I manually add/write the CSS in the HTML (using the <style> element to define it) it will work just fine.

Any suggestion on how I can make these HTMLs load their local resources? (even it it means changing the package or the way it was implemented)

Also posted here

Bertberta answered 28/1, 2019 at 8:49 Comment(3)
Implement a simple web server in your Flutter app and point the webview to that IP/Port as explained in medium.com/@segaud.kevin/… See also the discussion in github.com/fluttercommunity/flutter_webview_plugin/issues/23Boart
I've checked those links previously but TBH it seems over the top to implement a web server for a simple html ios/android app. will check it out though, thx.Bertberta
It's only a few lines of code. You can upvote and follow github.com/flutter/flutter/issues/27086 for a built-in solution.Boart
C
4

I've tried your code using my local .html, .css and image, this is what I've got:

enter image description here

It seems like there is an issue in the implementation of Flutter WebView, so I've filed this one in Github.

As a workaround, I think one of your options is to use a different plugin which is "flutter_inappwebview".

I've reused your code. The only difference is, I've change this part:

return WebView(
        initialUrl: new Uri.dataFromString(snapshot.data, mimeType: 'text/html').toString(),
        javascriptMode: JavascriptMode.unrestricted,
      );

to this:

return SafeArea(
          child: Container(
            margin: const EdgeInsets.all(10.0),
            decoration:
                BoxDecoration(border: Border.all(color: Colors.blueAccent)),
            child: InAppWebView(
              // initialUrl: "https://youtube.com/",
              initialFile: "assets/sample.html",
              initialHeaders: {},
              initialOptions: InAppWebViewGroupOptions(
                  crossPlatform: InAppWebViewOptions(
                debuggingEnabled: true,
              )),
              onWebViewCreated: (InAppWebViewController controller) {
                _webViewController = controller;
              },
              onLoadStart: (InAppWebViewController controller, String url) {
                setState(() {
                  this.url = url;
                });
              },
              onLoadStop:
                  (InAppWebViewController controller, String url) async {
                setState(() {
                  this.url = url;
                });
              },
              onProgressChanged:
                  (InAppWebViewController controller, int progress) {
                setState(() {
                  this.progress = progress / 100;
                });
              },
            ),
          ),
        );

Which resulted to this:

enter image description here

And here is my local .html and .css, just replace any image to "flutter_logo.png".

body{
    background-color: aliceblue;
}
h1{
    text-align: center;
    font-style: bold;
    color: blue;
}
p{
    text-align: center;
    font-style: italic;
    color: cornflowerblue
}
img{
    display: block;
    margin-left: auto;
    margin-right: auto;
    height: 15%;
    width: 15%;
}
<!DOCTYPE html>
<meta charset="utf-8">
<title>Sample HTML</title>
<html>
    <head>
        <link rel="stylesheet" href="sample.css">
    </head>
    <body>
        <h1>Flutter Webview</h1>
        <p>This paragraph have styles.</p>
    </body>
    <img src="flutter_logo.png" alt="">
</html>
Ced answered 29/9, 2020 at 21:4 Comment(0)
C
0

Use Uri.directory method seems to do the trick for me. It renders all linked css & javascript files, while loading data as string doesn't.

final uri = Uri.directory("$your_local_file_path");
final uriString = uri.toString().substring(0, uri.toString().length - 1); /// Remove final slash symbol
_webViewController.loadUrl(uriString);
Carrara answered 27/9, 2020 at 5:5 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.