244 lines
9.5 KiB
Swift
244 lines
9.5 KiB
Swift
//
|
|
// javaScriptBridgeJS.swift
|
|
// flutter_inappwebview
|
|
//
|
|
// Created by Lorenzo Pichilli on 16/02/21.
|
|
//
|
|
|
|
import Foundation
|
|
|
|
let JAVASCRIPT_BRIDGE_NAME = "flutter_inappwebview"
|
|
let JAVASCRIPT_BRIDGE_JS_PLUGIN_SCRIPT_GROUP_NAME = "IN_APP_WEBVIEW_JAVASCRIPT_BRIDGE_JS_PLUGIN_SCRIPT"
|
|
|
|
let JAVASCRIPT_BRIDGE_JS_PLUGIN_SCRIPT = PluginScript(
|
|
groupName: JAVASCRIPT_BRIDGE_JS_PLUGIN_SCRIPT_GROUP_NAME,
|
|
source: JAVASCRIPT_BRIDGE_JS_SOURCE,
|
|
injectionTime: .atDocumentStart,
|
|
forMainFrameOnly: false,
|
|
requiredInAllContentWorlds: true,
|
|
messageHandlerNames: ["callHandler"])
|
|
|
|
let JAVASCRIPT_BRIDGE_JS_SOURCE = """
|
|
window.\(JAVASCRIPT_BRIDGE_NAME) = {};
|
|
\(WEB_MESSAGE_CHANNELS_VARIABLE_NAME) = {};
|
|
window.\(JAVASCRIPT_BRIDGE_NAME).callHandler = function() {
|
|
var _windowId = \(WINDOW_ID_VARIABLE_JS_SOURCE);
|
|
var _callHandlerID = setTimeout(function(){});
|
|
window.webkit.messageHandlers['callHandler'].postMessage( {'handlerName': arguments[0], '_callHandlerID': _callHandlerID, 'args': JSON.stringify(Array.prototype.slice.call(arguments, 1)), '_windowId': _windowId} );
|
|
return new Promise(function(resolve, reject) {
|
|
window.\(JAVASCRIPT_BRIDGE_NAME)[_callHandlerID] = resolve;
|
|
});
|
|
};
|
|
\(WEB_MESSAGE_LISTENER_JS_SOURCE)
|
|
\(UTIL_JS_SOURCE)
|
|
"""
|
|
|
|
let PLATFORM_READY_JS_SOURCE = "window.dispatchEvent(new Event('flutterInAppWebViewPlatformReady'));";
|
|
|
|
let JAVASCRIPT_UTIL_VAR_NAME = "window.\(JAVASCRIPT_BRIDGE_NAME)._Util"
|
|
|
|
/*
|
|
https://github.com/github/fetch/blob/master/fetch.js
|
|
*/
|
|
let UTIL_JS_SOURCE = """
|
|
\(JAVASCRIPT_UTIL_VAR_NAME) = {
|
|
support: {
|
|
searchParams: 'URLSearchParams' in window,
|
|
iterable: 'Symbol' in window && 'iterator' in Symbol,
|
|
blob:
|
|
'FileReader' in window &&
|
|
'Blob' in window &&
|
|
(function() {
|
|
try {
|
|
new Blob();
|
|
return true;
|
|
} catch (e) {
|
|
return false;
|
|
}
|
|
})(),
|
|
formData: 'FormData' in window,
|
|
arrayBuffer: 'ArrayBuffer' in window
|
|
},
|
|
isDataView: function(obj) {
|
|
return obj && DataView.prototype.isPrototypeOf(obj);
|
|
},
|
|
fileReaderReady: function(reader) {
|
|
return new Promise(function(resolve, reject) {
|
|
reader.onload = function() {
|
|
resolve(reader.result);
|
|
};
|
|
reader.onerror = function() {
|
|
reject(reader.error);
|
|
};
|
|
});
|
|
},
|
|
readBlobAsArrayBuffer: function(blob) {
|
|
var reader = new FileReader();
|
|
var promise = \(JAVASCRIPT_UTIL_VAR_NAME).fileReaderReady(reader);
|
|
reader.readAsArrayBuffer(blob);
|
|
return promise;
|
|
},
|
|
convertBodyToArrayBuffer: function(body) {
|
|
var viewClasses = [
|
|
'[object Int8Array]',
|
|
'[object Uint8Array]',
|
|
'[object Uint8ClampedArray]',
|
|
'[object Int16Array]',
|
|
'[object Uint16Array]',
|
|
'[object Int32Array]',
|
|
'[object Uint32Array]',
|
|
'[object Float32Array]',
|
|
'[object Float64Array]'
|
|
];
|
|
var isArrayBufferView = null;
|
|
if (\(JAVASCRIPT_UTIL_VAR_NAME).support.arrayBuffer) {
|
|
isArrayBufferView =
|
|
ArrayBuffer.isView ||
|
|
function(obj) {
|
|
return obj && viewClasses.indexOf(Object.prototype.toString.call(obj)) > -1;
|
|
};
|
|
}
|
|
|
|
var bodyUsed = false;
|
|
|
|
this._bodyInit = body;
|
|
if (!body) {
|
|
this._bodyText = '';
|
|
} else if (typeof body === 'string') {
|
|
this._bodyText = body;
|
|
} else if (\(JAVASCRIPT_UTIL_VAR_NAME).support.blob && Blob.prototype.isPrototypeOf(body)) {
|
|
this._bodyBlob = body;
|
|
} else if (\(JAVASCRIPT_UTIL_VAR_NAME).support.formData && FormData.prototype.isPrototypeOf(body)) {
|
|
this._bodyFormData = body;
|
|
} else if (\(JAVASCRIPT_UTIL_VAR_NAME).support.searchParams && URLSearchParams.prototype.isPrototypeOf(body)) {
|
|
this._bodyText = body.toString();
|
|
} else if (\(JAVASCRIPT_UTIL_VAR_NAME).support.arrayBuffer && \(JAVASCRIPT_UTIL_VAR_NAME).support.blob && \(JAVASCRIPT_UTIL_VAR_NAME).isDataView(body)) {
|
|
this._bodyArrayBuffer = bufferClone(body.buffer);
|
|
this._bodyInit = new Blob([this._bodyArrayBuffer]);
|
|
} else if (\(JAVASCRIPT_UTIL_VAR_NAME).support.arrayBuffer && (ArrayBuffer.prototype.isPrototypeOf(body) || isArrayBufferView(body))) {
|
|
this._bodyArrayBuffer = bufferClone(body);
|
|
} else {
|
|
this._bodyText = body = Object.prototype.toString.call(body);
|
|
}
|
|
|
|
this.blob = function () {
|
|
if (bodyUsed) {
|
|
return Promise.reject(new TypeError('Already read'));
|
|
}
|
|
bodyUsed = true;
|
|
if (this._bodyBlob) {
|
|
return Promise.resolve(this._bodyBlob);
|
|
} else if (this._bodyArrayBuffer) {
|
|
return Promise.resolve(new Blob([this._bodyArrayBuffer]));
|
|
} else if (this._bodyFormData) {
|
|
throw new Error('could not read FormData body as blob');
|
|
} else {
|
|
return Promise.resolve(new Blob([this._bodyText]));
|
|
}
|
|
};
|
|
|
|
if (this._bodyArrayBuffer) {
|
|
if (bodyUsed) {
|
|
return Promise.reject(new TypeError('Already read'));
|
|
}
|
|
bodyUsed = true;
|
|
if (ArrayBuffer.isView(this._bodyArrayBuffer)) {
|
|
return Promise.resolve(
|
|
this._bodyArrayBuffer.buffer.slice(
|
|
this._bodyArrayBuffer.byteOffset,
|
|
this._bodyArrayBuffer.byteOffset + this._bodyArrayBuffer.byteLength
|
|
)
|
|
);
|
|
} else {
|
|
return Promise.resolve(this._bodyArrayBuffer);
|
|
}
|
|
}
|
|
return this.blob().then(\(JAVASCRIPT_UTIL_VAR_NAME).readBlobAsArrayBuffer);
|
|
},
|
|
isString: function(variable) {
|
|
return typeof variable === 'string' || variable instanceof String;
|
|
},
|
|
convertBodyRequest: function(body) {
|
|
if (body == null) {
|
|
return new Promise((resolve, reject) => resolve(null));
|
|
}
|
|
if (\(JAVASCRIPT_UTIL_VAR_NAME).isString(body) || (\(JAVASCRIPT_UTIL_VAR_NAME).support.searchParams && body instanceof URLSearchParams)) {
|
|
return new Promise((resolve, reject) => resolve(body.toString()));
|
|
}
|
|
if (window.Response != null) {
|
|
return new Response(body).arrayBuffer().then(function(arrayBuffer) {
|
|
return Array.from(new Uint8Array(arrayBuffer));
|
|
});
|
|
}
|
|
return \(JAVASCRIPT_UTIL_VAR_NAME).convertBodyToArrayBuffer(body).then(function(arrayBuffer) {
|
|
return Array.from(new Uint8Array(arrayBuffer));
|
|
});
|
|
},
|
|
arrayBufferToString: function(arrayBuffer) {
|
|
var uint8Array = new Uint8Array(arrayBuffer);
|
|
return uint8Array.reduce(function(acc, i) { return acc += String.fromCharCode.apply(null, [i]); }, '');
|
|
},
|
|
isBodyFormData: function(bodyString) {
|
|
return bodyString.indexOf('------WebKitFormBoundary') >= 0;
|
|
},
|
|
getFormDataContentType: function(bodyString) {
|
|
var boundary = bodyString.substr(2, 40);
|
|
return 'multipart/form-data; boundary=' + boundary;
|
|
},
|
|
convertHeadersToJson: function(headers) {
|
|
var headersObj = {};
|
|
for (var header of headers.keys()) {
|
|
var value = headers.get(header);
|
|
headersObj[header] = value;
|
|
}
|
|
return headersObj;
|
|
},
|
|
convertJsonToHeaders: function(headersJson) {
|
|
return new Headers(headersJson);
|
|
},
|
|
convertCredentialsToJson: function(credentials) {
|
|
var credentialsObj = {};
|
|
if (window.FederatedCredential != null && credentials instanceof FederatedCredential) {
|
|
credentialsObj.type = credentials.type;
|
|
credentialsObj.id = credentials.id;
|
|
credentialsObj.name = credentials.name;
|
|
credentialsObj.protocol = credentials.protocol;
|
|
credentialsObj.provider = credentials.provider;
|
|
credentialsObj.iconURL = credentials.iconURL;
|
|
} else if (window.PasswordCredential != null && credentials instanceof PasswordCredential) {
|
|
credentialsObj.type = credentials.type;
|
|
credentialsObj.id = credentials.id;
|
|
credentialsObj.name = credentials.name;
|
|
credentialsObj.password = credentials.password;
|
|
credentialsObj.iconURL = credentials.iconURL;
|
|
} else {
|
|
credentialsObj.type = 'default';
|
|
credentialsObj.value = credentials;
|
|
}
|
|
return credentialsObj;
|
|
},
|
|
convertJsonToCredential: function(credentialsJson) {
|
|
var credentials;
|
|
if (window.FederatedCredential != null && credentialsJson.type === 'federated') {
|
|
credentials = new FederatedCredential({
|
|
id: credentialsJson.id,
|
|
name: credentialsJson.name,
|
|
protocol: credentialsJson.protocol,
|
|
provider: credentialsJson.provider,
|
|
iconURL: credentialsJson.iconURL
|
|
});
|
|
} else if (window.PasswordCredential != null && credentialsJson.type === 'password') {
|
|
credentials = new PasswordCredential({
|
|
id: credentialsJson.id,
|
|
name: credentialsJson.name,
|
|
password: credentialsJson.password,
|
|
iconURL: credentialsJson.iconURL
|
|
});
|
|
} else {
|
|
credentials = credentialsJson.value == null ? undefined : credentialsJson.value;
|
|
}
|
|
return credentials;
|
|
}
|
|
};
|
|
"""
|