Can local image files be used with webview_flutter?

Viewed 1415

Background

Im using webview_flutter 3.0.0 in order to render a complex HTML string that I'm creating in real time. So its not content loaded from the web. I'm doing this as follows:

  final Completer<WebViewController> _controller =
  Completer<WebViewController>();
  late WebViewController _con;

  var finalThreadHTML;

  _loadHTML() async {

   finalThreadHTML = createComplexHTMLStringInRealTime();

    }

    _con.loadUrl(Uri.dataFromString(
        setThreadHTML(
            finalThreadHTML
        ),
        mimeType: 'text/html',
        encoding: Encoding.getByName('utf-8')
    ).toString());
  }

and then in my UI

     WebView(
      initialUrl: '',
      javascriptMode: JavascriptMode.unrestricted,
        javascriptChannels: <JavascriptChannel>[
          JavascriptChannel(
              name: 'MessageInvoker',
              onMessageReceived: (s) {
              }),
        ].toSet(),
      onWebViewCreated: (WebViewController webViewController) {
                      _con = webViewController;
                      _loadHTML();
                      },
      onProgress: (int progress) {
                            print("WebView is loading (progress : $progress%)");
                            },
      navigationDelegate: (NavigationRequest request) {
                            if (request.url.startsWith('https://www.youtube.com/')) {
                            print('blocking navigation to $request}');
                            return NavigationDecision.prevent;
                            }
                            print('allowing navigation to $request');
                            return NavigationDecision.navigate;
                            },
      onPageStarted: (String url) {
                            print('Page started loading: $url');
                            },
      onPageFinished: (String url) {
                            print('Page finished loading: $url');
                            },
      gestureNavigationEnabled: true,
    )

My realtime HTML string (createComplexHTMLStringInRealTime() )looks something like this:

String createComplexHTMLStringInRealTime(){
  return ('''
    <html>
      <head>
    
        <!-- Required meta tags -->
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
      </head>
      
        <body style="height:100vh;">
              Testing some stuff
              <img src="/images/blankAvatar.jpg" />
              Testing more stuff
        </body>
      </html>
      
    ''');
}

My question

In my formed HTML string I want to include some images, which are local asset files as defined in pubspec.yaml

So I tried doing this:

<img src="/images/blankAvatar.jpg" />

but that did not load anything, then I tried

<img src="file:///images/blankAvatar.jpg" />

Still nothing.

Is there anyway to load local files inline with my generated text to load a local file into the webview?

3 Answers

The local image in the img tag can be showed in webview_flutter, you need adjust the controller to load the (HTML) uri in scheme instead of uri in data.

_con.loadUrl(Uri(scheme: 'file', path: file.path).toString());

enter image description here

You can copy paste run full code and index.html below
You can use package https://pub.dev/packages/flutter_inappwebview
In working demo you can see flutter icon <img src="images/flutter-logo.svg" alt="flutter logo"> display correctly

Step 1: add android:usesCleartextTraffic="true" in AndroidManifest.xml
Step 2: pubspec.yaml setting

assets:
    - assets/images/
    - assets/

Step 3: Add files and image to assets folder

enter image description here

working demo

enter image description here

full code

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

InAppLocalhostServer localhostServer = new InAppLocalhostServer();

Future main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await localhostServer.start();
  runApp(new MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: const Text('InAppWebView Example'),
        ),
        body: Container(
            child: Column(children: <Widget>[
          Expanded(
            child: Container(
              child: InAppWebView(
                initialUrl: "http://localhost:8080/assets/index.html",
                initialHeaders: {},
                initialOptions: InAppWebViewGroupOptions(),
                onWebViewCreated: (InAppWebViewController controller) {},
                onLoadStart: (InAppWebViewController controller, String url) {},
                onLoadStop: (InAppWebViewController controller, String url) {},
              ),
            ),
          )
        ])),
      ),
    );
  }
}

index.html

<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Flutter InAppWebView</title>
    <link rel="stylesheet" href="https://getbootstrap.com/docs/4.3/dist/css/bootstrap.min.css">
    <link rel="stylesheet" href="css/style.css">
    <script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
    <link rel="shortcut icon" href="favicon.ico">
</head>
<body class="text-center">
    <div class="cover-container d-flex w-100 h-100 p-3 mx-auto flex-column">
        <header class="masthead mb-auto">
            <div class="inner">
                <h3 class="masthead-brand">Flutter InAppWebView</h3>
                <nav class="nav nav-masthead justify-content-center">
                    <a class="nav-link active" href="index.html">Home</a>
                    <a class="nav-link" href="page-1.html">Page 1</a>
                    <a class="nav-link" href="page-2.html">Page 2</a>
                </nav>
            </div>
        </header>

        <main role="main" class="inner cover">
            <h1 class="cover-heading">Inline WebView</h1>
            <img src="images/flutter-logo.svg" alt="flutter logo">
            <a href="index.html"><img src="images/flutter-logo.svg" alt="flutter logo"></a>
            <p class="lead">Cover is a one-page template for building simple and beautiful home pages. Download, edit the text, and add your own fullscreen background photo to make it your own.</p>
        </main>

        <footer class="mastfoot mt-auto">
            <div class="inner">
                <p>Cover template for <a target="_blank" href="https://getbootstrap.com/">Bootstrap</a>, by <a href="https://twitter.com/mdo">@mdo</a>.</p>
                <p>Phone link example <a href="tel:1-408-555-5555">1-408-555-5555</a></p>
                <p>Email link example <a href="mailto:example@gmail.com">example@gmail.com</a></p>
            </div>
        </footer>
    </div>
    <script src="js/main.js"></script>
</body>
</html>

Got this Solution from a answer hope it will help you

I use package asset_webview for my HTML5 game. It`s very simple code, but it is enough for my project. All images are loading without problems.

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

final URL = 'assets/html/index.html';

main() {
  runApp(MaterialApp(
      home: Padding(
          padding: EdgeInsets.only(top: 48.0),
          child: AssetWebview(
            initialUrl: "asset://local/${URL}",
          )
      )
  ));
}
Related