Skip to content

Commit 06a7c3d

Browse files
mvanbeusekomamantoux
authored andcommitted
[webview_flutter] Expose loadFile and loadHtmlString through app facing package. (flutter#4558)
1 parent 6a5f10b commit 06a7c3d

File tree

7 files changed

+201
-7
lines changed

7 files changed

+201
-7
lines changed

packages/webview_flutter/webview_flutter/CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
## NEXT
1+
## 2.4.0
22

3+
* Adds support for the `loadFile` and `loadHtmlString` methods.
34
* Updates example app Android compileSdkVersion to 31.
45
* Integration test fixes.
56
* Updates code for new analysis options.

packages/webview_flutter/webview_flutter/example/lib/main.dart

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import 'dart:convert';
99
import 'dart:io';
1010

1111
import 'package:flutter/material.dart';
12+
import 'package:path_provider/path_provider.dart';
1213
import 'package:webview_flutter/webview_flutter.dart';
1314

1415
void main() => runApp(MaterialApp(home: WebViewExample()));
@@ -28,6 +29,25 @@ The navigation delegate is set to block navigation to the youtube website.
2829
</html>
2930
''';
3031

32+
const String kLocalExamplePage = '''
33+
<!DOCTYPE html>
34+
<html lang="en">
35+
<head>
36+
<title>Load file or HTML string example</title>
37+
</head>
38+
<body>
39+
40+
<h1>Local demo page</h1>
41+
<p>
42+
This is an example page used to demonstrate how to load a local file or HTML
43+
string using the <a href="https://pub.dev/packages/webview_flutter">Flutter
44+
webview</a> plugin.
45+
</p>
46+
47+
</body>
48+
</html>
49+
''';
50+
3151
class WebViewExample extends StatefulWidget {
3252
@override
3353
_WebViewExampleState createState() => _WebViewExampleState();
@@ -133,6 +153,8 @@ enum MenuOptions {
133153
listCache,
134154
clearCache,
135155
navigationDelegate,
156+
loadLocalFile,
157+
loadHtmlString,
136158
}
137159

138160
class SampleMenu extends StatelessWidget {
@@ -171,6 +193,12 @@ class SampleMenu extends StatelessWidget {
171193
case MenuOptions.navigationDelegate:
172194
_onNavigationDelegateExample(controller.data!, context);
173195
break;
196+
case MenuOptions.loadLocalFile:
197+
_onLoadLocalFileExample(controller.data!, context);
198+
break;
199+
case MenuOptions.loadHtmlString:
200+
_onLoadHtmlStringExample(controller.data!, context);
201+
break;
174202
}
175203
},
176204
itemBuilder: (BuildContext context) => <PopupMenuItem<MenuOptions>>[
@@ -203,6 +231,14 @@ class SampleMenu extends StatelessWidget {
203231
value: MenuOptions.navigationDelegate,
204232
child: Text('Navigation Delegate example'),
205233
),
234+
const PopupMenuItem<MenuOptions>(
235+
value: MenuOptions.loadHtmlString,
236+
child: Text('Load HTML string'),
237+
),
238+
const PopupMenuItem<MenuOptions>(
239+
value: MenuOptions.loadLocalFile,
240+
child: Text('Load local file'),
241+
),
206242
],
207243
);
208244
},
@@ -279,6 +315,18 @@ class SampleMenu extends StatelessWidget {
279315
await controller.loadUrl('data:text/html;base64,$contentBase64');
280316
}
281317

318+
Future<void> _onLoadLocalFileExample(
319+
WebViewController controller, BuildContext context) async {
320+
final String pathToIndex = await _prepareLocalFile();
321+
322+
await controller.loadFile(pathToIndex);
323+
}
324+
325+
Future<void> _onLoadHtmlStringExample(
326+
WebViewController controller, BuildContext context) async {
327+
await controller.loadHtmlString(kLocalExamplePage);
328+
}
329+
282330
Widget _getCookieList(String cookies) {
283331
if (cookies == null || cookies == '""') {
284332
return Container();
@@ -292,6 +340,17 @@ class SampleMenu extends StatelessWidget {
292340
children: cookieWidgets.toList(),
293341
);
294342
}
343+
344+
static Future<String> _prepareLocalFile() async {
345+
final String tmpDir = (await getTemporaryDirectory()).path;
346+
final File indexFile = File(
347+
<String>{tmpDir, 'www', 'index.html'}.join(Platform.pathSeparator));
348+
349+
await indexFile.create(recursive: true);
350+
await indexFile.writeAsString(kLocalExamplePage);
351+
352+
return indexFile.path;
353+
}
295354
}
296355

297356
class NavigationControls extends StatelessWidget {

packages/webview_flutter/webview_flutter/example/pubspec.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ environment:
99
dependencies:
1010
flutter:
1111
sdk: flutter
12+
path_provider: ^2.0.6
1213
webview_flutter:
1314
# When depending on this package from a real application you should use:
1415
# webview_flutter: ^x.y.z

packages/webview_flutter/webview_flutter/lib/src/webview.dart

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -496,6 +496,35 @@ class WebViewController {
496496

497497
WebView _widget;
498498

499+
/// Loads the file located at the specified [absoluteFilePath].
500+
///
501+
/// The [absoluteFilePath] parameter should contain the absolute path to the
502+
/// file as it is stored on the device. For example:
503+
/// `/Users/username/Documents/www/index.html`.
504+
///
505+
/// Throws an ArgumentError if the [absoluteFilePath] does not exist.
506+
Future<void> loadFile(
507+
String absoluteFilePath,
508+
) {
509+
assert(absoluteFilePath.isNotEmpty);
510+
return _webViewPlatformController.loadFile(absoluteFilePath);
511+
}
512+
513+
/// Loads the supplied HTML string.
514+
///
515+
/// The [baseUrl] parameter is used when resolving relative URLs within the
516+
/// HTML string.
517+
Future<void> loadHtmlString(
518+
String html, {
519+
String? baseUrl,
520+
}) {
521+
assert(html.isNotEmpty);
522+
return _webViewPlatformController.loadHtmlString(
523+
html,
524+
baseUrl: baseUrl,
525+
);
526+
}
527+
499528
/// Loads the specified URL.
500529
///
501530
/// If `headers` is not null and the URL is an HTTP URL, the key value paris in `headers` will

packages/webview_flutter/webview_flutter/pubspec.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ name: webview_flutter
22
description: A Flutter plugin that provides a WebView widget on Android and iOS.
33
repository: https://github.com/flutter/plugins/tree/master/packages/webview_flutter/webview_flutter
44
issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+webview%22
5-
version: 2.3.1
5+
version: 2.4.0
66

77
environment:
88
sdk: ">=2.14.0 <3.0.0"
@@ -19,7 +19,7 @@ flutter:
1919
dependencies:
2020
flutter:
2121
sdk: flutter
22-
webview_flutter_android: ^2.3.1
22+
webview_flutter_android: ^2.4.0
2323
webview_flutter_platform_interface: ^1.5.2
2424
webview_flutter_wkwebview: ^2.4.0
2525

packages/webview_flutter/webview_flutter/test/webview_flutter_test.dart

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,98 @@ void main() {
8888
expect(disabledparams.webSettings!.javascriptMode, JavascriptMode.disabled);
8989
});
9090

91+
testWidgets('Load file', (WidgetTester tester) async {
92+
WebViewController? controller;
93+
await tester.pumpWidget(
94+
WebView(
95+
onWebViewCreated: (WebViewController webViewController) {
96+
controller = webViewController;
97+
},
98+
),
99+
);
100+
101+
expect(controller, isNotNull);
102+
103+
await controller!.loadFile('/test/path/index.html');
104+
105+
verify(mockWebViewPlatformController.loadFile(
106+
'/test/path/index.html',
107+
));
108+
});
109+
110+
testWidgets('Load file with empty path', (WidgetTester tester) async {
111+
WebViewController? controller;
112+
await tester.pumpWidget(
113+
WebView(
114+
onWebViewCreated: (WebViewController webViewController) {
115+
controller = webViewController;
116+
},
117+
),
118+
);
119+
120+
expect(controller, isNotNull);
121+
122+
expect(() => controller!.loadFile(''), throwsAssertionError);
123+
});
124+
125+
testWidgets('Load HTML string without base URL', (WidgetTester tester) async {
126+
WebViewController? controller;
127+
await tester.pumpWidget(
128+
WebView(
129+
onWebViewCreated: (WebViewController webViewController) {
130+
controller = webViewController;
131+
},
132+
),
133+
);
134+
135+
expect(controller, isNotNull);
136+
137+
await controller!.loadHtmlString('<p>This is a test paragraph.</p>');
138+
139+
verify(mockWebViewPlatformController.loadHtmlString(
140+
'<p>This is a test paragraph.</p>',
141+
));
142+
});
143+
144+
testWidgets('Load HTML string with base URL', (WidgetTester tester) async {
145+
WebViewController? controller;
146+
await tester.pumpWidget(
147+
WebView(
148+
onWebViewCreated: (WebViewController webViewController) {
149+
controller = webViewController;
150+
},
151+
),
152+
);
153+
154+
expect(controller, isNotNull);
155+
156+
await controller!.loadHtmlString(
157+
'<p>This is a test paragraph.</p>',
158+
baseUrl: 'https://flutter.dev',
159+
);
160+
161+
verify(mockWebViewPlatformController.loadHtmlString(
162+
'<p>This is a test paragraph.</p>',
163+
baseUrl: 'https://flutter.dev',
164+
));
165+
});
166+
167+
testWidgets('Load HTML string with empty string',
168+
(WidgetTester tester) async {
169+
WebViewController? controller;
170+
await tester.pumpWidget(
171+
WebView(
172+
onWebViewCreated: (WebViewController webViewController) {
173+
controller = webViewController;
174+
},
175+
),
176+
);
177+
178+
expect(controller, isNotNull);
179+
180+
expect(() => controller!.loadHtmlString(''), throwsAssertionError);
181+
});
182+
91183
testWidgets('Load url', (WidgetTester tester) async {
92184
WebViewController? controller;
93185
await tester.pumpWidget(

packages/webview_flutter/webview_flutter/test/webview_flutter_test.mocks.dart

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,3 @@
1-
// Copyright 2013 The Flutter Authors. All rights reserved.
2-
// Use of this source code is governed by a BSD-style license that can be
3-
// found in the LICENSE file.
4-
51
// Mocks generated by Mockito 5.0.16 from annotations
62
// in webview_flutter/test/webview_flutter_test.dart.
73
// Do not manually edit this file.
@@ -81,12 +77,28 @@ class MockWebViewPlatformController extends _i1.Mock
8177
_i1.throwOnMissingStub(this);
8278
}
8379

80+
@override
81+
_i9.Future<void> loadFile(String? absoluteFilePath) =>
82+
(super.noSuchMethod(Invocation.method(#loadFile, [absoluteFilePath]),
83+
returnValue: Future<void>.value(),
84+
returnValueForMissingStub: Future<void>.value()) as _i9.Future<void>);
85+
@override
86+
_i9.Future<void> loadHtmlString(String? html, {String? baseUrl}) =>
87+
(super.noSuchMethod(
88+
Invocation.method(#loadHtmlString, [html], {#baseUrl: baseUrl}),
89+
returnValue: Future<void>.value(),
90+
returnValueForMissingStub: Future<void>.value()) as _i9.Future<void>);
8491
@override
8592
_i9.Future<void> loadUrl(String? url, Map<String, String>? headers) =>
8693
(super.noSuchMethod(Invocation.method(#loadUrl, [url, headers]),
8794
returnValue: Future<void>.value(),
8895
returnValueForMissingStub: Future<void>.value()) as _i9.Future<void>);
8996
@override
97+
_i9.Future<void> loadRequest(_i4.WebViewRequest? request) =>
98+
(super.noSuchMethod(Invocation.method(#loadRequest, [request]),
99+
returnValue: Future<void>.value(),
100+
returnValueForMissingStub: Future<void>.value()) as _i9.Future<void>);
101+
@override
90102
_i9.Future<void> updateSettings(_i4.WebSettings? setting) =>
91103
(super.noSuchMethod(Invocation.method(#updateSettings, [setting]),
92104
returnValue: Future<void>.value(),

0 commit comments

Comments
 (0)