diff --git a/packages/webview_flutter/android/src/main/java/io/flutter/plugins/webviewflutter/FlutterWebView.java b/packages/webview_flutter/android/src/main/java/io/flutter/plugins/webviewflutter/FlutterWebView.java index bfb79a39e8ba..db65a8116b44 100644 --- a/packages/webview_flutter/android/src/main/java/io/flutter/plugins/webviewflutter/FlutterWebView.java +++ b/packages/webview_flutter/android/src/main/java/io/flutter/plugins/webviewflutter/FlutterWebView.java @@ -174,6 +174,12 @@ public void onMethodCall(MethodCall methodCall, Result result) { case "loadUrl": loadUrl(methodCall, result); break; + case "loadData": + loadData(methodCall, result); + break; + case "loadDataBase64": + loadDataBase64(methodCall, result); + break; case "updateSettings": updateSettings(methodCall, result); break; @@ -239,6 +245,33 @@ private void loadUrl(MethodCall methodCall, Result result) { result.success(null); } + @SuppressWarnings("unchecked") + private void loadData(MethodCall methodCall, Result result) { + Map request = (Map) methodCall.arguments; + String baseUrl = (String) request.get("baseUrl"); + String data = (String) request.get("data"); + String mimeType = (String) request.get("mimeType"); + + final String encoding = "UTF-8"; + webView.loadDataWithBaseURL(baseUrl, data, mimeType, encoding, null); + result.success(null); + } + + @SuppressWarnings("unchecked") + private void loadDataBase64(MethodCall methodCall, Result result) { + Map request = (Map) methodCall.arguments; + String data = (String) request.get("data"); + String mimeType = (String) request.get("mimeType"); + + // We do not use baseUrl, because Android has no way to set it in this context. + + // Theoretically, we should be able to use WebView#loadDataWithBaseURL here, but + // support for base64 seems to be broken. + final String url = String.format("data:%s;base64,%s", mimeType, data); + webView.loadUrl(url); + result.success(null); + } + private void canGoBack(Result result) { result.success(webView.canGoBack()); } diff --git a/packages/webview_flutter/ios/Classes/FlutterWebView.m b/packages/webview_flutter/ios/Classes/FlutterWebView.m index 969e010913f3..17cd74b628d2 100644 --- a/packages/webview_flutter/ios/Classes/FlutterWebView.m +++ b/packages/webview_flutter/ios/Classes/FlutterWebView.m @@ -128,6 +128,10 @@ - (void)onMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result { [self onUpdateSettings:call result:result]; } else if ([[call method] isEqualToString:@"loadUrl"]) { [self onLoadUrl:call result:result]; + } else if ([[call method] isEqualToString:@"loadData"]) { + [self onLoadData:call result:result]; + } else if ([[call method] isEqualToString:@"loadDataBase64"]) { + [self onLoadDataBase64:call result:result]; } else if ([[call method] isEqualToString:@"canGoBack"]) { [self onCanGoBack:call result:result]; } else if ([[call method] isEqualToString:@"canGoForward"]) { @@ -183,6 +187,112 @@ - (void)onLoadUrl:(FlutterMethodCall*)call result:(FlutterResult)result { } } +- (void)onLoadData:(FlutterMethodCall*)call result:(FlutterResult)result { + NSDictionary* arguments = [call arguments]; + if (!arguments) { + result([FlutterError errorWithCode:@"loadData_failed" + message:@"No arguments passed to method" + details:nil]); + return; + } + + NSString* const encoding = @"UTF-8"; + NSString* mimeType = arguments[@"mimeType"]; + NSString* baseUrl = arguments[@"baseUrl"]; + NSString* dataStr = arguments[@"data"]; + + if (![mimeType isKindOfClass:[NSString class]]) { + result([FlutterError errorWithCode:@"loadData_failed" + message:@"Argument type of mimeType is not string" + details:nil]); + return; + } + + if (![baseUrl isKindOfClass:[NSString class]]) { + result([FlutterError errorWithCode:@"loadData_failed" + message:@"Argument type of baseUrl is not string" + details:nil]); + return; + } + + NSURL* nsUrl = [NSURL URLWithString:baseUrl]; + if (!nsUrl) { + result([FlutterError errorWithCode:@"loadData_failed" + message:@"Argument type of baseUrl is not a valid URL" + details:[NSString stringWithFormat:@"URL was: '%@'", baseUrl]]); + return; + } + + if (![dataStr isKindOfClass:[NSString class]]) { + result([FlutterError errorWithCode:@"loadData_failed" + message:@"Argument type of data is not string" + details:nil]); + return; + } + + NSData* data = [dataStr dataUsingEncoding:NSUTF8StringEncoding]; + if (@available(iOS 9.0, *)) { + [_webView loadData:data MIMEType:mimeType characterEncodingName:encoding baseURL:nsUrl]; + } else { + NSLog(@"Setting data is not supported for Flutter WebViews prior to iOS 9."); + } + + result(nil); +} + +- (void)onLoadDataBase64:(FlutterMethodCall*)call result:(FlutterResult)result { + NSDictionary* arguments = [call arguments]; + if (!arguments) { + result([FlutterError errorWithCode:@"loadDataBase64_failed" + message:@"No arguments passed to method" + details:nil]); + return; + } + + NSString* const encoding = @"UTF-8"; + NSString* mimeType = arguments[@"mimeType"]; + NSString* dataStr = arguments[@"data"]; + NSString* baseUrl = arguments[@"baseUrl"]; + + if (![mimeType isKindOfClass:[NSString class]]) { + result([FlutterError errorWithCode:@"loadDataBase64_failed" + message:@"Argument type of mimeType is not string" + details:nil]); + return; + } + + if (![dataStr isKindOfClass:[NSString class]]) { + result([FlutterError errorWithCode:@"loadDataBase64_failed" + message:@"Argument type of data is not string" + details:nil]); + return; + } + + if (![baseUrl isKindOfClass:[NSString class]]) { + result([FlutterError errorWithCode:@"loadDataBase64_failed" + message:@"Argument type of baseUrl is not string" + details:nil]); + return; + } + + NSURL* nsUrl = [NSURL URLWithString:baseUrl]; + if (!nsUrl) { + result([FlutterError errorWithCode:@"loadData_failed" + message:@"Argument type of baseUrl is not a valid URL" + details:[NSString stringWithFormat:@"URL was: '%@'", baseUrl]]); + return; + } + + NSData* data = [[NSData alloc] initWithBase64EncodedString:dataStr options:0]; + if (@available(iOS 9.0, *)) { + [_webView loadData:data MIMEType:mimeType characterEncodingName:encoding baseURL:nsUrl]; + } else { + NSLog(@"Setting data is not supported for Flutter WebViews prior to iOS 9."); + } + + result(nil); +} + - (void)onCanGoBack:(FlutterMethodCall*)call result:(FlutterResult)result { BOOL canGoBack = [_webView canGoBack]; result([NSNumber numberWithBool:canGoBack]); diff --git a/packages/webview_flutter/lib/platform_interface.dart b/packages/webview_flutter/lib/platform_interface.dart index 6c991b14a76e..53193ad10a6f 100644 --- a/packages/webview_flutter/lib/platform_interface.dart +++ b/packages/webview_flutter/lib/platform_interface.dart @@ -182,6 +182,41 @@ abstract class WebViewPlatformController { "WebView loadUrl is not implemented on the current platform"); } + /// Loads the specified content data into the WebView. + /// + /// The string `data` will be interpreted as a UTF-8 string. + /// + /// `baseUrl` is the apparent URL which the page was loaded at, used to resolve + /// relative paths. + /// + /// Throws an ArgumentError if `baseUrl` is not a valid URL string. + Future loadData( + String data, + String baseUrl, + String mimeType, + ) { + throw UnimplementedError( + "WebView loadData is not implemented on the current platform"); + } + + /// Loads the specified content data into the WebView. + /// + /// The string `data` will be interpreted as a Base64 encoded string. Note + /// that any trailing padding = or == characters MUST be present for full device + /// compatibility. + /// + /// The `baseUrl` argument is required but has no effect on Android. + /// + /// Throws an ArgumentError if `baseUrl` is not a valid URL string. + Future loadDataBase64( + String data, + String mimeType, + String baseUrl, + ) { + throw UnimplementedError( + "WebView loadDataBase64 is not implemented on the current platform"); + } + /// Updates the webview settings. /// /// Any non null field in `settings` will be set as the new setting value. diff --git a/packages/webview_flutter/lib/src/webview_method_channel.dart b/packages/webview_flutter/lib/src/webview_method_channel.dart index 348b225bb257..776d78433f9b 100644 --- a/packages/webview_flutter/lib/src/webview_method_channel.dart +++ b/packages/webview_flutter/lib/src/webview_method_channel.dart @@ -80,6 +80,38 @@ class MethodChannelWebViewPlatform implements WebViewPlatformController { }); } + @override + Future loadData( + String data, + String baseUrl, + String mimeType, + ) async { + assert(data != null); + assert(baseUrl != null); + assert(mimeType != null); + return _channel.invokeMethod('loadData', { + 'data': data, + 'baseUrl': baseUrl, + 'mimeType': mimeType, + }); + } + + @override + Future loadDataBase64( + String data, + String mimeType, + String baseUrl, + ) async { + assert(data != null); + assert(mimeType != null); + assert(baseUrl != null); + return _channel.invokeMethod('loadDataBase64', { + 'data': data, + 'mimeType': mimeType, + 'baseUrl': baseUrl, + }); + } + @override Future currentUrl() => _channel.invokeMethod('currentUrl'); diff --git a/packages/webview_flutter/lib/webview_flutter.dart b/packages/webview_flutter/lib/webview_flutter.dart index 5e2bffd6539d..f1782643cb0f 100644 --- a/packages/webview_flutter/lib/webview_flutter.dart +++ b/packages/webview_flutter/lib/webview_flutter.dart @@ -609,6 +609,45 @@ class WebViewController { return _webViewPlatformController.loadUrl(url, headers); } + /// Loads the specified content data into the WebView. + /// + /// The string `data` will be interpreted as a UTF-8 string. + /// + /// `baseUrl` is the apparent URL which the page was loaded at, used to resolve + /// relative paths. + /// + /// Throws an ArgumentError if `baseUrl` is not a valid URL string. + Future loadData( + String data, { + @required String baseUrl, + @required String mimeType, + }) async { + assert(data != null); + assert(baseUrl != null); + assert(mimeType != null); + _validateUrlString(baseUrl); + return _webViewPlatformController.loadData(data, baseUrl, mimeType); + } + + /// Loads the specified content data into the WebView. + /// + /// The string `data` will be interpreted as a Base64 encoded string. Note + /// that any trailing padding = or == characters MUST be present for full device + /// compatibility. + /// + /// The `baseUrl` argument is required but has no effect on Android. + /// + /// Throws an ArgumentError if `baseUrl` is not a valid URL string. + Future loadDataBase64( + String data, { + @required String mimeType, + @required String baseUrl, + }) async { + assert(data != null); + assert(mimeType != null); + return _webViewPlatformController.loadDataBase64(data, mimeType, baseUrl); + } + /// Accessor to the current URL that the WebView is displaying. /// /// If [WebView.initialUrl] was never specified, returns `null`.