Skip to content

Commit

Permalink
[webview_flutter] Expose loadFile and loadHtmlString through app faci…
Browse files Browse the repository at this point in the history
…ng package. (flutter#4558)
  • Loading branch information
mvanbeusekom authored and amantoux committed Dec 11, 2021
1 parent 6a5f10b commit 06a7c3d
Show file tree
Hide file tree
Showing 7 changed files with 201 additions and 7 deletions.
3 changes: 2 additions & 1 deletion packages/webview_flutter/webview_flutter/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -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.
Expand Down
59 changes: 59 additions & 0 deletions packages/webview_flutter/webview_flutter/example/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import 'dart:convert';
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()));
Expand All @@ -28,6 +29,25 @@ The navigation delegate is set to block navigation to the youtube website.
</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();
Expand Down Expand Up @@ -133,6 +153,8 @@ enum MenuOptions {
listCache,
clearCache,
navigationDelegate,
loadLocalFile,
loadHtmlString,
}

class SampleMenu extends StatelessWidget {
Expand Down Expand Up @@ -171,6 +193,12 @@ class SampleMenu extends StatelessWidget {
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>>[
Expand Down Expand Up @@ -203,6 +231,14 @@ class SampleMenu extends StatelessWidget {
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'),
),
],
);
},
Expand Down Expand Up @@ -279,6 +315,18 @@ class SampleMenu extends StatelessWidget {
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();
Expand All @@ -292,6 +340,17 @@ class SampleMenu extends StatelessWidget {
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 {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ environment:
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
Expand Down
29 changes: 29 additions & 0 deletions packages/webview_flutter/webview_flutter/lib/src/webview.dart
Original file line number Diff line number Diff line change
Expand Up @@ -496,6 +496,35 @@ class WebViewController {

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
Expand Down
4 changes: 2 additions & 2 deletions packages/webview_flutter/webview_flutter/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ name: webview_flutter
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"
Expand All @@ -19,7 +19,7 @@ flutter:
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

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,98 @@ void main() {
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(
Expand Down
Original file line number Diff line number Diff line change
@@ -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.
Expand Down Expand Up @@ -81,12 +77,28 @@ class MockWebViewPlatformController extends _i1.Mock
_i1.throwOnMissingStub(this);
}

@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(),
Expand Down

0 comments on commit 06a7c3d

Please sign in to comment.