Flutter网页视图缓存插件flutter_webview_cash的使用

Flutter网页视图缓存插件flutter_webview_cash的使用

对于如何开始使用Flutter,您可以查看我们的在线文档。

iOS

为了让插件正常工作,您需要在ios/Runner/Info.plist文件中添加一个新的键:

<key>NSAppTransportSecurity</key>
<dict>
    <key>NSAllowsArbitraryLoads</key>
    <true/>
    <key>NSAllowsArbitraryLoadsInWebContent</key>
    <true/>
</dict>

NSAllowsArbitraryLoadsInWebContent用于iOS 10及以上版本,而NSAllowsArbitraryLoads用于iOS 9。

如何使用

使用Flutter导航启动全屏WebView

new MaterialApp(
  routes: {
    "/": (_) => new WebviewScaffold(
      url: "https://www.google.com",
      appBar: new AppBar(
        title: new Text("Widget webview"),
      ),
    ),
  },
);

可选参数hiddeninitialChild允许您在页面加载时显示其他内容。如果您将hidden设置为true,它会显示一个默认的CircularProgressIndicator。如果您另外指定了一个Widget作为initialChild,则可以在页面加载前显示您喜欢的任何内容。

例如,以下代码将在页面加载之前显示一个带有文本“等待…”的红色屏幕。

return new MaterialApp(
  title: 'Flutter WebView Demo',
  theme: new ThemeData(
    primarySwatch: Colors.blue,
  ),
  routes: {
    '/': (_) => const MyHomePage(title: 'Flutter WebView Demo'),
    '/widget': (_) => new WebviewScaffold(
      url: selectedUrl,
      appBar: new AppBar(
        title: const Text('Widget webview'),
      ),
      withZoom: true,
      withLocalStorage: true,
      hidden: true,
      initialChild: Container(
        color: Colors.redAccent,
        child: const Center(
          child: Text('Waiting.....'),
        ),
      ),
    ),
  },
);

FlutterWebviewPlugin提供了一个单例实例,该实例与一个唯一的WebView相关联,因此您可以从应用程序的任何位置控制WebView。

监听事件

final flutterWebviewPlugin = new FlutterWebviewPlugin();

flutterWebviewPlugin.onUrlChanged.listen((String url) {
  // 在这里处理URL更改事件
});

监听WebView中的滚动事件

final flutterWebviewPlugin = new FlutterWebviewPlugin();
flutterWebviewPlugin.onScrollYChanged.listen((double offsetY) { // 最新的垂直滚动偏移量
  // 在这里比较垂直滚动变化
});

flutterWebviewPlugin.onScrollXChanged.listen((double offsetX) { // 最新的水平滚动偏移量
  // 在这里比较水平滚动变化
});

注意:请注意iOS和Android之间的滚动距离略有不同。Android的滚动值差异通常比iOS设备大。

隐藏WebView

final flutterWebviewPlugin = new FlutterWebviewPlugin();

flutterWebviewPlugin.launch(url, hidden: true);

关闭已启动的WebView

flutterWebviewPlugin.close();

在自定义矩形区域内显示WebView

final flutterWebviewPlugin = new FlutterWebviewPlugin();

flutterWebviewPlugin.launch(url,
  fullScreen: false,
  rect: new Rect.fromLTWH(
    0.0,
    0.0,
    MediaQuery.of(context).size.width,
    300.0,
  ),
);

向WebView注入自定义代码

使用flutterWebviewPlugin.evalJavaScript(String code)。此函数必须在页面加载完成后运行(即监听onStateChanged事件,当状态为finishLoad时)。

如果要嵌入大量JavaScript,可以使用资源文件。将资源文件添加到pubspec.yaml,然后调用函数如下:

Future<String> loadJS(String name) async {
  var givenJS = rootBundle.loadString('assets/$name.js');
  return givenJS.then((String js) {
    flutterWebViewPlugin.onStateChanged.listen((viewState) async {
      if (viewState.type == WebViewState.finishLoad) {
        flutterWebViewPlugin.evalJavascript(js);
      }
    });
  });
}

访问文件系统中的本地文件

在启动函数或WebView框架中将withLocalUrl选项设置为true以启用本地URL支持。

注意,在iOS上,还需要将localUrlScope选项设置为目录路径。所有位于该文件夹(或子文件夹)内的文件都将被允许访问。如果省略,则仅打开的本地文件将被允许访问,导致无法加载子资源。此选项在Android上被忽略。

忽略SSL错误

ignoreSSLErrors选项设置为true以显示来自通常不受WebView信任的服务器(如自签名证书)的内容。

警告: 不要在生产环境中使用此功能。

注意,在iOS上,您需要向ios/Runner/Info.plist文件中添加新的键:

<key>NSAppTransportSecurity</key>
<dict>
    <key>NSAllowsArbitraryLoads</key>
    <true/>
    <key>NSAllowsArbitraryLoadsInWebContent</key>
    <true/>
</dict>

NSAllowsArbitraryLoadsInWebContent用于iOS 10及以上版本,而NSAllowsArbitraryLoads用于iOS 9。

您可以通过访问https://self-signed.badssl.com/来测试您的SSL证书是否已被忽略。

WebView事件

  • Stream<Null> onDestroy
  • Stream<String> onUrlChanged
  • Stream<WebViewStateChanged> onStateChanged
  • Stream<double> onScrollXChanged
  • Stream<double> onScrollYChanged
  • Stream<String> onError

别忘了释放WebView

flutterWebviewPlugin.dispose()

WebView函数

Future<Null> launch(String url, {
  Map<String, String> headers: null,
  Set<JavascriptChannel> javascriptChannels: null,
  bool withJavascript: true,
  bool clearCache: false,
  bool clearCookies: false,
  bool hidden: false,
  bool enableAppScheme: true,
  Rect rect: null,
  String userAgent: null,
  bool withZoom: false,
  bool displayZoomControls: false,
  bool withLocalStorage: true,
  bool withLocalUrl: true,
  String localUrlScope: null,
  bool withOverviewMode: false,
  bool scrollBar: true,
  bool supportMultipleWindows: false,
  bool appCacheEnabled: false,
  bool allowFileURLs: false,
  bool useWideViewPort: false,
  String invalidUrlRegex: null,
  bool geolocationEnabled: false,
  bool debuggingEnabled: false,
  bool ignoreSSLErrors: false,
});
Future<String> evalJavascript(String code);
Future<Map<String, dynamic>> getCookies();
Future<Null> cleanCookies();
Future<Null> resize(Rect rect);
Future<Null> show();
Future<Null> hide();
Future<Null> reloadUrl(String url);
Future<Null> close();
Future<Null> reload();
Future<Null> goBack();
Future<Null> goForward();
Future<Null> stopLoading();
Future<bool> canGoBack();
Future<bool> canGoForward();

完整示例Demo

以下是一个完整的示例Demo,展示了如何使用flutter_webview_cash插件创建一个具有多种功能的WebView。

import 'dart:async';

import 'package:flutter/material.dart';
import 'package:flutter_webview_cash/flutter_webview_plugin.dart';

const kAndroidUserAgent =
    'Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 Mobile Safari/537.36';

String selectedUrl = 'https://flutter.io';

// ignore: prefer_collection_literals
final Set<JavascriptChannel> jsChannels = [
  JavascriptChannel(
      name: 'Print',
      onMessageReceived: (JavascriptMessage message) {
        print(message.message);
      }),
].toSet();

void main() {
  WidgetsFlutterBinding.ensureInitialized();
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  final flutterWebViewPlugin = FlutterWebviewPlugin();

  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter WebView Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      routes: {
        '/': (_) => const MyHomePage(title: 'Flutter WebView Demo'),
        '/widget': (_) {
          return WebviewScaffold(
            url: selectedUrl,
            javascriptChannels: jsChannels,
            mediaPlaybackRequiresUserGesture: false,
            appBar: AppBar(
              title: const Text('Widget WebView'),
            ),
            withZoom: true,
            withLocalStorage: true,
            hidden: true,
            initialChild: Container(
              color: Colors.redAccent,
              child: const Center(
                child: Text('Waiting.....'),
              ),
            ),
            bottomNavigationBar: BottomAppBar(
              child: Row(
                children: <Widget>[
                  IconButton(
                    icon: const Icon(Icons.arrow_back_ios),
                    onPressed: () {
                      flutterWebViewPlugin.goBack();
                    },
                  ),
                  IconButton(
                    icon: const Icon(Icons.arrow_forward_ios),
                    onPressed: () {
                      flutterWebViewPlugin.goForward();
                    },
                  ),
                  IconButton(
                    icon: const Icon(Icons.autorenew),
                    onPressed: () {
                      flutterWebViewPlugin.reload();
                    },
                  ),
                ],
              ),
            ),
          );
        },
      },
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({Key? key, required this.title}) : super(key: key);

  final String title;

  [@override](/user/override)
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  // WebView插件实例
  final flutterWebViewPlugin = FlutterWebviewPlugin();

  // 销毁监听器
  late StreamSubscription _onDestroy;

  // URL更改监听器
  late StreamSubscription<String> _onUrlChanged;

  // 状态更改监听器
  late StreamSubscription<WebViewStateChanged> _onStateChanged;

  late StreamSubscription<WebViewHttpError> _onHttpError;

  late StreamSubscription<double> _onProgressChanged;

  late StreamSubscription<double> _onScrollYChanged;

  late StreamSubscription<double> _onScrollXChanged;

  final _urlCtrl = TextEditingController(text: selectedUrl);

  final _codeCtrl = TextEditingController(text: 'window.navigator.userAgent');

  final _scaffoldKey = GlobalKey<ScaffoldState>();

  final _history = [];

  [@override](/user/override)
  void initState() {
    super.initState();

    flutterWebViewPlugin.close();

    _urlCtrl.addListener(() {
      selectedUrl = _urlCtrl.text;
    });

    // 添加销毁监听器
    _onDestroy = flutterWebViewPlugin.onDestroy.listen((_) {
      if (mounted) {
        ScaffoldMessenger.of(context)
            .showSnackBar(const SnackBar(content: Text('Webview Destroyed')));
      }
    });

    // 添加URL更改监听器
    _onUrlChanged = flutterWebViewPlugin.onUrlChanged.listen((String url) {
      if (mounted) {
        setState(() {
          _history.add('onUrlChanged: $url');
        });
      }
    });

    _onProgressChanged =
        flutterWebViewPlugin.onProgressChanged.listen((double progress) {
      if (mounted) {
        setState(() {
          _history.add('onProgressChanged: $progress');
        });
      }
    });

    _onScrollYChanged =
        flutterWebViewPlugin.onScrollYChanged.listen((double y) {
      if (mounted) {
        setState(() {
          _history.add('Scroll in Y Direction: $y');
        });
      }
    });

    _onScrollXChanged =
        flutterWebViewPlugin.onScrollXChanged.listen((double x) {
      if (mounted) {
        setState(() {
          _history.add('Scroll in X Direction: $x');
        });
      }
    });

    _onStateChanged =
        flutterWebViewPlugin.onStateChanged.listen((WebViewStateChanged state) {
      if (mounted) {
        setState(() {
          _history.add('onStateChanged: ${state.type} ${state.url}');
        });
      }
    });

    _onHttpError =
        flutterWebViewPlugin.onHttpError.listen((WebViewHttpError error) {
      if (mounted) {
        setState(() {
          _history.add('onHttpError: ${error.code} ${error.url}');
        });
      }
    });
  }

  [@override](/user/override)
  void dispose() {
    // 取消所有监听器
    _onDestroy.cancel();
    _onUrlChanged.cancel();
    _onStateChanged.cancel();
    _onHttpError.cancel();
    _onProgressChanged.cancel();
    _onScrollXChanged.cancel();
    _onScrollYChanged.cancel();

    flutterWebViewPlugin.dispose();

    super.dispose();
  }

  [@override](/user/override)
  Widget build(BuildContext context) {
    return Scaffold(
      key: _scaffoldKey,
      appBar: AppBar(
        title: const Text('插件示例应用'),
      ),
      body: SingleChildScrollView(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Container(
              padding: const EdgeInsets.all(24.0),
              child: TextField(controller: _urlCtrl),
            ),
            ElevatedButton(
              onPressed: () {
                flutterWebViewPlugin.launch(
                  selectedUrl,
                  rect: Rect.fromLTWH(
                      0.0, 0.0, MediaQuery.of(context).size.width, 300.0),
                  userAgent: kAndroidUserAgent,
                  invalidUrlRegex:
                      r'^(https).+(twitter)', // 防止点击Twitter图标时重定向到Twitter
                );
              },
              child: const Text('打开WebView(矩形区域)'),
            ),
            ElevatedButton(
              onPressed: () {
                flutterWebViewPlugin.launch(selectedUrl, hidden: true);
              },
              child: const Text('打开“隐藏”WebView'),
            ),
            ElevatedButton(
              onPressed: () {
                flutterWebViewPlugin.launch(selectedUrl);
              },
              child: const Text('全屏打开WebView'),
            ),
            ElevatedButton(
              onPressed: () {
                Navigator.of(context).pushNamed('/widget');
              },
              child: const Text('打开widget WebView'),
            ),
            Container(
              padding: const EdgeInsets.all(24.0),
              child: TextField(controller: _codeCtrl),
            ),
            ElevatedButton(
              onPressed: () {
                final future =
                    flutterWebViewPlugin.evalJavascript(_codeCtrl.text);
                future.then((String? result) {
                  setState(() {
                    _history.add('eval: $result');
                  });
                });
              },
              child: const Text('执行一些JavaScript'),
            ),
            ElevatedButton(
              onPressed: () {
                final future = flutterWebViewPlugin
                    .evalJavascript('alert("Hello World");');
                future.then((String? result) {
                  setState(() {
                    _history.add('eval: $result');
                  });
                });
              },
              child: const Text('执行JavaScript alert()'),
            ),
            ElevatedButton(
              onPressed: () {
                setState(() {
                  _history.clear();
                });
                flutterWebViewPlugin.close();
              },
              child: const Text('关闭'),
            ),
            ElevatedButton(
              onPressed: () {
                flutterWebViewPlugin.getCookies().then((m) {
                  setState(() {
                    _history.add('cookies: $m');
                  });
                });
              },
              child: const Text('获取Cookies'),
            ),
            Text(_history.join('\n'))
          ],
        ),
      ),
    );
  }
}

更多关于Flutter网页视图缓存插件flutter_webview_cash的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter网页视图缓存插件flutter_webview_cash的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


flutter_webview_cache 是一个用于在 Flutter 应用中缓存网页视图的插件。它可以帮助你加载和缓存网页内容,从而在下次访问时更快地加载页面,减少网络请求。

安装

首先,你需要在 pubspec.yaml 文件中添加 flutter_webview_cache 依赖:

dependencies:
  flutter:
    sdk: flutter
  flutter_webview_cache: ^1.0.0  # 请检查最新版本

然后运行 flutter pub get 来安装依赖。

基本用法

以下是一个使用 flutter_webview_cache 的基本示例:

import 'package:flutter/material.dart';
import 'package:flutter_webview_cache/flutter_webview_cache.dart';

class WebViewCacheExample extends StatelessWidget {
  [@override](/user/override)
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('WebView Cache Example'),
      ),
      body: WebViewCache(
        initialUrl: 'https://example.com',
        enableCache: true, // 启用缓存
      ),
    );
  }
}

void main() => runApp(MaterialApp(
  home: WebViewCacheExample(),
));

主要参数

  • initialUrl: 初始加载的URL。
  • enableCache: 是否启用缓存,默认为 true
  • cacheDuration: 缓存的有效时间,默认为 7 天。
  • onPageStarted: 当页面开始加载时调用。
  • onPageFinished: 当页面加载完成时调用。
  • onError: 当页面加载出错时调用。

清除缓存

你可以使用 WebViewCacheController 来手动清除缓存:

class WebViewCacheExample extends StatefulWidget {
  [@override](/user/override)
  _WebViewCacheExampleState createState() => _WebViewCacheExampleState();
}

class _WebViewCacheExampleState extends State<WebViewCacheExample> {
  WebViewCacheController _controller;

  [@override](/user/override)
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('WebView Cache Example'),
        actions: [
          IconButton(
            icon: Icon(Icons.delete),
            onPressed: () {
              _controller.clearCache();
            },
          ),
        ],
      ),
      body: WebViewCache(
        initialUrl: 'https://example.com',
        enableCache: true,
        onWebViewCreated: (controller) {
          _controller = controller;
        },
      ),
    );
  }
}
回到顶部