实现在 webview_flutter 中显示从服务器请求的 html

967 阅读1分钟

有时候需要从后端获取用户协议这样的 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 插件