[webview_flutter] WKWebView implementation of loadFlutterAsset method. (#4582)
diff --git a/packages/webview_flutter/webview_flutter_wkwebview/CHANGELOG.md b/packages/webview_flutter/webview_flutter_wkwebview/CHANGELOG.md
index c1d2712..0aaf4bc 100644
--- a/packages/webview_flutter/webview_flutter_wkwebview/CHANGELOG.md
+++ b/packages/webview_flutter/webview_flutter_wkwebview/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 2.7.0
+
+* Adds implementation of the `loadFlutterAsset` method from the platform interface.
+
## 2.6.0
* Implements new cookie manager for setting cookies and providing initial cookies.
diff --git a/packages/webview_flutter/webview_flutter_wkwebview/example/assets/www/index.html b/packages/webview_flutter/webview_flutter_wkwebview/example/assets/www/index.html
new file mode 100644
index 0000000..9895dd3
--- /dev/null
+++ b/packages/webview_flutter/webview_flutter_wkwebview/example/assets/www/index.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<!-- 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. -->
+<html lang="en">
+<head>
+<title>Load file or HTML string example</title>
+<link rel="stylesheet" href="styles/style.css" />
+</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>
\ No newline at end of file
diff --git a/packages/webview_flutter/webview_flutter_wkwebview/example/assets/www/styles/style.css b/packages/webview_flutter/webview_flutter_wkwebview/example/assets/www/styles/style.css
new file mode 100644
index 0000000..c2140b8
--- /dev/null
+++ b/packages/webview_flutter/webview_flutter_wkwebview/example/assets/www/styles/style.css
@@ -0,0 +1,3 @@
+h1 {
+ color: blue;
+}
\ No newline at end of file
diff --git a/packages/webview_flutter/webview_flutter_wkwebview/example/ios/RunnerTests/FLTWebViewTests.m b/packages/webview_flutter/webview_flutter_wkwebview/example/ios/RunnerTests/FLTWebViewTests.m
index 6c7c6bf..976b9c4 100644
--- a/packages/webview_flutter/webview_flutter_wkwebview/example/ios/RunnerTests/FLTWebViewTests.m
+++ b/packages/webview_flutter/webview_flutter_wkwebview/example/ios/RunnerTests/FLTWebViewTests.m
@@ -164,7 +164,120 @@
OCMReject([mockWebView loadFileURL:[OCMArg any] allowingReadAccessToURL:[OCMArg any]]);
}
-- (void)testLoadFileSucceedsWithBaseUrl {
+- (void)testLoadFlutterAssetSucceeds {
+ NSBundle *mockBundle = OCMPartialMock([NSBundle mainBundle]);
+ NSString *filePath = [FlutterDartProject lookupKeyForAsset:@"assets/file.html"];
+ NSURL *url = [NSURL URLWithString:[@"file:///" stringByAppendingString:filePath]];
+ [OCMStub([mockBundle URLForResource:[filePath stringByDeletingPathExtension]
+ withExtension:@"html"]) andReturn:(url)];
+
+ XCTestExpectation *resultExpectation =
+ [self expectationWithDescription:@"Should return successful result over the method channel."];
+ FLTWebViewController *controller =
+ [[FLTWebViewController alloc] initWithFrame:CGRectMake(0, 0, 300, 400)
+ viewIdentifier:1
+ arguments:nil
+ binaryMessenger:self.mockBinaryMessenger];
+ FLTWKWebView *mockWebView = OCMClassMock(FLTWKWebView.class);
+ controller.webView = mockWebView;
+ [controller onMethodCall:[FlutterMethodCall methodCallWithMethodName:@"loadFlutterAsset"
+ arguments:@"assets/file.html"]
+ result:^(id _Nullable result) {
+ XCTAssertNil(result);
+ [resultExpectation fulfill];
+ }];
+
+ [self waitForExpectations:@[ resultExpectation ] timeout:1.0];
+ OCMVerify([mockWebView loadFileURL:url
+ allowingReadAccessToURL:[url URLByDeletingLastPathComponent]]);
+}
+
+- (void)testLoadFlutterAssetFailsWithInvalidKey {
+ NSArray *resultExpectations = @[
+ [self expectationWithDescription:@"Should return failed result when argument is nil."],
+ [self expectationWithDescription:
+ @"Should return failed result when argument is not of type NSString*."],
+ [self expectationWithDescription:
+ @"Should return failed result when argument is an empty string."],
+ ];
+
+ FLTWebViewController *controller =
+ [[FLTWebViewController alloc] initWithFrame:CGRectMake(0, 0, 300, 400)
+ viewIdentifier:1
+ arguments:nil
+ binaryMessenger:self.mockBinaryMessenger];
+ FLTWKWebView *mockWebView = OCMClassMock(FLTWKWebView.class);
+ controller.webView = mockWebView;
+ [controller onMethodCall:[FlutterMethodCall methodCallWithMethodName:@"loadFlutterAsset"
+ arguments:nil]
+ result:^(id _Nullable result) {
+ FlutterError *expected =
+ [FlutterError errorWithCode:@"loadFlutterAsset_invalidKey"
+ message:@"Supplied asset key is not valid."
+ details:@"Argument is nil."];
+ [FLTWebViewTests assertFlutterError:result withExpected:expected];
+ [resultExpectations[0] fulfill];
+ }];
+ [controller onMethodCall:[FlutterMethodCall methodCallWithMethodName:@"loadFlutterAsset"
+ arguments:@(10)]
+ result:^(id _Nullable result) {
+ FlutterError *expected =
+ [FlutterError errorWithCode:@"loadFlutterAsset_invalidKey"
+ message:@"Supplied asset key is not valid."
+ details:@"Argument is not of type NSString."];
+ [FLTWebViewTests assertFlutterError:result withExpected:expected];
+ [resultExpectations[1] fulfill];
+ }];
+ [controller onMethodCall:[FlutterMethodCall methodCallWithMethodName:@"loadFlutterAsset"
+ arguments:@""]
+ result:^(id _Nullable result) {
+ FlutterError *expected =
+ [FlutterError errorWithCode:@"loadFlutterAsset_invalidKey"
+ message:@"Supplied asset key is not valid."
+ details:@"Argument contains an empty string."];
+ [FLTWebViewTests assertFlutterError:result withExpected:expected];
+ [resultExpectations[2] fulfill];
+ }];
+
+ [self waitForExpectations:resultExpectations timeout:1.0];
+ OCMReject([mockWebView loadFileURL:[OCMArg any] allowingReadAccessToURL:[OCMArg any]]);
+}
+
+- (void)testLoadFlutterAssetFailsWithParsingError {
+ NSBundle *mockBundle = OCMPartialMock([NSBundle mainBundle]);
+ NSString *filePath = [FlutterDartProject lookupKeyForAsset:@"assets/file.html"];
+ [OCMStub([mockBundle URLForResource:[filePath stringByDeletingPathExtension]
+ withExtension:@"html"]) andReturn:(nil)];
+
+ XCTestExpectation *resultExpectation =
+ [self expectationWithDescription:@"Should return failed result over the method channel."];
+ FLTWebViewController *controller =
+ [[FLTWebViewController alloc] initWithFrame:CGRectMake(0, 0, 300, 400)
+ viewIdentifier:1
+ arguments:nil
+ binaryMessenger:self.mockBinaryMessenger];
+ FLTWKWebView *mockWebView = OCMClassMock(FLTWKWebView.class);
+ controller.webView = mockWebView;
+ [controller
+ onMethodCall:[FlutterMethodCall methodCallWithMethodName:@"loadFlutterAsset"
+ arguments:@"assets/file.html"]
+ result:^(id _Nullable result) {
+ FlutterError *expected = [FlutterError
+ errorWithCode:@"loadFlutterAsset_invalidKey"
+ message:@"Failed parsing file path for supplied key."
+ details:[NSString
+ stringWithFormat:
+ @"Failed to convert path '%@' into NSURL for key '%@'.",
+ filePath, @"assets/file.html"]];
+ [FLTWebViewTests assertFlutterError:result withExpected:expected];
+ [resultExpectation fulfill];
+ }];
+
+ [self waitForExpectations:@[ resultExpectation ] timeout:1.0];
+ OCMReject([mockWebView loadFileURL:[OCMArg any] allowingReadAccessToURL:[OCMArg any]]);
+}
+
+- (void)testLoadHtmlStringSucceedsWithBaseUrl {
NSURL *baseUrl = [NSURL URLWithString:@"https://flutter.dev"];
XCTestExpectation *resultExpectation =
[self expectationWithDescription:@"Should return successful result over the method channel."];
@@ -189,7 +302,7 @@
OCMVerify([mockWebView loadHTMLString:@"some HTML string" baseURL:baseUrl]);
}
-- (void)testLoadFileSucceedsWithoutBaseUrl {
+- (void)testLoadHtmlStringSucceedsWithoutBaseUrl {
XCTestExpectation *resultExpectation =
[self expectationWithDescription:@"Should return successful result over the method channel."];
FLTWebViewController *controller =
diff --git a/packages/webview_flutter/webview_flutter_wkwebview/example/lib/main.dart b/packages/webview_flutter/webview_flutter_wkwebview/example/lib/main.dart
index ce7548a..d4e0ec4 100644
--- a/packages/webview_flutter/webview_flutter_wkwebview/example/lib/main.dart
+++ b/packages/webview_flutter/webview_flutter_wkwebview/example/lib/main.dart
@@ -171,6 +171,7 @@
listCache,
clearCache,
navigationDelegate,
+ loadFlutterAsset,
loadLocalFile,
loadHtmlString,
doPostRequest,
@@ -214,6 +215,9 @@
case _MenuOptions.navigationDelegate:
_onNavigationDelegateExample(controller.data!, context);
break;
+ case _MenuOptions.loadFlutterAsset:
+ _onLoadFlutterAssetExample(controller.data!, context);
+ break;
case _MenuOptions.loadLocalFile:
_onLoadLocalFileExample(controller.data!, context);
break;
@@ -262,6 +266,10 @@
child: Text('Navigation Delegate example'),
),
const PopupMenuItem<_MenuOptions>(
+ value: _MenuOptions.loadFlutterAsset,
+ child: Text('Load Flutter Asset'),
+ ),
+ const PopupMenuItem<_MenuOptions>(
value: _MenuOptions.loadHtmlString,
child: Text('Load HTML string'),
),
@@ -355,6 +363,11 @@
await controller.loadUrl('data:text/html;base64,$contentBase64');
}
+ Future<void> _onLoadFlutterAssetExample(
+ WebViewController controller, BuildContext context) async {
+ await controller.loadFlutterAsset('assets/www/index.html');
+ }
+
Future<void> _onLoadLocalFileExample(
WebViewController controller, BuildContext context) async {
final String pathToIndex = await _prepareLocalFile();
diff --git a/packages/webview_flutter/webview_flutter_wkwebview/example/lib/web_view.dart b/packages/webview_flutter/webview_flutter_wkwebview/example/lib/web_view.dart
index 1efd031..4d479f9 100644
--- a/packages/webview_flutter/webview_flutter_wkwebview/example/lib/web_view.dart
+++ b/packages/webview_flutter/webview_flutter_wkwebview/example/lib/web_view.dart
@@ -319,6 +319,14 @@
WebView _widget;
+ /// Loads the Flutter asset specified in the pubspec.yaml file.
+ ///
+ /// Throws an ArgumentError if [key] is not part of the specified assets
+ /// in the pubspec.yaml file.
+ Future<void> loadFlutterAsset(String key) {
+ return _webViewPlatformController.loadFlutterAsset(key);
+ }
+
/// Loads the file located on the specified [absoluteFilePath].
///
/// The [absoluteFilePath] parameter should contain the absolute path to the
diff --git a/packages/webview_flutter/webview_flutter_wkwebview/example/pubspec.yaml b/packages/webview_flutter/webview_flutter_wkwebview/example/pubspec.yaml
index 2070b11..b8c2464 100644
--- a/packages/webview_flutter/webview_flutter_wkwebview/example/pubspec.yaml
+++ b/packages/webview_flutter/webview_flutter_wkwebview/example/pubspec.yaml
@@ -34,3 +34,5 @@
assets:
- assets/sample_audio.ogg
- assets/sample_video.mp4
+ - assets/www/index.html
+ - assets/www/styles/style.css
diff --git a/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FlutterWebView.m b/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FlutterWebView.m
index ea45a8b..3f3b9d9 100644
--- a/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FlutterWebView.m
+++ b/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FlutterWebView.m
@@ -163,6 +163,8 @@
[self onUpdateSettings:call result:result];
} else if ([[call method] isEqualToString:@"loadFile"]) {
[self onLoadFile:call result:result];
+ } else if ([[call method] isEqualToString:@"loadFlutterAsset"]) {
+ [self onLoadFlutterAsset:call result:result];
} else if ([[call method] isEqualToString:@"loadHtmlString"]) {
[self onLoadHtmlString:call result:result];
} else if ([[call method] isEqualToString:@"loadUrl"]) {
@@ -244,6 +246,34 @@
result(nil);
}
+- (void)onLoadFlutterAsset:(FlutterMethodCall*)call result:(FlutterResult)result {
+ NSString* error = nil;
+ if (![FLTWebViewController isValidStringArgument:[call arguments] withErrorMessage:&error]) {
+ result([FlutterError errorWithCode:@"loadFlutterAsset_invalidKey"
+ message:@"Supplied asset key is not valid."
+ details:error]);
+ return;
+ }
+
+ NSString* assetKey = [call arguments];
+ NSString* assetFilePath = [FlutterDartProject lookupKeyForAsset:assetKey];
+ NSURL* url = [[NSBundle mainBundle] URLForResource:[assetFilePath stringByDeletingPathExtension]
+ withExtension:assetFilePath.pathExtension];
+
+ if (!url) {
+ result([FlutterError
+ errorWithCode:@"loadFlutterAsset_invalidKey"
+ message:@"Failed parsing file path for supplied key."
+ details:[NSString
+ stringWithFormat:@"Failed to convert path '%@' into NSURL for key '%@'.",
+ assetFilePath, assetKey]]);
+ return;
+ }
+
+ [_webView loadFileURL:url allowingReadAccessToURL:[url URLByDeletingLastPathComponent]];
+ result(nil);
+}
+
- (void)onLoadHtmlString:(FlutterMethodCall*)call result:(FlutterResult)result {
NSDictionary* arguments = [call arguments];
if (![arguments isKindOfClass:NSDictionary.class]) {
diff --git a/packages/webview_flutter/webview_flutter_wkwebview/pubspec.yaml b/packages/webview_flutter/webview_flutter_wkwebview/pubspec.yaml
index fc274b4..08e98b1 100644
--- a/packages/webview_flutter/webview_flutter_wkwebview/pubspec.yaml
+++ b/packages/webview_flutter/webview_flutter_wkwebview/pubspec.yaml
@@ -2,7 +2,7 @@
description: A Flutter plugin that provides a WebView widget based on Apple's WKWebView control.
repository: https://github.com/flutter/plugins/tree/master/packages/webview_flutter/webview_flutter_wkwebview
issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+webview%22
-version: 2.6.0
+version: 2.7.0
environment:
sdk: ">=2.14.0 <3.0.0"