I want to render a local HTML file stored in my phone memory in webview using flutter and dart.
问题:
回答1:
Here is an answer with a little more detail. I am using the webview_flutter plugin from the Flutter Team.
Steps
Add the dependency to pubspec.yaml:
dependencies: webview_flutter: ^0.3.4
Put an html file in the
assets
folder (see this). I'll call ithelp.html
.Get the html string in code and add it to the webview.
import 'dart:convert'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:webview_flutter/webview_flutter.dart'; class HelpScreen extends StatefulWidget { @override HelpScreenState createState() { return HelpScreenState(); } } class HelpScreenState extends State<HelpScreen> { WebViewController _controller; @override Widget build(BuildContext context) { _loadHtmlFromAssets(); return Scaffold( appBar: AppBar(title: Text('Help')), body: WebView( initialUrl: 'about:blank', onWebViewCreated: (WebViewController webViewController) { _controller = webViewController; }, ), ); } _loadHtmlFromAssets() async { String fileText = await rootBundle.loadString('assets/help.html'); _controller.loadUrl( Uri.dataFromString( fileText, mimeType: 'text/html', encoding: Encoding.getByName('utf-8') ).toString()); } }
Notes:
- I needed to set the encoding to UTF-8 because I was getting a crash for non-ASCII characters.
- In iOS you need to add the key
io.flutter.embedded_views_preview
astrue
in the Info.plist file. Check the docs for any update on this requirement.
See also
- The Power of WebViews in Flutter
回答2:
You can pass a data URI
Uri.dataFromString('<html><body>hello world</body></html>', mimeType: 'text/html').toString()
or you can launch a web server inside Flutter and pass an URL that points to the IP/port the server serves the file from.
See also the discussion in https://github.com/fluttercommunity/flutter_webview_plugin/issues/23
See https://flutter.io/docs/development/ui/assets-and-images#loading-text-assets about how to load a string from assets.
See https://flutter.io/docs/cookbook/persistence/reading-writing-files for how to read other files.
回答3:
@Suragch, your code doesn't work as you posted it, it says localUrl was called on null. _loadHtmlFromAssets needs to be called after assigning the controller :
onWebViewCreated: (WebViewController webViewController) {
_controller = webViewController;
_loadHtmlFromAssets();
}
Then it works fine :)
回答4:
I have the same problem; this is how I solved it.
Add webview_flutter to your project dependencies:
webview_flutter: 0.3.14+1
Create a WebViewController inside your screen/stateful widget
WebViewController _controller;
Implement the WebView and assign a value to the _controller using the onWebViewCreated property. Load the HTML file.
WebView(
initialUrl: '',
onWebViewCreated: (WebViewController webViewController) async {
_controller = webViewController;
await loadHtmlFromAssets('legal/privacy_policy.html', _controller);
},
)
- Implement the function to load the file from the asset folder
Future<void> loadHtmlFromAssets(String filename, controller) async {
String fileText = await rootBundle.loadString(filename);
controller.loadUrl(Uri.dataFromString(fileText, mimeType: 'text/html', encoding: Encoding.getByName('utf-8')).toString());
}
回答5:
You can use my plugin flutter_inappwebview, which has a lot of events, methods, and options compared to other plugins!
To load an html file from your assets folder, you need to declare it in the pubspec.yaml
file before use it (see more here).
Example of a pubspec.yaml
file:
...
# The following section is specific to Flutter.
flutter:
# The following line ensures that the Material Icons font is
# included with your application, so that you can use the icons in
# the material Icons class.
uses-material-design: true
assets:
- assets/index.html
...
After that, you can simply use the initialFile
parameter of the InAppWebView
widget to load index.html
into the WebView:
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter_inappwebview/flutter_inappwebview.dart';
Future main() async {
runApp(new MyApp());
}
class MyApp extends StatefulWidget {
@override
_MyAppState createState() => new _MyAppState();
}
class _MyAppState extends State<MyApp> {
@override
void initState() {
super.initState();
}
@override
void dispose() {
super.dispose();
}
@override
Widget build(BuildContext context) {
return MaterialApp(
home: InAppWebViewPage()
);
}
}
class InAppWebViewPage extends StatefulWidget {
@override
_InAppWebViewPageState createState() => new _InAppWebViewPageState();
}
class _InAppWebViewPageState extends State<InAppWebViewPage> {
InAppWebViewController webView;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("InAppWebView")
),
body: Container(
child: Column(children: <Widget>[
Expanded(
child: Container(
child: InAppWebView(
initialFile: "assets/index.html",
initialHeaders: {},
initialOptions: InAppWebViewWidgetOptions(
inAppWebViewOptions: InAppWebViewOptions(
debuggingEnabled: true,
),
),
onWebViewCreated: (InAppWebViewController controller) {
webView = controller;
},
onLoadStart: (InAppWebViewController controller, String url) {
},
onLoadStop: (InAppWebViewController controller, String url) {
},
),
),
),
]))
);
}
}
回答6:
unzip the apk package,I found the reason: path is wrong;
For Android:
"assets/test.html" == "file:///android_asset/flutter_assets/assets/test.html"
so,just like this:
WebView(
initialUrl: "file:///android_asset/flutter_assets/assets/test.html",
javascriptMode: JavascriptMode.unrestricted,
)
you can load "assets/test.html".