From c1dc83ae33a76a4dfe19ba159b471c8b1c72671e Mon Sep 17 00:00:00 2001 From: Maurits van Beusekom Date: Fri, 5 Nov 2021 13:03:40 +0100 Subject: [PATCH 1/5] Implementation of loadFile for WKWebView. Adds native implementation for the `loadFile` method channel call to the webview_flutter_wkwebview package. --- .../example/ios/RunnerTests/FLTWebViewTests.m | 98 +++++++++++++++++++ .../example/lib/main.dart | 47 +++++++++ .../example/lib/web_view.dart | 14 +++ .../example/pubspec.yaml | 4 + .../ios/Classes/FlutterWebView.m | 41 ++++++++ 5 files changed, 204 insertions(+) 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 9d127c2c4aaa..65bf1ee7dc43 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 @@ -88,6 +88,104 @@ - (void)testContentInsetsSumAlwaysZeroAfterSetFrame { } } +- (void)testLoadFileSucceeds { + NSString *testFilePath = @"/assets/file.html"; + NSURL *url = [NSURL fileURLWithPath:testFilePath isDirectory:NO]; + 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:@"loadFile" + arguments:testFilePath] + result:^(id _Nullable result) { + XCTAssertNil(result); + [resultExpectation fulfill]; + }]; + + [self waitForExpectations:@[ resultExpectation ] timeout:30.0]; + OCMVerify([mockWebView loadFileURL:url + allowingReadAccessToURL:[url URLByDeletingLastPathComponent]]); +} + +- (void)testLoadFileFailsWithNilPath { + 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:@"loadFile" arguments:nil] + result:^(id _Nullable result) { + XCTAssertTrue([result class] == [FlutterError class]); + FlutterError *errorResult = result; + XCTAssertEqualObjects(errorResult.code, @"loadFile_failed"); + XCTAssertEqualObjects(errorResult.message, @"Failed parsing file path."); + XCTAssertEqualObjects(errorResult.details, @"Argument is nil."); + [resultExpectation fulfill]; + }]; + + [self waitForExpectations:@[ resultExpectation ] timeout:1.0]; + OCMReject([mockWebView loadFileURL:[OCMArg any] allowingReadAccessToURL:[OCMArg any]]); +} + +- (void)testLoadFileFailsWithNonStringPath { + 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:@"loadFile" arguments:@(10)] + result:^(id _Nullable result) { + XCTAssertTrue([result class] == [FlutterError class]); + FlutterError *errorResult = result; + XCTAssertEqualObjects(errorResult.code, @"loadFile_failed"); + XCTAssertEqualObjects(errorResult.message, @"Failed parsing file path."); + XCTAssertEqualObjects(errorResult.details, @"Argument is not of type NSString."); + [resultExpectation fulfill]; + }]; + + [self waitForExpectations:@[ resultExpectation ] timeout:1.0]; + OCMReject([mockWebView loadFileURL:[OCMArg any] allowingReadAccessToURL:[OCMArg any]]); +} + +- (void)testLoadFileFailsWithEmptyPath { + 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:@"loadFile" arguments:@""] + result:^(id _Nullable result) { + XCTAssertTrue([result class] == [FlutterError class]); + FlutterError *errorResult = result; + XCTAssertEqualObjects(errorResult.code, @"loadFile_failed"); + XCTAssertEqualObjects(errorResult.message, @"Failed parsing file path."); + XCTAssertEqualObjects(errorResult.details, @"Argument contains an empty string."); + [resultExpectation fulfill]; + }]; + + [self waitForExpectations:@[ resultExpectation ] timeout:1.0]; + OCMReject([mockWebView loadFileURL:[OCMArg any] allowingReadAccessToURL:[OCMArg any]]); +} + - (void)testRunJavascriptFailsForNullString { // Setup 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 21240f63ec1a..7d85f6441eac 100644 --- a/packages/webview_flutter/webview_flutter_wkwebview/example/lib/main.dart +++ b/packages/webview_flutter/webview_flutter_wkwebview/example/lib/main.dart @@ -6,8 +6,11 @@ import 'dart:async'; import 'dart:convert'; +import 'dart:io'; + import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; +import 'package:path_provider/path_provider.dart'; import 'package:webview_flutter_platform_interface/webview_flutter_platform_interface.dart'; import 'navigation_decision.dart'; @@ -33,6 +36,21 @@ The navigation delegate is set to block navigation to the youtube website. '''; +const String kLocalFileExamplePage = ''' + + + +Local demo page + + + +

Local demo page

+

This is a local page used to demonstrate how to load a local file using the Flutter webview plugin.

+ + + +'''; + class _WebViewExample extends StatefulWidget { const _WebViewExample({Key? key}) : super(key: key); @@ -120,6 +138,7 @@ enum _MenuOptions { listCache, clearCache, navigationDelegate, + loadLocalFile, } class _SampleMenu extends StatelessWidget { @@ -157,6 +176,9 @@ class _SampleMenu extends StatelessWidget { case _MenuOptions.navigationDelegate: _onNavigationDelegateExample(controller.data!, context); break; + case _MenuOptions.loadLocalFile: + _onLoadLocalFileExample(controller.data!, context); + break; } }, itemBuilder: (BuildContext context) => >[ @@ -189,6 +211,10 @@ class _SampleMenu extends StatelessWidget { value: _MenuOptions.navigationDelegate, child: Text('Navigation Delegate example'), ), + const PopupMenuItem<_MenuOptions>( + value: _MenuOptions.loadLocalFile, + child: Text('Load local file'), + ), ], ); }, @@ -259,6 +285,13 @@ class _SampleMenu extends StatelessWidget { await controller.loadUrl('data:text/html;base64,$contentBase64'); } + void _onLoadLocalFileExample( + WebViewController controller, BuildContext context) async { + String pathToIndex = await _prepareLocalFile(); + + await controller.loadFile(pathToIndex); + } + Widget _getCookieList(String cookies) { if (cookies == null || cookies == '""') { return Container(); @@ -272,6 +305,20 @@ class _SampleMenu extends StatelessWidget { children: cookieWidgets.toList(), ); } + + static Future _prepareLocalFile() async { + final String tmpDir = (await getTemporaryDirectory()).path; + File indexFile = File('$tmpDir/www/index.html'); + + if (await indexFile.exists()) { + return indexFile.path; + } + + await Directory('$tmpDir/www').create(recursive: true); + await indexFile.writeAsString(kLocalFileExamplePage); + + return indexFile.path; + } } class _NavigationControls extends StatelessWidget { 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 403db1f08ac6..671505e2ad2c 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 @@ -305,6 +305,20 @@ class WebViewController { WebView _widget; + /// Loads the file located on 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 loadFile( + String absoluteFilePath, + ) { + assert(absoluteFilePath != null || absoluteFilePath.isNotEmpty); + return _webViewPlatformController.loadFile(absoluteFilePath); + } + /// 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_wkwebview/example/pubspec.yaml b/packages/webview_flutter/webview_flutter_wkwebview/example/pubspec.yaml index 229da5e337a5..c8001c8ffde4 100644 --- a/packages/webview_flutter/webview_flutter_wkwebview/example/pubspec.yaml +++ b/packages/webview_flutter/webview_flutter_wkwebview/example/pubspec.yaml @@ -8,6 +8,9 @@ environment: dependencies: flutter: sdk: flutter + + path_provider: ^2.0.6 + webview_flutter_wkwebview: # When depending on this package from a real application you should use: # webview_flutter: ^x.y.z @@ -31,3 +34,4 @@ flutter: assets: - assets/sample_audio.ogg - assets/sample_video.mp4 + \ No newline at end of file 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 5e12f8acb2ea..3e606575542a 100644 --- a/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FlutterWebView.m +++ b/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FlutterWebView.m @@ -135,6 +135,8 @@ - (UIView*)view { - (void)onMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result { if ([[call method] isEqualToString:@"updateSettings"]) { [self onUpdateSettings:call result:result]; + } else if ([[call method] isEqualToString:@"loadFile"]) { + [self onLoadFile:call result:result]; } else if ([[call method] isEqualToString:@"loadUrl"]) { [self onLoadUrl:call result:result]; } else if ([[call method] isEqualToString:@"canGoBack"]) { @@ -185,6 +187,22 @@ - (void)onUpdateSettings:(FlutterMethodCall*)call result:(FlutterResult)result { result([FlutterError errorWithCode:@"updateSettings_failed" message:error details:nil]); } +- (void)onLoadFile:(FlutterMethodCall*)call result:(FlutterResult)result { + NSString* error = nil; + if (![FLTWebViewController isValidStringArgument:[call arguments] withErrorMessage:&error]) { + result([FlutterError errorWithCode:@"loadFile_failed" + message:@"Failed parsing file path." + details:error]); + return; + } + + NSURL* url = [NSURL fileURLWithPath:[call arguments] isDirectory:NO]; + NSURL* baseUrl = [url URLByDeletingLastPathComponent]; + + [_webView loadFileURL:url allowingReadAccessToURL:baseUrl]; + result(nil); +} + - (void)onLoadUrl:(FlutterMethodCall*)call result:(FlutterResult)result { if (![self loadRequest:[call arguments]]) { result([FlutterError @@ -517,6 +535,29 @@ - (void)updateUserAgent:(NSString*)userAgent { } } ++ (bool)isValidStringArgument:(id)argument withErrorMessage:(NSString**)errorDetails { + if (!argument) { + if (errorDetails) { + *errorDetails = @"Argument is nil."; + } + return NO; + } + if (![argument isKindOfClass:NSString.class]) { + if (errorDetails) { + *errorDetails = @"Argument is not of type NSString."; + } + return NO; + } + if (![argument length]) { + if (errorDetails) { + *errorDetails = @"Argument contains an empty string."; + } + return NO; + } + + return YES; +} + #pragma mark WKUIDelegate - (WKWebView*)webView:(WKWebView*)webView From f1343c25576e794e52d31c48fb9df86a3ceda8b8 Mon Sep 17 00:00:00 2001 From: Maurits van Beusekom Date: Mon, 8 Nov 2021 15:26:31 +0100 Subject: [PATCH 2/5] Implementation of loadHtmlString for WKWebView. Adds native implementation for the `loadHtmlString` method channel call to the webview_flutter_wkwebview package. --- .../ios/Runner.xcodeproj/project.pbxproj | 4 +- .../xcshareddata/xcschemes/Runner.xcscheme | 2 +- .../example/ios/RunnerTests/FLTWebViewTests.m | 173 ++++++++++++++---- .../example/lib/main.dart | 17 +- .../example/lib/web_view.dart | 15 ++ .../ios/Classes/FlutterWebView.m | 29 +++ 6 files changed, 201 insertions(+), 39 deletions(-) diff --git a/packages/webview_flutter/webview_flutter_wkwebview/example/ios/Runner.xcodeproj/project.pbxproj b/packages/webview_flutter/webview_flutter_wkwebview/example/ios/Runner.xcodeproj/project.pbxproj index ba0deb4781d4..c83e0d82e4ec 100644 --- a/packages/webview_flutter/webview_flutter_wkwebview/example/ios/Runner.xcodeproj/project.pbxproj +++ b/packages/webview_flutter/webview_flutter_wkwebview/example/ios/Runner.xcodeproj/project.pbxproj @@ -3,7 +3,7 @@ archiveVersion = 1; classes = { }; - objectVersion = 46; + objectVersion = 50; objects = { /* Begin PBXBuildFile section */ @@ -274,7 +274,7 @@ isa = PBXProject; attributes = { DefaultBuildSystemTypeForWorkspace = Original; - LastUpgradeCheck = 1030; + LastUpgradeCheck = 1300; ORGANIZATIONNAME = "The Flutter Authors"; TargetAttributes = { 68BDCAE823C3F7CB00D9C032 = { diff --git a/packages/webview_flutter/webview_flutter_wkwebview/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/packages/webview_flutter/webview_flutter_wkwebview/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index d7453a8ce862..cb713d767632 100644 --- a/packages/webview_flutter/webview_flutter_wkwebview/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/packages/webview_flutter/webview_flutter_wkwebview/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -1,6 +1,6 @@ -Local demo page +Load file or HTML string example

Local demo page

-

This is a local page used to demonstrate how to load a local file using the Flutter webview plugin.

+

This is an example page used to demonstrate how to load a local file or HTML string using the Flutter webview plugin.

@@ -139,6 +139,7 @@ enum _MenuOptions { clearCache, navigationDelegate, loadLocalFile, + loadHtmlString, } class _SampleMenu extends StatelessWidget { @@ -179,6 +180,9 @@ class _SampleMenu extends StatelessWidget { case _MenuOptions.loadLocalFile: _onLoadLocalFileExample(controller.data!, context); break; + case _MenuOptions.loadHtmlString: + _onLoadHtmlStringExample(controller.data!, context); + break; } }, itemBuilder: (BuildContext context) => >[ @@ -211,6 +215,10 @@ 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'), @@ -292,6 +300,11 @@ class _SampleMenu extends StatelessWidget { await controller.loadFile(pathToIndex); } + void _onLoadHtmlStringExample( + WebViewController controller, BuildContext context) async { + await controller.loadHtmlString(kLocalFileExamplePage); + } + Widget _getCookieList(String cookies) { if (cookies == null || cookies == '""') { return Container(); 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 671505e2ad2c..ca4359825a67 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,21 @@ class WebViewController { return _webViewPlatformController.loadFile(absoluteFilePath); } + /// Loads the supplied HTML string. + /// + /// The [baseUrl] parameter is used when resolving relative URLs within the + /// HTML string. + Future loadHtmlString( + String html, { + String? baseUrl, + }) { + assert(html != null || 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_wkwebview/ios/Classes/FlutterWebView.m b/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FlutterWebView.m index 3e606575542a..58fe64a41da2 100644 --- a/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FlutterWebView.m +++ b/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FlutterWebView.m @@ -137,6 +137,8 @@ - (void)onMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result { [self onUpdateSettings:call result:result]; } else if ([[call method] isEqualToString:@"loadFile"]) { [self onLoadFile:call result:result]; + } else if ([[call method] isEqualToString:@"loadHtmlString"]) { + [self onLoadHtmlString:call result:result]; } else if ([[call method] isEqualToString:@"loadUrl"]) { [self onLoadUrl:call result:result]; } else if ([[call method] isEqualToString:@"canGoBack"]) { @@ -203,6 +205,33 @@ - (void)onLoadFile:(FlutterMethodCall*)call result:(FlutterResult)result { result(nil); } +- (void)onLoadHtmlString:(FlutterMethodCall*)call result:(FlutterResult)result { + NSDictionary* arguments = [call arguments]; + if (!arguments || ![arguments isKindOfClass:NSDictionary.class]) { + result([FlutterError + errorWithCode:@"loadHtmlString_failed" + message:@"Failed parsing arguments." + details:@"Arguments should be a dictionary containing at least a 'html' element and " + @"optionally a 'baseUrl' argument. For example: `@{ @\"html\": @\"some html " + @"code\", @\"baseUrl\": @\"https://flutter.dev\" }`"]); + return; + } + + NSString* htmlString = [call arguments][@"html"]; + NSString* baseUrl = + [call arguments][@"baseUrl"] == [NSNull null] ? nil : [call arguments][@"baseUrl"]; + NSString* error = nil; + if (![FLTWebViewController isValidStringArgument:htmlString withErrorMessage:&error]) { + result([FlutterError errorWithCode:@"loadHtmlString_failed" + message:@"Failed parsing HTML string argument." + details:error]); + return; + } + + [_webView loadHTMLString:htmlString baseURL:[NSURL URLWithString:baseUrl]]; + result(nil); +} + - (void)onLoadUrl:(FlutterMethodCall*)call result:(FlutterResult)result { if (![self loadRequest:[call arguments]]) { result([FlutterError From b94583921cebef47b88fcf27d8fa649234098bee Mon Sep 17 00:00:00 2001 From: Maurits van Beusekom Date: Tue, 9 Nov 2021 09:35:13 +0100 Subject: [PATCH 3/5] Bump version number --- .../webview_flutter/webview_flutter_wkwebview/CHANGELOG.md | 4 ++++ .../webview_flutter/webview_flutter_wkwebview/pubspec.yaml | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/webview_flutter/webview_flutter_wkwebview/CHANGELOG.md b/packages/webview_flutter/webview_flutter_wkwebview/CHANGELOG.md index 4db6dbfd2864..28c9c1ed3522 100644 --- a/packages/webview_flutter/webview_flutter_wkwebview/CHANGELOG.md +++ b/packages/webview_flutter/webview_flutter_wkwebview/CHANGELOG.md @@ -1,3 +1,7 @@ +## 2.3.0 + +* Implemented new `loadFile` and `loadHtmlString` methods from the platform interface. + ## 2.2.0 * Implemented new `runJavascript` and `runJavascriptReturningResult` methods in platform interface. diff --git a/packages/webview_flutter/webview_flutter_wkwebview/pubspec.yaml b/packages/webview_flutter/webview_flutter_wkwebview/pubspec.yaml index 5176adb9749c..ec5bd271cfa5 100644 --- a/packages/webview_flutter/webview_flutter_wkwebview/pubspec.yaml +++ b/packages/webview_flutter/webview_flutter_wkwebview/pubspec.yaml @@ -2,7 +2,7 @@ name: webview_flutter_wkwebview 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.2.0 +version: 2.3.0 environment: sdk: ">=2.14.0 <3.0.0" From d5cf9f9887c9a6ef5cff22e58f4326f133d9524f Mon Sep 17 00:00:00 2001 From: Maurits van Beusekom Date: Thu, 11 Nov 2021 17:02:46 +0100 Subject: [PATCH 4/5] Apply feedback on PR --- .../example/lib/main.dart | 10 ++++----- .../example/lib/web_view.dart | 2 -- .../ios/Classes/FlutterWebView.m | 21 ++++++++++++++++++- 3 files changed, 25 insertions(+), 8 deletions(-) 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 2efdf31a24af..72168ecc8568 100644 --- a/packages/webview_flutter/webview_flutter_wkwebview/example/lib/main.dart +++ b/packages/webview_flutter/webview_flutter_wkwebview/example/lib/main.dart @@ -46,7 +46,11 @@ const String kLocalFileExamplePage = '''

Local demo page

-

This is an example page used to demonstrate how to load a local file or HTML string using the Flutter webview plugin.

+

+ This is an example page used to demonstrate how to load a local file or HTML + string using the Flutter + webview plugin. +

@@ -343,10 +347,6 @@ class _SampleMenu extends StatelessWidget { final String tmpDir = (await getTemporaryDirectory()).path; File indexFile = File('$tmpDir/www/index.html'); - if (await indexFile.exists()) { - return indexFile.path; - } - await Directory('$tmpDir/www').create(recursive: true); await indexFile.writeAsString(kLocalFileExamplePage); 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 f3a84c01ab7f..ddc475342b04 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 @@ -315,7 +315,6 @@ class WebViewController { Future loadFile( String absoluteFilePath, ) { - assert(absoluteFilePath != null || absoluteFilePath.isNotEmpty); return _webViewPlatformController.loadFile(absoluteFilePath); } @@ -327,7 +326,6 @@ class WebViewController { String html, { String? baseUrl, }) { - assert(html != null || html.isNotEmpty); return _webViewPlatformController.loadHtmlString( html, baseUrl: baseUrl, 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 390e5f368467..5ef8e847ca65 100644 --- a/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FlutterWebView.m +++ b/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FlutterWebView.m @@ -206,6 +206,17 @@ - (void)onLoadFile:(FlutterMethodCall*)call result:(FlutterResult)result { } NSURL* url = [NSURL fileURLWithPath:[call arguments] isDirectory:NO]; + + if (!url) { + NSString* errorDetails = [NSString stringWithFormat:@"Initializing NSURL with the supplied " + @"'%@' path resulted in a nil value.", + [call arguments]]; + result([FlutterError errorWithCode:@"loadFile_failed" + message:@"Failed parsing file path." + details:errorDetails]); + return; + } + NSURL* baseUrl = [url URLByDeletingLastPathComponent]; [_webView loadFileURL:url allowingReadAccessToURL:baseUrl]; @@ -214,7 +225,7 @@ - (void)onLoadFile:(FlutterMethodCall*)call result:(FlutterResult)result { - (void)onLoadHtmlString:(FlutterMethodCall*)call result:(FlutterResult)result { NSDictionary* arguments = [call arguments]; - if (!arguments || ![arguments isKindOfClass:NSDictionary.class]) { + if (![arguments isKindOfClass:NSDictionary.class]) { result([FlutterError errorWithCode:@"loadHtmlString_failed" message:@"Failed parsing arguments." @@ -603,6 +614,14 @@ - (void)updateUserAgent:(NSString*)userAgent { } } +/** + * Validates if the given `argument` is a non-null non-empty string. + * + * @param argument The argument that should be validated. + * @param errorDetails An optional NSString variable which will contain a detailed error message in + * case the supplied argument is not valid. + * @return `true` if the given `argument` is a valid non-null, non-empty string; otherwise `false`. + */ + (bool)isValidStringArgument:(id)argument withErrorMessage:(NSString**)errorDetails { if (!argument) { if (errorDetails) { From 98eb2368af9dcee3912e39116ecd43a1ad7d92a4 Mon Sep 17 00:00:00 2001 From: Maurits van Beusekom Date: Fri, 12 Nov 2021 08:53:04 +0100 Subject: [PATCH 5/5] Fix final nits --- .../webview_flutter_wkwebview/example/lib/web_view.dart | 2 ++ .../webview_flutter_wkwebview/ios/Classes/FlutterWebView.m | 6 +++--- 2 files changed, 5 insertions(+), 3 deletions(-) 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 ddc475342b04..ab4b77336765 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 @@ -315,6 +315,7 @@ class WebViewController { Future loadFile( String absoluteFilePath, ) { + assert(absoluteFilePath.isNotEmpty); return _webViewPlatformController.loadFile(absoluteFilePath); } @@ -326,6 +327,7 @@ class WebViewController { String html, { String? baseUrl, }) { + assert(html.isNotEmpty); return _webViewPlatformController.loadHtmlString( html, baseUrl: baseUrl, 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 5ef8e847ca65..351d1ae58760 100644 --- a/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FlutterWebView.m +++ b/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FlutterWebView.m @@ -615,14 +615,14 @@ - (void)updateUserAgent:(NSString*)userAgent { } /** - * Validates if the given `argument` is a non-null non-empty string. + * Validates if the given `argument` is a non-null, non-empty string. * * @param argument The argument that should be validated. * @param errorDetails An optional NSString variable which will contain a detailed error message in * case the supplied argument is not valid. - * @return `true` if the given `argument` is a valid non-null, non-empty string; otherwise `false`. + * @return `YES` if the given `argument` is a valid non-null, non-empty string; otherwise `NO`. */ -+ (bool)isValidStringArgument:(id)argument withErrorMessage:(NSString**)errorDetails { ++ (BOOL)isValidStringArgument:(id)argument withErrorMessage:(NSString**)errorDetails { if (!argument) { if (errorDetails) { *errorDetails = @"Argument is nil.";