有时候需要从后端获取用户协议这样的 html 字符串,然后显示出来。但是 webview_flutter 仅支持 initialUrl 参数,不像 flutter_inappwebview 支持 initialData: InAppWebViewInitialData(data: html)
这样的参数。如果硬要显示,则需要绕一圈。或者用 flutter_inappwebview 插件。
然而 flutter_inappwebview 在 android 端的混合视图掉帧很严重,正式版的 webview_flutter 1.0.5 发布后,性能更强。
现在来实现在 webview_flutter 中显示从后端或者其他什么地方来的 html 字符串(以下 html 均指 html 字符串)。
既然 webview_flutter 仅支持 url 的形式,那么我们就给他一个 url。所以得想办法启动一个 HTTP 服务。好消息是 Dart 可以很方便的实现。可以通过 var server = HttpServer.bind(address, port)
开启一个 http server。然后调用 server.listen(reqHandle)
即可监听请求,并返回响应。
一个简单的示例:
/// 要显示的 html
var html = "<html><p>hello my friend</p></html>";
// http server
HttpServer server;
/// 处理请求,这里对所有请求都响应 html
void reqHandle(HttpRequest request) {
request.response.headers.add('Content-Type', 'text/html; charset=UTF-8');
request.response.write(html);
request.response.close();
}
/// 开启一个服务
Future<HttpServer> serve() async {
server = await HttpServer.bind(InternetAddress.loopbackIPv4, 0);
server.listen(reqHandle);
return server;
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: server == null ? CircularProgressIndicator() : Container(
child: WebView(
initialUrl: 'http://${server.address.address}:${server.port}/',
),
),
);
}
@override
void initState() {
// 切换为高性能的混合视图
if (Platform.isAndroid) WebView.platform = SurfaceAndroidWebView();
serve().then((val){setState(() {});});
super.initState();
}
@override
void dispose() {
server?.close();
super.dispose();
}
通过一个简单的 http server 即可实现。如果你觉得还是太麻烦,可以使用插件 html_server
使用超简单
class Example extends StatefulWidget {
@override
_ExampleState createState() => _ExampleState();
}
class _ExampleState extends State<Example> {
HtmlServer server;
@override
Widget build(BuildContext context) {
return Container(
child: server == null ? CircularProgressIndicator() : WebView(
initialUrl: server.url,
),
);
}
initWeb() async {
String html = "<html><p>hello my friend</p></html>";
server = await HtmlServer.serve(html);
setState(() {});
}
@override
void initState() {
initWeb();
super.initState();
}
@override
void dispose() {
server.dispose();
super.dispose();
}
}
如果要打开 assets 的资源,可以使用 local_assets_server 插件