这个想法是在将包含潜在复杂JavaScript和HTML的Web视图加载到WKWebView之前,将IOS本机代码加载到javascript桥文件中。此javascript桥将覆盖XMLHttpRequst对象上的open(),send(),fetch()和相关方法,以通过IOS本机代码而不是直接通过XHR路由所有Http通信。如果请求是异步的,则当准备好返回响应时,将创建一个Promise并由IOS本机代码调用resolvePromise()。
XMLHttpRequest.prototype.send = function(data) {
console.log("Overriden ajax ::XMLHttpRequest.prototype.send:", arguments);
console.log('uri',this.uri);
console.log("xhrObj::", this);
if(!this.uri) {
return this.realSend.apply(this, arguments);
}
// generate a unique id to reference the promise later from native function
var promiseId = generateUUID();
updateReadyState(this, 2);
delegateHttpToNativeWithPromise(promiseId, this, this.uri, this.httpMethod, data)
.then(function(responseWrapper) {
console.log('send resolve() - promise returned with responseWrapper', responseWrapper);
updateReadyState(responseWrapper.xhrObj, 3)
updateReadyState(responseWrapper.xhrObj, 4)
return responseWrapper.response;
}, function(xhrObj) {
console.log('send reject() - promise errorred with responseWrapper', responseWrapper);
updateReadyState(responseWrapper.xhrObj, 3)
updateReadyState(responseWrapper.xhrObj, 4)
return responseWrapper.response;
});
}
function delegateHttpToNativeWithPromise(promiseId, xhrObject, relativeIBAuthUri, methodType, payload) {
var promise = new Promise(function(resolve, reject) {
methodType = methodType || "get";
// save reference to promise in the global variable
promises[promiseId] = { resolve, reject, xhrObject };
try {
// call native function
if(window.webkit) {
window.webkit.messageHandlers.nativeNetwork.postMessage({
promiseId: promiseId,
apiUri: relativeIBAuthUri,
methodType: methodType,
requestHeaders : requestHeaders,
payload: payload});
}
requestHeaders = [];
}
catch(exception) {
console.error(exception)
// handle it somehow
}
});
return promise;
}
function resolvePromise(promiseId, status, headers, encodedResponse, error) {
var response = atob(encodedResponse);
if(promises[promiseId]) {
var xhrObj = promises[promiseId].xhrObject || null;
if(xhrObj != null) {
setReadOnlyProperty(xhrObj, "response", response);
setReadOnlyProperty(xhrObj, "responseText", response);
setReadOnlyProperty(xhrObj, "status", status);
setReadOnlyProperty(xhrObj, "statusText", "OK");
setReadOnlyProperty(xhrObj, "responseHeaders",headers);
}
if (error){
console.log('resolvePromise - error', error);
promises[promiseId].reject({response: response, xhrObj:xhrObj});
} else{
console.log('resolvePromise - success, resolving...');
promises[promiseId].resolve({response: response, xhrObj:xhrObj});
}
// remove reference to stored promise
delete promises[promiseId];
}
else {
console.log('promiseId not found in ', promises);
}
}
XMLHttpRequest.prototype.getResponseHeader = function(header) {
console.log('getResponseHeader', this);
if(!this.responseHeaders || this.responseHeaders == null) {
return null;
}
return this.responseHeaders[header];
}
XMLHttpRequest.prototype.getAllResponseHeaders = function() {
if(!this.responseHeaders || this.responseHeaders == null) {
return "";
}
var response = "";
for(header in this.responseHeaders) {
response += header+": "+this.responseHeaders[header]+"\r\n";
}
console.log('getAllResponseHeaders',response);
return response;
}
是否可以成功覆盖所有这些方法?我的最初发现表明不可以,因为原生XHR方法的复杂性无法用Javascript复制。