无法在 webview 中显示本地存储中的 html 文件

Posted

技术标签:

【中文标题】无法在 webview 中显示本地存储中的 html 文件【英文标题】:Unable to display html file from local storage in webview 【发布时间】:2021-08-25 23:08:31 【问题描述】:

我有一个 Flutter 项目:

下载 zip 文件(全是 html 文件) 将 html 文件解压到新目录 (ebooks/02) 将本地文件 url 保存在列表中 在 Webview 中显示 url 并在列表中来回迭代。

但是,在网络视图中,我得到的只是“无法加载资产...”

尽管任何标准的 http url 在 webview 中都可以正常工作。

我尝试了这两个答案但没有结果:Answer1 & Answer2

我得到的例外是:

E/flutter (10963): [ERROR:flutter/lib/ui/ui_dart_state.cc(186)] 未处理的异常:无法加载资产:/data/user/0/com.pts.school_ebook_reader_app_prag/app_flutter/ebooks /04/00.html

我需要了解如何在 webview 中显示给定路径的本地 html。

任何帮助将不胜感激。

编辑:

webview 代码(目前只显示列表中的第一个 url):

 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;
  

添加文件的代码:

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);

以及打印 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 if file exists
      print("File $UserData.ebook[0] exists ? " +
          File(UserData.ebook[0]).existsSync().toString());

结果:

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

【问题讨论】:

拜托,你能在这里添加代码吗?然后我们可以尝试理解这个问题。 您是否检查过此路径上的文件是否存在?在您保存文件的位置显示代码 是的,当我尝试在浏览器中打开它时,它也可以工作。添​​加保存文件的代码 【参考方案1】:

我认为您应该将 html 作为普通文件加载,而不是像资产一样,因为它不在 Assets 目录中并将其转换为 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";
  

然后显示如下:

return WebView(
    initialUrl: snapshot.data.toString(),
    javascriptMode: JavascriptMode.unrestricted,
  );

【讨论】:

谢谢,最后它显示了一些东西......但它以原始 html 显示,就像你在 fileText 中打印的 whqat 一样......我该怎么办? 很抱歉再次打扰您,它现在只是显示一个空白屏幕,而它在浏览器中完美打开 嘿@Autocrab 你检查了吗? 这很奇怪,我已经运行了测试应用程序,它显示了 html。抱歉,没有想法【参考方案2】:

在尝试了所有可能的插件之后,终于意识到 Flutter webview 目前无法显示本地 html 文件,这些文件在 css 和 javascript 方面很繁重。

同一个 webview 只能显示外部 url 或基本 html 文件(减去 css 和 js)。

为此,我切换到了原生 android

【讨论】:

【参考方案3】:

我知道这可能有点晚了,但是可以使用复杂的 js 和 css 添加 HTML 视图,可以通过两种方法完成。第一种也是非常糟糕的方法是将所有内容放在一个文件中,它将在 ios 和 Android 中都可见,并通过 WebView 加载它,另一种方法(我正在使用这个方法来加载 Angular 本地 Web 组件)一个应用程序)是使用插件webview_flutter_plus,它是flutter中普通WebView的扩展。该插件需要在 pubspec.yaml 中添加 WebComponent 所需的所有文件,这样你就可以添加多个复杂的 css 文件和 js 文件。

插件中的教程非常完整。

我面临的唯一问题是 iOS,它找不到文件,但这应该是由本机问题引起的,iOS 尝试加载文件运行时并且这些文件位于不同的位置,所以你需要在 html 文件中找到正确的路径并在运行时替换它(这是我在 swift 的本机项目中实现的解决方案)。

希望这对未来的项目有所帮助。

【讨论】:

以上是关于无法在 webview 中显示本地存储中的 html 文件的主要内容,如果未能解决你的问题,请参考以下文章

从资产文件夹的本地html(WebView)中的外部存储中打开文件(视频)? (安卓)

为啥 WebView 无法打开某些本地 URL(Android)?

当设备在 react-native 中离线时,在 webview 中显示本地图像

Android - 如何在 WebView 中访问本地存储值?

Android 4.0.1 打破了 WebView HTML 5 本地存储?

Android-WebView与本地HTML(播放视频)