[webview_flutter] Expose loadFile and loadHtmlString through app facing package. (#4558)
diff --git a/packages/webview_flutter/webview_flutter/CHANGELOG.md b/packages/webview_flutter/webview_flutter/CHANGELOG.md
index 63d95c0..7b7e112 100644
--- a/packages/webview_flutter/webview_flutter/CHANGELOG.md
+++ b/packages/webview_flutter/webview_flutter/CHANGELOG.md
@@ -1,5 +1,6 @@
-## NEXT
+## 2.4.0
+* Adds support for the `loadFile` and `loadHtmlString` methods.
* Updates example app Android compileSdkVersion to 31.
* Integration test fixes.
* Updates code for new analysis options.
diff --git a/packages/webview_flutter/webview_flutter/example/lib/main.dart b/packages/webview_flutter/webview_flutter/example/lib/main.dart
index 0a8928e..5c05e8f 100644
--- a/packages/webview_flutter/webview_flutter/example/lib/main.dart
+++ b/packages/webview_flutter/webview_flutter/example/lib/main.dart
@@ -9,6 +9,7 @@
import 'dart:io';
import 'package:flutter/material.dart';
+import 'package:path_provider/path_provider.dart';
import 'package:webview_flutter/webview_flutter.dart';
void main() => runApp(MaterialApp(home: WebViewExample()));
@@ -28,6 +29,25 @@
</html>
''';
+const String kLocalExamplePage = '''
+<!DOCTYPE html>
+<html lang="en">
+<head>
+<title>Load file or HTML string example</title>
+</head>
+<body>
+
+<h1>Local demo page</h1>
+<p>
+ This is an example page used to demonstrate how to load a local file or HTML
+ string using the <a href="https://pub.dev/packages/webview_flutter">Flutter
+ webview</a> plugin.
+</p>
+
+</body>
+</html>
+''';
+
class WebViewExample extends StatefulWidget {
@override
_WebViewExampleState createState() => _WebViewExampleState();
@@ -133,6 +153,8 @@
listCache,
clearCache,
navigationDelegate,
+ loadLocalFile,
+ loadHtmlString,
}
class SampleMenu extends StatelessWidget {
@@ -171,6 +193,12 @@
case MenuOptions.navigationDelegate:
_onNavigationDelegateExample(controller.data!, context);
break;
+ case MenuOptions.loadLocalFile:
+ _onLoadLocalFileExample(controller.data!, context);
+ break;
+ case MenuOptions.loadHtmlString:
+ _onLoadHtmlStringExample(controller.data!, context);
+ break;
}
},
itemBuilder: (BuildContext context) => <PopupMenuItem<MenuOptions>>[
@@ -203,6 +231,14 @@
value: MenuOptions.navigationDelegate,
child: Text('Navigation Delegate example'),
),
+ const PopupMenuItem<MenuOptions>(
+ value: MenuOptions.loadHtmlString,
+ child: Text('Load HTML string'),
+ ),
+ const PopupMenuItem<MenuOptions>(
+ value: MenuOptions.loadLocalFile,
+ child: Text('Load local file'),
+ ),
],
);
},
@@ -279,6 +315,18 @@
await controller.loadUrl('data:text/html;base64,$contentBase64');
}
+ Future<void> _onLoadLocalFileExample(
+ WebViewController controller, BuildContext context) async {
+ final String pathToIndex = await _prepareLocalFile();
+
+ await controller.loadFile(pathToIndex);
+ }
+
+ Future<void> _onLoadHtmlStringExample(
+ WebViewController controller, BuildContext context) async {
+ await controller.loadHtmlString(kLocalExamplePage);
+ }
+
Widget _getCookieList(String cookies) {
if (cookies == null || cookies == '""') {
return Container();
@@ -292,6 +340,17 @@
children: cookieWidgets.toList(),
);
}
+
+ static Future<String> _prepareLocalFile() async {
+ final String tmpDir = (await getTemporaryDirectory()).path;
+ final File indexFile = File(
+ <String>{tmpDir, 'www', 'index.html'}.join(Platform.pathSeparator));
+
+ await indexFile.create(recursive: true);
+ await indexFile.writeAsString(kLocalExamplePage);
+
+ return indexFile.path;
+ }
}
class NavigationControls extends StatelessWidget {
diff --git a/packages/webview_flutter/webview_flutter/example/pubspec.yaml b/packages/webview_flutter/webview_flutter/example/pubspec.yaml
index 53fdd56..284a7a9 100644
--- a/packages/webview_flutter/webview_flutter/example/pubspec.yaml
+++ b/packages/webview_flutter/webview_flutter/example/pubspec.yaml
@@ -9,6 +9,7 @@
dependencies:
flutter:
sdk: flutter
+ path_provider: ^2.0.6
webview_flutter:
# When depending on this package from a real application you should use:
# webview_flutter: ^x.y.z
diff --git a/packages/webview_flutter/webview_flutter/lib/src/webview.dart b/packages/webview_flutter/webview_flutter/lib/src/webview.dart
index b24020b..eb6ee4e 100644
--- a/packages/webview_flutter/webview_flutter/lib/src/webview.dart
+++ b/packages/webview_flutter/webview_flutter/lib/src/webview.dart
@@ -496,6 +496,35 @@
WebView _widget;
+ /// Loads the file located at the specified [absoluteFilePath].
+ ///
+ /// The [absoluteFilePath] parameter should contain the absolute path to the
+ /// file as it is stored on the device. For example:
+ /// `/Users/username/Documents/www/index.html`.
+ ///
+ /// Throws an ArgumentError if the [absoluteFilePath] does not exist.
+ Future<void> loadFile(
+ String absoluteFilePath,
+ ) {
+ assert(absoluteFilePath.isNotEmpty);
+ return _webViewPlatformController.loadFile(absoluteFilePath);
+ }
+
+ /// Loads the supplied HTML string.
+ ///
+ /// The [baseUrl] parameter is used when resolving relative URLs within the
+ /// HTML string.
+ Future<void> loadHtmlString(
+ String html, {
+ String? baseUrl,
+ }) {
+ assert(html.isNotEmpty);
+ return _webViewPlatformController.loadHtmlString(
+ html,
+ baseUrl: baseUrl,
+ );
+ }
+
/// Loads the specified URL.
///
/// If `headers` is not null and the URL is an HTTP URL, the key value paris in `headers` will
diff --git a/packages/webview_flutter/webview_flutter/pubspec.yaml b/packages/webview_flutter/webview_flutter/pubspec.yaml
index 23693f3..82f790a 100644
--- a/packages/webview_flutter/webview_flutter/pubspec.yaml
+++ b/packages/webview_flutter/webview_flutter/pubspec.yaml
@@ -2,7 +2,7 @@
description: A Flutter plugin that provides a WebView widget on Android and iOS.
repository: https://github.com/flutter/plugins/tree/master/packages/webview_flutter/webview_flutter
issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+webview%22
-version: 2.3.1
+version: 2.4.0
environment:
sdk: ">=2.14.0 <3.0.0"
@@ -19,7 +19,7 @@
dependencies:
flutter:
sdk: flutter
- webview_flutter_android: ^2.3.1
+ webview_flutter_android: ^2.4.0
webview_flutter_platform_interface: ^1.5.2
webview_flutter_wkwebview: ^2.4.0
diff --git a/packages/webview_flutter/webview_flutter/test/webview_flutter_test.dart b/packages/webview_flutter/webview_flutter/test/webview_flutter_test.dart
index f8a9e33..b055302 100644
--- a/packages/webview_flutter/webview_flutter/test/webview_flutter_test.dart
+++ b/packages/webview_flutter/webview_flutter/test/webview_flutter_test.dart
@@ -88,6 +88,98 @@
expect(disabledparams.webSettings!.javascriptMode, JavascriptMode.disabled);
});
+ testWidgets('Load file', (WidgetTester tester) async {
+ WebViewController? controller;
+ await tester.pumpWidget(
+ WebView(
+ onWebViewCreated: (WebViewController webViewController) {
+ controller = webViewController;
+ },
+ ),
+ );
+
+ expect(controller, isNotNull);
+
+ await controller!.loadFile('/test/path/index.html');
+
+ verify(mockWebViewPlatformController.loadFile(
+ '/test/path/index.html',
+ ));
+ });
+
+ testWidgets('Load file with empty path', (WidgetTester tester) async {
+ WebViewController? controller;
+ await tester.pumpWidget(
+ WebView(
+ onWebViewCreated: (WebViewController webViewController) {
+ controller = webViewController;
+ },
+ ),
+ );
+
+ expect(controller, isNotNull);
+
+ expect(() => controller!.loadFile(''), throwsAssertionError);
+ });
+
+ testWidgets('Load HTML string without base URL', (WidgetTester tester) async {
+ WebViewController? controller;
+ await tester.pumpWidget(
+ WebView(
+ onWebViewCreated: (WebViewController webViewController) {
+ controller = webViewController;
+ },
+ ),
+ );
+
+ expect(controller, isNotNull);
+
+ await controller!.loadHtmlString('<p>This is a test paragraph.</p>');
+
+ verify(mockWebViewPlatformController.loadHtmlString(
+ '<p>This is a test paragraph.</p>',
+ ));
+ });
+
+ testWidgets('Load HTML string with base URL', (WidgetTester tester) async {
+ WebViewController? controller;
+ await tester.pumpWidget(
+ WebView(
+ onWebViewCreated: (WebViewController webViewController) {
+ controller = webViewController;
+ },
+ ),
+ );
+
+ expect(controller, isNotNull);
+
+ await controller!.loadHtmlString(
+ '<p>This is a test paragraph.</p>',
+ baseUrl: 'https://flutter.dev',
+ );
+
+ verify(mockWebViewPlatformController.loadHtmlString(
+ '<p>This is a test paragraph.</p>',
+ baseUrl: 'https://flutter.dev',
+ ));
+ });
+
+ testWidgets('Load HTML string with empty string',
+ (WidgetTester tester) async {
+ WebViewController? controller;
+ await tester.pumpWidget(
+ WebView(
+ onWebViewCreated: (WebViewController webViewController) {
+ controller = webViewController;
+ },
+ ),
+ );
+
+ expect(controller, isNotNull);
+
+ expect(() => controller!.loadHtmlString(''), throwsAssertionError);
+ });
+
testWidgets('Load url', (WidgetTester tester) async {
WebViewController? controller;
await tester.pumpWidget(
diff --git a/packages/webview_flutter/webview_flutter/test/webview_flutter_test.mocks.dart b/packages/webview_flutter/webview_flutter/test/webview_flutter_test.mocks.dart
index b9d43cc..8857f60 100644
--- a/packages/webview_flutter/webview_flutter/test/webview_flutter_test.mocks.dart
+++ b/packages/webview_flutter/webview_flutter/test/webview_flutter_test.mocks.dart
@@ -1,7 +1,3 @@
-// Copyright 2013 The Flutter Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
// Mocks generated by Mockito 5.0.16 from annotations
// in webview_flutter/test/webview_flutter_test.dart.
// Do not manually edit this file.
@@ -82,11 +78,27 @@
}
@override
+ _i9.Future<void> loadFile(String? absoluteFilePath) =>
+ (super.noSuchMethod(Invocation.method(#loadFile, [absoluteFilePath]),
+ returnValue: Future<void>.value(),
+ returnValueForMissingStub: Future<void>.value()) as _i9.Future<void>);
+ @override
+ _i9.Future<void> loadHtmlString(String? html, {String? baseUrl}) =>
+ (super.noSuchMethod(
+ Invocation.method(#loadHtmlString, [html], {#baseUrl: baseUrl}),
+ returnValue: Future<void>.value(),
+ returnValueForMissingStub: Future<void>.value()) as _i9.Future<void>);
+ @override
_i9.Future<void> loadUrl(String? url, Map<String, String>? headers) =>
(super.noSuchMethod(Invocation.method(#loadUrl, [url, headers]),
returnValue: Future<void>.value(),
returnValueForMissingStub: Future<void>.value()) as _i9.Future<void>);
@override
+ _i9.Future<void> loadRequest(_i4.WebViewRequest? request) =>
+ (super.noSuchMethod(Invocation.method(#loadRequest, [request]),
+ returnValue: Future<void>.value(),
+ returnValueForMissingStub: Future<void>.value()) as _i9.Future<void>);
+ @override
_i9.Future<void> updateSettings(_i4.WebSettings? setting) =>
(super.noSuchMethod(Invocation.method(#updateSettings, [setting]),
returnValue: Future<void>.value(),