1

I have a Flutter project in which I am:

  • Downloading the zip file (full of html files)
  • Extracting the html files to a new directory (ebooks/02)
  • Saving the local file urls in a List
  • Displaying the urls in Webview & iterate through List for back & forth.

However, in the web view all I get is "Unable to load asset..."

enter image description here

Though any standard http url works fine in webview.

I tried from these two answers but no result: Answer1 & Answer2

The exception I get is :

E/flutter (10963): [ERROR:flutter/lib/ui/ui_dart_state.cc(186)] Unhandled Exception: Unable to load asset: /data/user/0/com.pts.school_ebook_reader_app_prag/app_flutter/ebooks/04/00.html

I need to understand how to make the local html at the given path display in webview.

Any help would be appreciated.

Edit:

The webview code (currently trying to display only 1st url in list):

 class _BookReaderState extends State<BookReader> {
  List<String> urls = UserData.ebook;

  WebViewController web;
  final _key = UniqueKey();
  String _url;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          automaticallyImplyLeading: false,
          title: Text(
            "Book Title Here",
            style: GoogleFonts.roboto(
                fontWeight: FontWeight.w900,
                fontSize: 25.0,
                color: Colors.white),
            textAlign: TextAlign.center,
          ),
          actions: [
            Padding(
              padding: EdgeInsets.only(right: 50),
              child: IconButton(
                  icon: Image.asset('images/04_mobile-menu.png'),
                  color: Colors.red,
                  alignment: Alignment.centerLeft,
                  onPressed: () {
                    Navigator.push(
                        context,
                        MaterialPageRoute(
                            builder: (context) => MyLibrary_Screen()));
                  }),
            ),
            Padding(
              padding: const EdgeInsets.only(left: 1.0),
              child: IconButton(
                  icon: Image.asset('images/05_mobile-close.png'),
                  color: Colors.red,
                  alignment: Alignment.centerRight,
                  onPressed: () {
                    Navigator.push(
                        context,
                        MaterialPageRoute(
                            builder: (context) => MyLibrary_Screen()));
                  }),
            ),
          ],
        ),
        body: Column(
          children: [
            Padding(
              padding: EdgeInsets.symmetric(horizontal: 10, vertical: 10),
              child: Container(
                  width: 700,
                  height: 490,
                  child: FutureBuilder<String>(
                      future: _loadHtmlFromAssets(0),
                      builder: (context, snapshot) {
                        if (snapshot.hasData) {
                          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();
                      })),
            ),
            Padding(
              padding: EdgeInsets.only(top: 85),
              child: Container(
                height: 70,
                color: Colors.blue,
                child: RowSuper(
                  innerDistance: 50,
                  children: [
                    InkWell(
                      child: Image.asset(
                        "images/05_mobile-arrow-left.png",
                        alignment: Alignment.bottomLeft,
                        height: 170,
                        width: 90,
                      ),
                      onTap: () => pageIncDec(1),
                    ),
                    Text('Page ${urls.indexOf(_url) + 1} of ${urls.length}',
                        style: GoogleFonts.roboto(
                            fontWeight: FontWeight.w900,
                            fontSize: 33.0,
                            color: Colors.white)),
                    InkWell(
                      child: Image.asset(
                        "images/05_mobile-arrow-right.png",
                        alignment: Alignment.bottomRight,
                        height: 270,
                        width: 90,
                      ),
                      onTap: () => pageIncDec(2),
                    ),
                  ],
                ),
              ),
            ),
          ],
        ));
  }

  pageIncDec(int i) async {
    int n;
    if (i == 1) {
      setState(() {
        urls.indexOf(_url) > 0 ? n = urls.indexOf(_url) - 1 : n = 0;
      });
    } else {
      setState(() {
        urls.indexOf(_url) < urls.length
            ? n = urls.indexOf(_url) + 1
            : n = urls.length - 1;
      });
    }

     _url = await _loadHtmlFromAssets(n);

    web.loadUrl(_url);
    print(_url);
  }

  Future<String> _loadHtmlFromAssets(int n) async {
    String fileText = await rootBundle.loadString(urls[n]);
    print(fileText);
    String r = (Uri.dataFromString(fileText,
            mimeType: 'text/html', encoding: Encoding.getByName('utf-8'))
        .toString());
    print(r);
    return r;
  }

Code to add files :

Directory dir =
        Directory('${_appDocDir.path}/$folderName/${item.key_name}');
    List<FileSystemEntity> listOfAllFolderAndFiles =
        await dir.list(recursive: false).toList();

    if (UserData.ebook != null) UserData.ebook.clear();

    listOfAllFolderAndFiles.forEach((element) {
      if (element.toString().contains("html")) {
        String url = element.toString().replaceAll("File: ", "");
        url = url.replaceAll("'", "");
        UserData.ebook.add(url.toString());
      }
      UserData.eBookTitle = item.title;
    });

    print(UserData.ebook);

And result of printing UserData.ebook :

I/flutter ( 3465): [/data/user/0/com.pts.school_ebook_reader_app_prag/app_flutter/ebooks/02/00.html, /data/user/0/com.pts.school_ebook_reader_app_prag/app_flutter/ebooks/02/01.html, /data/user/0/com.pts.school_ebook_reader_app_prag/app_flutter/ebooks/02/02.html, /data/user/0/com.pts.school_ebook_reader_app_prag/app_flutter/ebooks/02/03.html, /data/user/0/com.pts.school_ebook_reader_app_prag/app_flutter/ebooks/02/04.html, /data/user/0/com.pts.school_ebook_reader_app_prag/app_flutter/ebooks/02/05.html, /data/user/0/com.pts.school_ebook_reader_app_prag/app_flutter/ebooks/02/06.html]

Checking:

//Checking if file exists
      print("File ${UserData.ebook[0]} exists ? " +
          File(UserData.ebook[0]).existsSync().toString());

Result:

I/flutter ( 3465): File /data/user/0/com.pts.school_ebook_reader_app_prag/app_flutter/ebooks/02/00.html exists ? true

3 Answers3

1

Finally after trying all possible plugins realized that Flutter webview as of now cannot display local html files that are heavy on css & javascript side.

The same webview can only display external urls or basic html files(minus css & js).

I switched over to native android for this.

0

I think you should load html as normal file, not like asset, because it's not located in Assets directory and convert it to base64:

  Future<String> _loadHtmlFromAssets(int n) async {
    final file = File(urls[n]);
    String fileText = await file.readAsString();
    final base64 = base64Encode(utf8.encode(fileText));
    return "data:text/html;base64,$base64";
  }

Then show it like:

return WebView(
    initialUrl: snapshot.data.toString(),
    javascriptMode: JavascriptMode.unrestricted,
  );
Autocrab
  • 3,474
  • 1
  • 15
  • 15
  • Thank you, finally it shows something...but its displaying in raw html exactly like whqat you printed in fileText..what should i do ? –  Jun 09 '21 at 06:32
  • Sorry to bother you again, its just showing a blank screen now, while it opens perfectly in browser –  Jun 09 '21 at 07:46
  • Hey @Autocrab did you check it ? –  Jun 09 '21 at 12:04
  • That's strange, i've run test app and it show html. Sorry, no ideas – Autocrab Jun 09 '21 at 12:31
0

I know this may be a little late, but it's possible to add an HTML view with complex js and css, it can be done in two methods. The first and really bad looking way is to put all in one file, it will be visible both in iOS and Android and to load it via the WebView, the other method (I'm using this one to load an Angular local web component in an app) is to use the plugin webview_flutter_plus which is an extension of the normal WebView in flutter. This plugin requires to add in the pubspec.yaml all the files needed in the WebComponent, so you can add multiple complex css files and js files.

The tutorial in the plugin is pretty complete.

The only problem I'm facing is with iOS, which doesn't find the files, but that should be caused by a native problem, iOS try to load the files runtime and those are in a different location, so you need to find the correct path and replace it runtime in the html file (that was the solution I've implemented in a native project in swift).

Hope this helped for future projects.

Anicecube
  • 11
  • 2