Commit f89610ae authored by Lorenzo Pichilli's avatar Lorenzo Pichilli

updated AjaxRequest class, fixed 'InvalidStateError' ajax error #189, No need...

updated AjaxRequest class, fixed 'InvalidStateError' ajax error #189, No need to listen to window.addEventListener(flutterInAppBrowserPlatformReady, fuction(){ }) javascript event anymore to use JaaScript message handlers
parent 44c17d1e
This diff is collapsed.
......@@ -45,6 +45,7 @@
- Renamed `injectScriptCode` to `evaluateJavascript`
- Renamed `injectStyleCode` to `injectCSSCode`
- Renamed `injectStyleFile` to `injectCSSFileFromUrl`
- No need to listen to `window.addEventListener("flutterInAppBrowserPlatformReady", fuction(){ })` javascript event anymore to call `window.flutter_inappbrowser.callHandler(handlerName <String>, ...args)` to use the JavaScript message handlers
## 1.2.1
......
......@@ -184,12 +184,6 @@ public class InAppWebViewClient extends WebViewClient {
view.clearFocus();
view.requestFocus();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
webView.evaluateJavascript(InAppWebView.platformReadyJS, (ValueCallback<String>) null);
} else {
webView.loadUrl("javascript:" + InAppWebView.platformReadyJS.replaceAll("[\r\n]+", ""));
}
Map<String, Object> obj = new HashMap<>();
if (inAppBrowserActivity != null)
obj.put("uuid", inAppBrowserActivity.uuid);
......
......@@ -77,26 +77,23 @@
window.location = "#foo-" + randomNumber;
}
window.addEventListener("flutterInAppBrowserPlatformReady", function(event) {
console.log("ready");
window.flutter_inappbrowser.callHandler('handlerFoo').then(function(result) {
//console.log(result, typeof result);
//console.log(JSON.stringify(result), result.bar);
});
window.flutter_inappbrowser.callHandler('handlerFoo').then(function(result) {
console.log(result, typeof result);
console.log(JSON.stringify(result), result.bar);
});
window.flutter_inappbrowser.callHandler('handlerFooWithArgs', 1, true, ['bar', 5], {foo: 'baz'}).then(function(result) {
//console.log(result, typeof result);
//console.log(JSON.stringify(result));
});
window.flutter_inappbrowser.callHandler('handlerFooWithArgs', 1, true, ['bar', 5], {foo: 'baz'}).then(function(result) {
console.log(result, typeof result);
console.log(JSON.stringify(result));
});
$(document).ready(function() {
console.log("jQuery ready");
var xhttp = new XMLHttpRequest();
xhttp.addEventListener("load", function() {
console.log(this.responseText);
console.log(this.response);
});
xhttp.open("POST", "http://192.168.1.20:8082/test-ajax-post");
xhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
......
......@@ -290,16 +290,19 @@ class _InlineExampleScreenState extends State<InlineExampleScreen> {
},
shouldInterceptAjaxRequest: (InAppWebViewController controller, AjaxRequest ajaxRequest) async {
print("AJAX REQUEST: ${ajaxRequest.method} - ${ajaxRequest.url}, DATA: ${ajaxRequest.data}");
if (ajaxRequest.url == "http://192.168.1.20:8082/test-ajax-post") {
ajaxRequest.responseType = 'json';
}
// ajaxRequest.method = "GET";
// ajaxRequest.url = "http://192.168.1.20:8082/test-download-file";
// ajaxRequest.headers = {
// "Custom-Header": "Custom-Value"
// };
// return ajaxRequest;
return null;
return ajaxRequest;
},
onAjaxReadyStateChange: (InAppWebViewController controller, AjaxRequest ajaxRequest) async {
print("AJAX READY STATE CHANGE: ${ajaxRequest.method} - ${ajaxRequest.url}, ${ajaxRequest.status}, ${ajaxRequest.readyState}, ${ajaxRequest.responseType}, ${ajaxRequest.responseText}, ${ajaxRequest.responseHeaders}");
print("AJAX READY STATE CHANGE: ${ajaxRequest.method} - ${ajaxRequest.url}, ${ajaxRequest.status}, ${ajaxRequest.readyState}, ${ajaxRequest.responseType}, ${ajaxRequest.responseText}, ${ajaxRequest.response}, ${ajaxRequest.responseHeaders}");
return AjaxRequestAction.PROCEED;
},
onAjaxProgress: (InAppWebViewController controller, AjaxRequest ajaxRequest) async {
......
......@@ -82,8 +82,6 @@ window.\(JAVASCRIPT_BRIDGE_NAME).callHandler = function() {
}
"""
let platformReadyJS = "window.dispatchEvent(new Event('flutterInAppBrowserPlatformReady'));";
let findTextHighlightJS = """
var wkwebview_SearchResultCount = 0;
var wkwebview_CurrentHighlight = 0;
......@@ -266,6 +264,29 @@ let interceptAjaxRequestsJS = """
ajax.prototype._flutter_inappbrowser_password = null;
ajax.prototype._flutter_inappbrowser_already_onreadystatechange_wrapped = false;
ajax.prototype._flutter_inappbrowser_request_headers = {};
function convertRequestResponse(request, callback) {
if (request.response != null && request.responseType != null) {
switch (request.responseType) {
case 'arraybuffer':
callback(new Uint8Array(request.response));
return;
case 'blob':
const reader = new FileReader();
reader.addEventListener('loadend', function() {
callback(new Uint8Array(reader.result));
});
reader.readAsArrayBuffer(blob);
return;
case 'document':
callback(request.response.documentElement.outerHTML);
return;
case 'json':
callback(request.response);
return;
};
}
callback(null);
};
ajax.prototype.open = function(method, url, isAsync, user, password) {
isAsync = (isAsync != null) ? isAsync : true;
this._flutter_inappbrowser_url = url;
......@@ -293,36 +314,40 @@ let interceptAjaxRequestsJS = """
responseHeaders[header] = value;
});
}
var ajaxRequest = {
method: this._flutter_inappbrowser_method,
url: this._flutter_inappbrowser_url,
isAsync: this._flutter_inappbrowser_isAsync,
user: this._flutter_inappbrowser_user,
password: this._flutter_inappbrowser_password,
withCredentials: this.withCredentials,
headers: this._flutter_inappbrowser_request_headers,
readyState: this.readyState,
status: this.status,
responseURL: this.responseURL,
responseType: this.responseType,
responseText: this.responseText,
statusText: this.statusText,
responseHeaders, responseHeaders,
event: {
type: e.type,
loaded: e.loaded,
lengthComputable: e.lengthComputable,
total: e.total
}
};
window.\(JAVASCRIPT_BRIDGE_NAME).callHandler('onAjaxProgress', ajaxRequest).then(function(result) {
if (result != null) {
switch (result) {
case 0:
self.abort();
return;
};
}
convertRequestResponse(this, function(response) {
var ajaxRequest = {
method: self._flutter_inappbrowser_method,
url: self._flutter_inappbrowser_url,
isAsync: self._flutter_inappbrowser_isAsync,
user: self._flutter_inappbrowser_user,
password: self._flutter_inappbrowser_password,
withCredentials: self.withCredentials,
headers: self._flutter_inappbrowser_request_headers,
readyState: self.readyState,
status: self.status,
responseURL: self.responseURL,
responseType: self.responseType,
response: response,
responseText: (self.responseType == 'text' || self.responseType == '') ? self.responseText : null,
responseXML: (self.responseType == 'document' && self.responseXML != null) ? self.responseXML.documentElement.outerHTML : null,
statusText: self.statusText,
responseHeaders, responseHeaders,
event: {
type: e.type,
loaded: e.loaded,
lengthComputable: e.lengthComputable,
total: e.total
}
};
window.\(JAVASCRIPT_BRIDGE_NAME).callHandler('onAjaxProgress', ajaxRequest).then(function(result) {
if (result != null) {
switch (result) {
case 0:
self.abort();
return;
};
}
});
});
}
};
......@@ -345,33 +370,37 @@ let interceptAjaxRequestsJS = """
responseHeaders[header] = value;
});
}
var ajaxRequest = {
method: this._flutter_inappbrowser_method,
url: this._flutter_inappbrowser_url,
isAsync: this._flutter_inappbrowser_isAsync,
user: this._flutter_inappbrowser_user,
password: this._flutter_inappbrowser_password,
withCredentials: this.withCredentials,
headers: this._flutter_inappbrowser_request_headers,
readyState: this.readyState,
status: this.status,
responseURL: this.responseURL,
responseType: this.responseType,
responseText: this.responseText,
statusText: this.statusText,
responseHeaders: responseHeaders
};
window.\(JAVASCRIPT_BRIDGE_NAME).callHandler('onAjaxReadyStateChange', ajaxRequest).then(function(result) {
if (result != null) {
switch (result) {
case 0:
self.abort();
return;
};
}
if (onreadystatechange != null) {
onreadystatechange();
}
convertRequestResponse(this, function(response) {
var ajaxRequest = {
method: self._flutter_inappbrowser_method,
url: self._flutter_inappbrowser_url,
isAsync: self._flutter_inappbrowser_isAsync,
user: self._flutter_inappbrowser_user,
password: self._flutter_inappbrowser_password,
withCredentials: self.withCredentials,
headers: self._flutter_inappbrowser_request_headers,
readyState: self.readyState,
status: self.status,
responseURL: self.responseURL,
responseType: self.responseType,
response: response,
responseText: (self.responseType == 'text' || self.responseType == '') ? self.responseText : null,
responseXML: (self.responseType == 'document' && self.responseXML != null) ? self.responseXML.documentElement.outerHTML : null,
statusText: self.statusText,
responseHeaders: responseHeaders
};
window.\(JAVASCRIPT_BRIDGE_NAME).callHandler('onAjaxReadyStateChange', ajaxRequest).then(function(result) {
if (result != null) {
switch (result) {
case 0:
self.abort();
return;
};
}
if (onreadystatechange != null) {
onreadystatechange();
}
});
});
} else if (onreadystatechange != null) {
onreadystatechange();
......@@ -393,7 +422,8 @@ let interceptAjaxRequestsJS = """
user: this._flutter_inappbrowser_user,
password: this._flutter_inappbrowser_password,
withCredentials: this.withCredentials,
headers: this._flutter_inappbrowser_request_headers
headers: this._flutter_inappbrowser_request_headers,
responseType: this.responseType
};
window.\(JAVASCRIPT_BRIDGE_NAME).callHandler('shouldInterceptAjaxRequest', ajaxRequest).then(function(result) {
if (result != null) {
......@@ -404,6 +434,9 @@ let interceptAjaxRequestsJS = """
};
data = result.data;
self.withCredentials = result.withCredentials;
if (result.responseType != null) {
self.responseType = result.responseType;
};
for (var header in result.headers) {
var value = result.headers[header];
self.setRequestHeader(header, value);
......@@ -1310,7 +1343,6 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi
currentURL = url
InAppWebView.credentialsProposed = []
onLoadStop(url: (currentURL?.absoluteString)!)
evaluateJavaScript(platformReadyJS, completionHandler: nil)
if IABController != nil {
IABController!.updateUrlTextField(url: (currentURL?.absoluteString)!)
......
......@@ -578,8 +578,9 @@ class InAppWebViewController {
String password = argMap["password"];
bool withCredentials = argMap["withCredentials"];
Map<dynamic, dynamic> headers = argMap["headers"];
String responseType = argMap["responseType"];
var request = new AjaxRequest(data: data, method: method, url: url, isAsync: isAsync, user: user, password: password, withCredentials: withCredentials, headers: headers);
var request = new AjaxRequest(data: data, method: method, url: url, isAsync: isAsync, user: user, password: password, withCredentials: withCredentials, headers: headers, responseType: responseType);
if (_widget != null && _widget.shouldInterceptAjaxRequest != null)
return jsonEncode(await _widget.shouldInterceptAjaxRequest(this, request));
......@@ -600,13 +601,15 @@ class InAppWebViewController {
int status = argMap["status"];
String responseURL = argMap["responseURL"];
String responseType = argMap["responseType"];
dynamic response = argMap["response"];
String responseText = argMap["responseText"];
String responseXML = argMap["responseXML"];
String statusText = argMap["statusText"];
Map<dynamic, dynamic> responseHeaders = argMap["responseHeaders"];
var request = new AjaxRequest(data: data, method: method, url: url, isAsync: isAsync, user: user, password: password,
withCredentials: withCredentials, headers: headers, readyState: AjaxRequestReadyState.fromValue(readyState), status: status, responseURL: responseURL,
responseType: responseType, responseText: responseText, statusText: statusText, responseHeaders: responseHeaders);
responseType: responseType, response: response, responseText: responseText, responseXML: responseXML, statusText: statusText, responseHeaders: responseHeaders);
if (_widget != null && _widget.onAjaxReadyStateChange != null)
return jsonEncode(await _widget.onAjaxReadyStateChange(this, request));
......@@ -627,7 +630,9 @@ class InAppWebViewController {
int status = argMap["status"];
String responseURL = argMap["responseURL"];
String responseType = argMap["responseType"];
dynamic response = argMap["response"];
String responseText = argMap["responseText"];
String responseXML = argMap["responseXML"];
String statusText = argMap["statusText"];
Map<dynamic, dynamic> responseHeaders = argMap["responseHeaders"];
Map<dynamic, dynamic> eventMap = argMap["event"];
......@@ -636,7 +641,7 @@ class InAppWebViewController {
var request = new AjaxRequest(data: data, method: method, url: url, isAsync: isAsync, user: user, password: password,
withCredentials: withCredentials, headers: headers, readyState: AjaxRequestReadyState.fromValue(readyState), status: status, responseURL: responseURL,
responseType: responseType, responseText: responseText, statusText: statusText, responseHeaders: responseHeaders, event: event);
responseType: responseType, response: response, responseText: responseText, responseXML: responseXML, statusText: statusText, responseHeaders: responseHeaders, event: event);
if (_widget != null && _widget.onAjaxProgress != null)
return jsonEncode(await _widget.onAjaxProgress(this, request));
......@@ -1106,14 +1111,6 @@ class InAppWebViewController {
///The JavaScript function that can be used to call the handler is `window.flutter_inappbrowser.callHandler(handlerName <String>, ...args)`, where `args` are [rest parameters](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/rest_parameters).
///The `args` will be stringified automatically using `JSON.stringify(args)` method and then they will be decoded on the Dart side.
///
///In order to call `window.flutter_inappbrowser.callHandler(handlerName <String>, ...args)` properly, you need to wait and listen the JavaScript event `flutterInAppBrowserPlatformReady`.
///This event will be dispatch as soon as the platform (Android or iOS) is ready to handle the `callHandler` method.
///```javascript
/// window.addEventListener("flutterInAppBrowserPlatformReady", function(event) {
/// console.log("ready");
/// });
///```
///
///`window.flutter_inappbrowser.callHandler` returns a JavaScript [Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise)
///that can be used to get the json result returned by [JavaScriptHandlerCallback].
///In this case, simply return data that you want to send and it will be automatically json encoded using [jsonEncode] from the `dart:convert` library.
......@@ -1121,7 +1118,6 @@ class InAppWebViewController {
///So, on the JavaScript side, to get data coming from the Dart side, you will use:
///```html
///<script>
/// window.addEventListener("flutterInAppBrowserPlatformReady", function(event) {
/// window.flutter_inappbrowser.callHandler('handlerFoo').then(function(result) {
/// console.log(result, typeof result);
/// console.log(JSON.stringify(result));
......@@ -1131,19 +1127,8 @@ class InAppWebViewController {
/// console.log(result, typeof result);
/// console.log(JSON.stringify(result));
/// });
/// });
///</script>
///```
///
///Instead, on the `onLoadStop` WebView event, you can use `callHandler` directly:
///```dart
/// // Inject JavaScript that will receive data back from Flutter
/// inAppWebViewController.injectScriptCode("""
/// window.flutter_inappbrowser.callHandler('test', 'Text from Javascript').then(function(result) {
/// console.log(result);
/// });
/// """);
///```
void addJavaScriptHandler({@required String handlerName, @required JavaScriptHandlerCallback callback}) {
assert(!javaScriptHandlerForbiddenNames.contains(handlerName));
this.javaScriptHandlersMap[handlerName] = (callback);
......
......@@ -938,7 +938,7 @@ class AjaxRequestReadyState {
///AjaxRequest class represents a JavaScript [XMLHttpRequest](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest) object.
class AjaxRequest {
///Data passed to as a parameter to the `XMLHttpRequest.send()` method.
///Data passed as a parameter to the `XMLHttpRequest.send()` method.
dynamic data;
///The HTTP request method of the `XMLHttpRequest` request.
String method;
......@@ -969,8 +969,12 @@ class AjaxRequest {
///It also lets the author change the [response type](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/responseType).
///If an empty string is set as the value of responseType, the default value of text is used.
String responseType;
///The response's body content. The content-type depends on the [AjaxRequest.reponseType].
dynamic response;
///The text received from a server following a request being sent.
String responseText;
///The HTML or XML string retrieved by the request or null if the request was unsuccessful, has not yet been sent, or if the data can't be parsed as XML or HTML.
String responseXML;
///A String containing the response's status message as returned by the HTTP server.
///Unlike [AjaxRequest.status] which indicates a numerical status code, this property contains the text of the response status, such as "OK" or "Not Found".
///If the request's readyState is in [AjaxRequestReadyState.UNSENT] or [AjaxRequestReadyState.OPENED] state, the value of statusText will be an empty string.
......@@ -985,7 +989,7 @@ class AjaxRequest {
AjaxRequest({this.data, this.method, this.url, this.isAsync, this.user, this.password,
this.withCredentials, this.headers, this.readyState, this.status, this.responseURL, this.responseType,
this.responseText, this.statusText, this.responseHeaders, this.event, this.action = AjaxRequestAction.PROCEED});
this.response, this.responseText, this.responseXML, this.statusText, this.responseHeaders, this.event, this.action = AjaxRequestAction.PROCEED});
Map<String, dynamic> toMap() {
return {
......@@ -1001,7 +1005,9 @@ class AjaxRequest {
"status": status,
"responseURL": responseURL,
"responseType": responseType,
"response": response,
"responseText": responseText,
"responseXML": responseXML,
"statusText": statusText,
"responseHeaders": responseHeaders,
"action": action?.toValue()
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment