diff --git a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/HttpRequestManager.java b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/HttpRequestManager.java
new file mode 100644
index 000000000000..ab08455a58ae
--- /dev/null
+++ b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/HttpRequestManager.java
@@ -0,0 +1,203 @@
+// 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.
+
+package io.flutter.plugins.webviewflutter;
+
+import android.os.Handler;
+import androidx.annotation.VisibleForTesting;
+import java.io.BufferedOutputStream;
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.net.HttpURLConnection;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.Map;
+import java.util.concurrent.Executor;
+
+/** Defines callback methods for the HttpRequestManager. */
+interface HttpRequestCallback {
+ void onComplete(String result);
+
+ void onError(Exception error);
+}
+
+/**
+ * Works around on Android WebView postUrl method to accept headers.
+ *
+ *
Android WebView does not provide a post request method that accepts headers. Only method that
+ * is provided is {@link android.webkit.WebView#postUrl(String, byte[])} and it accepts only URL and
+ * HTTP body. CustomHttpPostRequest is implemented to provide this feature since adding a header to
+ * post requests is a feature that is likely to be wanted.
+ *
+ *
In the implementation, {@link HttpURLConnection} is used to create a post request with the
+ * HTTP headers and the HTTP body.
+ */
+public class HttpRequestManager {
+ private final Executor executor;
+ private final Handler resultHandler;
+
+ HttpRequestManager(Executor executor, Handler resultHandler) {
+ this.executor = executor;
+ this.resultHandler = resultHandler;
+ }
+
+ /**
+ * Executes the given HTTP request in a background thread. See https://developer.android.com/guide/background/threading.
+ *
+ * @param request {@link WebViewRequest} to execute.
+ * @param callback methods to invoke after the HTTP request has completed.
+ */
+ public void requestAsync(final WebViewRequest request, final HttpRequestCallback callback) {
+ executor.execute(
+ new Runnable() {
+ @Override
+ public void run() {
+ try {
+ String responseResult = request(request);
+ notifyComplete(responseResult, callback);
+ } catch (IOException e) {
+ notifyError(e, callback);
+ }
+ }
+ });
+ }
+
+ /**
+ * Executes the given HTTP request synchronously.
+ *
+ * @param request {@link WebViewRequest} to execute.
+ * @return The response body as a String.
+ */
+ public String request(WebViewRequest request) throws IOException {
+ URL url = URLFactory.create(request.getUri());
+ HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection();
+ try {
+ // Basic request configuration
+ httpURLConnection.setConnectTimeout(5000);
+ httpURLConnection.setRequestMethod(request.getMethod().getValue().toUpperCase());
+
+ // Set HTTP headers
+ for (Map.Entry entry : request.getHeaders().entrySet()) {
+ httpURLConnection.setRequestProperty(entry.getKey(), entry.getValue());
+ }
+
+ // Set HTTP body
+ if (request.getBody() != null && request.getBody().length > 0) {
+ // Used to enable streaming of a HTTP request body without internal buffering,
+ // when the content length is known in advance. It improves the performance
+ // because otherwise HTTPUrlConnection will be forced to buffer the complete
+ // request body in memory before it is transmitted, wasting (and possibly exhausting)
+ // heap and increasing latency.
+ httpURLConnection.setFixedLengthStreamingMode(request.getBody().length);
+
+ httpURLConnection.setDoOutput(true);
+ OutputStream os = BufferedOutputStreamFactory.create(httpURLConnection.getOutputStream());
+ os.write(request.getBody());
+ os.flush();
+ os.close();
+ }
+
+ // Collect and return response body
+ String line = "";
+ StringBuilder contentBuilder = new StringBuilder();
+ BufferedReader rd =
+ BufferedReaderFactory.create(
+ InputStreamReaderFactory.create(httpURLConnection.getInputStream()));
+ while ((line = rd.readLine()) != null) {
+ contentBuilder.append(line);
+ }
+ return contentBuilder.toString();
+ } finally {
+ httpURLConnection.disconnect();
+ }
+ }
+
+ private void notifyComplete(final String responseResult, final HttpRequestCallback callback) {
+ resultHandler.post(
+ new Runnable() {
+ @Override
+ public void run() {
+ callback.onComplete(responseResult);
+ }
+ });
+ }
+
+ private void notifyError(final Exception error, final HttpRequestCallback callback) {
+ resultHandler.post(
+ new Runnable() {
+ @Override
+ public void run() {
+ callback.onError(error);
+ }
+ });
+ }
+ /** Factory class for creating a {@link URL} */
+ static class URLFactory {
+ /**
+ * Creates a {@link URL}.
+ *
+ *
Important: This method is visible for testing purposes only and should
+ * never be called from outside this class.
+ *
+ * @param url to create the instance for.
+ * @return The new {@link URL} object.
+ */
+ @VisibleForTesting
+ public static URL create(String url) throws MalformedURLException {
+ return new URL(url);
+ }
+ }
+ /** Factory class for creating a {@link BufferedOutputStream} */
+ static class BufferedOutputStreamFactory {
+ /**
+ * Creates a {@link BufferedOutputStream}.
+ *
+ *
Important: This method is visible for testing purposes only and should
+ * never be called from outside this class.
+ *
+ * @param stream to create the instance for.
+ * @return The new {@link BufferedOutputStream} object.
+ */
+ @VisibleForTesting
+ public static BufferedOutputStream create(OutputStream stream) {
+ return new BufferedOutputStream(stream);
+ }
+ }
+ /** Factory class for creating a {@link BufferedReader} */
+ static class BufferedReaderFactory {
+ /**
+ * Creates a {@link BufferedReader}.
+ *
+ *
Important: This method is visible for testing purposes only and should
+ * never be called from outside this class.
+ *
+ * @param stream to create the instance for.
+ * @return The new {@link BufferedReader} object.
+ */
+ @VisibleForTesting
+ public static BufferedReader create(InputStreamReader stream) {
+ return new BufferedReader(stream);
+ }
+ }
+ /** Factory class for creating a {@link InputStreamReader} */
+ static class InputStreamReaderFactory {
+ /**
+ * Creates a {@link InputStreamReader}.
+ *
+ *
Important: This method is visible for testing purposes only and should
+ * never be called from outside this class.
+ *
+ * @param stream to create the instance for.
+ * @return The new {@link InputStreamReader} object.
+ */
+ @VisibleForTesting
+ public static InputStreamReader create(InputStream stream) {
+ return new InputStreamReader(stream);
+ }
+ }
+}
diff --git a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewRequest.java b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewRequest.java
new file mode 100644
index 000000000000..f5e80c3a178e
--- /dev/null
+++ b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewRequest.java
@@ -0,0 +1,107 @@
+// 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.
+
+package io.flutter.plugins.webviewflutter;
+
+import java.util.Collections;
+import java.util.Map;
+
+/**
+ * Defines the supported HTTP methods for loading a page in the {@link android.webkit.WebView} and
+ * the {@link HttpRequestManager}.
+ */
+enum WebViewLoadMethod {
+ GET("get"),
+
+ POST("post");
+
+ private final String value;
+
+ WebViewLoadMethod(String value) {
+ this.value = value;
+ }
+
+ /** Converts to WebViewLoadMethod to String format. */
+ public String serialize() {
+ return getValue();
+ }
+
+ /** Returns the enum value. */
+ public String getValue() {
+ return value;
+ }
+
+ /** Converts to String to WebViewLoadMethod format. */
+ public static WebViewLoadMethod deserialize(String value) {
+ for (WebViewLoadMethod webViewLoadMethod : WebViewLoadMethod.values()) {
+ if (webViewLoadMethod.value.equals(value)) {
+ return webViewLoadMethod;
+ }
+ }
+ throw new IllegalArgumentException("No enum value found for '" + value + "'.");
+ }
+}
+
+/**
+ * Creates a HTTP request object.
+ *
+ *