Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for POST #307

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,8 @@ private void openUrl(MethodCall call, MethodChannel.Result result) {
Map<String, String> headers = call.argument("headers");
boolean scrollBar = call.argument("scrollBar");
boolean allowFileURLs = call.argument("allowFileURLs");
boolean isPost = call.argument("isPost");
Map<String, Object> body = call.argument("body");

if (webViewManager == null || webViewManager.closed == true) {
webViewManager = new WebviewManager(activity);
Expand All @@ -118,7 +120,9 @@ private void openUrl(MethodCall call, MethodChannel.Result result) {
scrollBar,
supportMultipleWindows,
appCacheEnabled,
allowFileURLs
allowFileURLs,
isPost,
body
);
result.success(null);
}
Expand Down
201 changes: 197 additions & 4 deletions android/src/main/java/com/flutter_webview_plugin/WebviewManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,18 @@
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.FrameLayout;
import android.os.AsyncTask;

import java.io.InputStreamReader;
import java.net.URL;
import java.net.HttpURLConnection;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.BufferedReader;
import java.io.DataOutputStream;

import org.json.JSONObject;

import java.util.HashMap;
import java.util.Map;
Expand Down Expand Up @@ -204,7 +216,9 @@ void openUrl(
boolean scrollBar,
boolean supportMultipleWindows,
boolean appCacheEnabled,
boolean allowFileURLs
boolean allowFileURLs,
boolean isPost,
Map<String, Object> body
) {
webView.getSettings().setJavaScriptEnabled(withJavascript);
webView.getSettings().setBuiltInZoomControls(withZoom);
Expand Down Expand Up @@ -243,13 +257,38 @@ void openUrl(
webView.setVerticalScrollBarEnabled(false);
}

if (headers != null) {
webView.loadUrl(url, headers);
if (isPost && body != null) {
PostUrlTask task = new PostUrlTask();
task.setListener(createPostUrlTaskListener(url));

PostUrlInput input = new PostUrlInput(url, headers, body, userAgent);

task.execute(input);

} else {
webView.loadUrl(url);
if (headers != null) {
webView.loadUrl(url, headers);
} else {
webView.loadUrl(url);
}
}
}

/// Helper method for creating the listener for the Post Url task
private PostUrlTask.Listener createPostUrlTaskListener(String url) {
final String urlString = url;
return new PostUrlTask.Listener() {
@Override
public void onSuccess(PostUrlResult result) {
if (result.responseStatus == "HTTP_OK") {
webView.loadDataWithBaseURL(urlString, result.htmlResult, "text/html", "utf-8", null);
} else {
// Do nothing for now // Show error page?
}
}
};
}

void reloadUrl(String url) {
webView.loadUrl(url);
}
Expand Down Expand Up @@ -340,3 +379,157 @@ void stopLoading(MethodCall call, MethodChannel.Result result){
}
}
}


class PostUrlInput {
PostUrlInput(
String urlString,
Map<String, String> headers,
Map<String, Object> body,
String userAgent
){
this.urlString = urlString;
this.headers = headers;
this.body = body;
this.userAgent = userAgent;
}

String urlString;
Map<String, String> headers;
Map<String, Object> body;
String userAgent;
}

class PostUrlResult {
PostUrlResult(String responseStatus, String htmlResult) {
this.responseStatus = responseStatus;
this.htmlResult = htmlResult;
}

String responseStatus;
String htmlResult;
}

// Since Android WebView does not support loading POST with
// custom header, this class is used to get the html needed
// to make a POST request and show the response to WebView
class PostUrlTask extends AsyncTask<PostUrlInput, Void, PostUrlResult> {

private Listener listener;

@Override
protected PostUrlResult doInBackground(PostUrlInput... params) {

HttpURLConnection httpConn = null;
String responseStatus = null;
String htmlResult = "";
PostUrlInput input = params[0];

try {
URL url = new URL(input.urlString);

// HttpURLConnection
httpConn = (HttpURLConnection) url.openConnection();

// request POST
httpConn.setRequestMethod("POST");

// no Redirects
httpConn.setInstanceFollowRedirects(false);

httpConn.setDoOutput(true);

// Set headers
if (input.headers != null){
for (Map.Entry<String, String> header : input.headers.entrySet()){
httpConn.setRequestProperty(header.getKey(), header.getValue());
}
}

// Set user agent
if(input.userAgent != null) {
httpConn.setRequestProperty("User-Agent", input.userAgent);
}

httpConn.setReadTimeout(10000);
httpConn.setConnectTimeout(20000);

httpConn.connect();

OutputStream outStream = null;

try {
outStream = new DataOutputStream(httpConn.getOutputStream ());

JSONObject bodyJson = new JSONObject(input.body);

outStream = httpConn.getOutputStream();
outStream.write( bodyJson.toString().getBytes("UTF-8"));

outStream.flush();

Log.d("debug","flush");
} catch (IOException e) {
e.printStackTrace();
responseStatus = "POST_ERROR";
} finally {
if (outStream != null) {
outStream.close();
}
}

final int status = httpConn.getResponseCode();

if (status == HttpURLConnection.HTTP_OK) {
responseStatus = "HTTP_OK";

// Get the html here
InputStream stream = httpConn.getInputStream();
StringBuffer stringBuffer = new StringBuffer();
String line;
BufferedReader br = new BufferedReader(new InputStreamReader(stream, "UTF-8"));
while ((line = br.readLine()) != null) {
stringBuffer.append(line);
}

try {
stream.close();
} catch (Exception e) {
e.printStackTrace();
}

htmlResult = stringBuffer.toString();
}
else{
responseStatus = "STATUS="+String.valueOf(status);
}

} catch (IOException e) {
e.printStackTrace();
} finally {
if (httpConn != null) {
httpConn.disconnect();
}
}

PostUrlResult result = new PostUrlResult(responseStatus, htmlResult);
return result;
}

@Override
protected void onPostExecute(PostUrlResult result) {
super.onPostExecute(result);

if (listener != null) {
listener.onSuccess(result);
}
}

void setListener(Listener listener) {
this.listener = listener;
}

interface Listener {
void onSuccess(PostUrlResult result);
}
}
22 changes: 22 additions & 0 deletions ios/Classes/FlutterWebviewPlugin.m
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,7 @@ - (void)navigate:(FlutterMethodCall*)call {
if (self.webview != nil) {
NSString *url = call.arguments[@"url"];
NSNumber *withLocalUrl = call.arguments[@"withLocalUrl"];
NSNumber *isPost = call.arguments[@"isPost"];
if ( [withLocalUrl boolValue]) {
NSURL *htmlUrl = [NSURL fileURLWithPath:url isDirectory:false];
if (@available(iOS 9.0, *)) {
Expand All @@ -152,6 +153,27 @@ - (void)navigate:(FlutterMethodCall*)call {
[request setAllHTTPHeaderFields:headers];
}

if (isPost != nil) {
if ([isPost boolValue]) {
/// If this is a post request then set the method and body
[request setHTTPMethod:@"POST"];

NSDictionary *body = call.arguments[@"body"];

NSError *error = nil;
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:body
options:NSJSONWritingPrettyPrinted
error:&error];

/// Check if there is an error
if (!jsonData) {
NSLog(@"Error parsing JSON %@", error);
} else {
[request setHTTPBody:jsonData];
}
}
}

[self.webview loadRequest:request];
}
}
Expand Down
7 changes: 7 additions & 0 deletions lib/src/base.dart
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,8 @@ class FlutterWebviewPlugin {
bool clearCookies,
bool hidden,
bool enableAppScheme,
bool isPost,
Map<String, dynamic> body,
Rect rect,
String userAgent,
bool withZoom,
Expand All @@ -118,6 +120,7 @@ class FlutterWebviewPlugin {
'hidden': hidden ?? false,
'clearCookies': clearCookies ?? false,
'enableAppScheme': enableAppScheme ?? true,
'isPost': isPost ?? false,
'userAgent': userAgent,
'withZoom': withZoom ?? false,
'withLocalStorage': withLocalStorage ?? true,
Expand All @@ -132,6 +135,10 @@ class FlutterWebviewPlugin {
args['headers'] = headers;
}

if (isPost != false && body != null) {
args['body'] = body;
}

if (rect != null) {
args['rect'] = {
'left': rect.left,
Expand Down
6 changes: 6 additions & 0 deletions lib/src/webview_scaffold.dart
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ class WebviewScaffold extends StatefulWidget {
this.clearCache,
this.clearCookies,
this.enableAppScheme,
this.isPost,
this.body,
this.userAgent,
this.primary = true,
this.persistentFooterButtons,
Expand All @@ -39,6 +41,8 @@ class WebviewScaffold extends StatefulWidget {
final bool clearCache;
final bool clearCookies;
final bool enableAppScheme;
final bool isPost;
final Map<String, dynamic> body;
final String userAgent;
final bool primary;
final List<Widget> persistentFooterButtons;
Expand Down Expand Up @@ -106,6 +110,8 @@ class _WebviewScaffoldState extends State<WebviewScaffold> {
clearCookies: widget.clearCookies,
hidden: widget.hidden,
enableAppScheme: widget.enableAppScheme,
isPost: widget.isPost,
body: widget.body,
userAgent: widget.userAgent,
rect: _rect,
withZoom: widget.withZoom,
Expand Down