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 83a7ed6340f8..44ea64e3e90b 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 @@ -18,12 +18,15 @@ import io.flutter.plugin.common.MethodChannel.MethodCallHandler; import io.flutter.plugin.common.MethodChannel.Result; import io.flutter.plugin.platform.PlatformView; +import java.io.UnsupportedEncodingException; +import java.net.URLEncoder; import java.util.Collections; import java.util.List; import java.util.Map; public class FlutterWebView implements PlatformView, MethodCallHandler { private static final String JS_CHANNEL_NAMES_FIELD = "javascriptChannelNames"; + private static final String TAG = "FlutterWebView"; private final InputAwareWebView webView; private final MethodChannel methodChannel; private final FlutterWebViewClient flutterWebViewClient; @@ -121,6 +124,9 @@ public void onMethodCall(MethodCall methodCall, Result result) { case "loadUrl": loadUrl(methodCall, result); break; + case "postUrl": + postUrl(methodCall, result); + break; case "updateSettings": updateSettings(methodCall, result); break; @@ -162,6 +168,20 @@ public void onMethodCall(MethodCall methodCall, Result result) { } } + private static String initialParametersToString(Map parameters) + throws UnsupportedEncodingException { + StringBuilder sb = new StringBuilder(); + for (Map.Entry entry : parameters.entrySet()) { + sb.append( + URLEncoder.encode(entry.getKey(), "UTF-8") + + "=" + + URLEncoder.encode(entry.getValue().toString(), "UTF-8") + + "&"); + } + + return sb.deleteCharAt(sb.length() - 1).toString(); + } + @SuppressWarnings("unchecked") private void loadUrl(MethodCall methodCall, Result result) { Map request = (Map) methodCall.arguments; @@ -174,6 +194,18 @@ private void loadUrl(MethodCall methodCall, Result result) { result.success(null); } + @SuppressWarnings("unchecked") + private void postUrl(MethodCall methodCall, Result result) { + Map request = (Map) methodCall.arguments; + String url = (String) request.get("url"); + + byte[] params = (byte[]) request.get("params"); + + webView.postUrl(url, params); + + 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 60fa24052038..46ec19aec68d 100644 --- a/packages/webview_flutter/ios/Classes/FlutterWebView.m +++ b/packages/webview_flutter/ios/Classes/FlutterWebView.m @@ -3,6 +3,7 @@ // found in the LICENSE file. #import "FlutterWebView.h" +#import #import "FLTWKNavigationDelegate.h" #import "JavaScriptChannelHandler.h" @@ -98,6 +99,8 @@ - (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:@"postUrl"]) { + [self postUrl:call result:result]; } else if ([[call method] isEqualToString:@"canGoBack"]) { [self onCanGoBack:call result:result]; } else if ([[call method] isEqualToString:@"canGoForward"]) { @@ -340,6 +343,29 @@ - (bool)loadUrl:(NSString*)url withHeaders:(NSDictionary*) return true; } +- (bool)postUrl:(FlutterMethodCall*)call result:(FlutterResult)result { + NSDictionary* args = [call arguments]; + + NSString* url = (NSString*)args[@"url"]; + NSURL* nsUrl = [NSURL URLWithString:url]; + if (!nsUrl) { + return false; + } + + NSMutableURLRequest* request = [NSMutableURLRequest requestWithURL:nsUrl]; + FlutterStandardTypedData* postData = (FlutterStandardTypedData*)args[@"params"]; + NSString* contentLength = @(postData.data.length).stringValue; + + [request setHTTPMethod:@"POST"]; + [request setHTTPBody:postData.data]; + + [request setValue:contentLength forHTTPHeaderField:@"Content-Length"]; + [request setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"]; + + [_webView loadRequest:request]; + return true; +} + - (void)registerJavaScriptChannels:(NSSet*)channelNames controller:(WKUserContentController*)userContentController { for (NSString* channelName in channelNames) { diff --git a/packages/webview_flutter/lib/platform_interface.dart b/packages/webview_flutter/lib/platform_interface.dart index cf6a2fd933f7..bbdd69fff9e3 100644 --- a/packages/webview_flutter/lib/platform_interface.dart +++ b/packages/webview_flutter/lib/platform_interface.dart @@ -3,6 +3,7 @@ // found in the LICENSE file. import 'dart:async'; +import 'dart:typed_data'; import 'package:flutter/foundation.dart'; import 'package:flutter/gestures.dart'; @@ -61,6 +62,18 @@ abstract class WebViewPlatformController { "WebView loadUrl is not implemented on the current platform"); } + /// Post to the specified URL. + /// + /// `url` must not be null + /// `params` must not be null + /// + /// `params` have to be ascii encoded + /// Throws an ArgumentError if `url` is not a valid URL string. + Future postUrl(String url, Uint8List params) { + throw UnimplementedError( + "Webview postUrl 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 2bb7470a1145..090d9bd81860 100644 --- a/packages/webview_flutter/lib/src/webview_method_channel.dart +++ b/packages/webview_flutter/lib/src/webview_method_channel.dart @@ -3,6 +3,7 @@ // found in the LICENSE file. import 'dart:async'; +import 'dart:typed_data'; import 'package:flutter/services.dart'; @@ -55,6 +56,16 @@ class MethodChannelWebViewPlatform implements WebViewPlatformController { }); } + @override + Future postUrl(String url, Uint8List params) async { + assert(url != null); + assert(params != null); + return _channel.invokeMethod('postUrl', { + 'url': url, + 'params': params, + }); + } + @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 11541d322dfb..e8fb0acb0864 100644 --- a/packages/webview_flutter/lib/webview_flutter.dart +++ b/packages/webview_flutter/lib/webview_flutter.dart @@ -505,6 +505,20 @@ class WebViewController { return _webViewPlatformController.loadUrl(url, headers); } + /// Post to the specified URL. + /// + /// `url` must not be null + /// `params` must not be null + /// + /// `params` have to be ascii encoded + /// Throws an ArgumentError if `url` is not a valid URL string. + Future postUrl(String url, List params) async { + assert(url != null); + assert(params != null); + _validateUrlString(url); + return _webViewPlatformController.postUrl(url, params); + } + /// Accessor to the current URL that the WebView is displaying. /// /// If [WebView.initialUrl] was never specified, returns `null`.