无法在 Web 视图中显示来自本地存储的 html 文件
Unable to display html file from local storage in webview
我有一个 Flutter 项目,我在其中:
- 正在下载 zip 文件(包含 html 个文件)
- 正在将 html 文件提取到新目录 (ebooks/02)
- 将本地文件 urls 保存在列表中
- 在 Webview 中显示 url 并在列表中来回迭代。
但是,在 Web 视图中,我得到的只是“无法加载资产...”
虽然任何标准的 http url 在 webview 中都可以正常工作。
我尝试了这两个答案但没有结果:Answer1 & Answer2
我得到的异常是:
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
我需要了解如何在 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
我认为你应该加载 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,
);
最后在尝试了所有可能的插件后意识到 Flutter webview 目前无法显示本地 html 文件,这些文件在 css 和 javascript 端很重。
相同的 webview 只能显示外部 url 或基本 html 文件(减去 css & js)。
为此我切换到原生 android。
我知道这可能有点晚了,但是可以添加带有复杂 js 的 HTML 视图和 css,可以通过两种方法完成。第一个也是非常难看的方法是将所有内容放在一个文件中,它在 iOS 和 Android 中都可见,并通过 WebView 加载它,另一种方法(我正在使用这个在应用程序中加载 Angular 本地 Web 组件)是使用插件 webview_flutter_plus,它是 flutter 中普通 WebView 的扩展。本插件需要在pubspec.yaml中添加WebComponent中需要的所有文件,所以可以添加多个复杂的css文件和js文件。
插件中的教程很完整。
我面临的唯一问题是 iOS,它没有找到文件,但这应该是由本机问题引起的,iOS 尝试加载文件运行时和它们位于不同的位置,因此您需要找到正确的路径并在 html 文件中运行时替换它(这是我在 swift 的本机项目中实现的解决方案)。
希望这对以后的项目有所帮助。
我有一个 Flutter 项目,我在其中:
- 正在下载 zip 文件(包含 html 个文件)
- 正在将 html 文件提取到新目录 (ebooks/02)
- 将本地文件 urls 保存在列表中
- 在 Webview 中显示 url 并在列表中来回迭代。
但是,在 Web 视图中,我得到的只是“无法加载资产...”
虽然任何标准的 http url 在 webview 中都可以正常工作。
我尝试了这两个答案但没有结果:Answer1 & Answer2
我得到的异常是:
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
我需要了解如何在 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
我认为你应该加载 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,
);
最后在尝试了所有可能的插件后意识到 Flutter webview 目前无法显示本地 html 文件,这些文件在 css 和 javascript 端很重。
相同的 webview 只能显示外部 url 或基本 html 文件(减去 css & js)。
为此我切换到原生 android。
我知道这可能有点晚了,但是可以添加带有复杂 js 的 HTML 视图和 css,可以通过两种方法完成。第一个也是非常难看的方法是将所有内容放在一个文件中,它在 iOS 和 Android 中都可见,并通过 WebView 加载它,另一种方法(我正在使用这个在应用程序中加载 Angular 本地 Web 组件)是使用插件 webview_flutter_plus,它是 flutter 中普通 WebView 的扩展。本插件需要在pubspec.yaml中添加WebComponent中需要的所有文件,所以可以添加多个复杂的css文件和js文件。
插件中的教程很完整。
我面临的唯一问题是 iOS,它没有找到文件,但这应该是由本机问题引起的,iOS 尝试加载文件运行时和它们位于不同的位置,因此您需要找到正确的路径并在 html 文件中运行时替换它(这是我在 swift 的本机项目中实现的解决方案)。
希望这对以后的项目有所帮助。