@capgo/inappbrowser 8.2.0 → 8.3.0-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +110 -28
- package/android/src/main/assets/proxy-bridge.js +197 -0
- package/android/src/main/java/ee/forgr/capacitor_inappbrowser/InAppBrowserPlugin.java +29 -26
- package/android/src/main/java/ee/forgr/capacitor_inappbrowser/Options.java +5 -7
- package/android/src/main/java/ee/forgr/capacitor_inappbrowser/ProxyBridge.java +60 -0
- package/android/src/main/java/ee/forgr/capacitor_inappbrowser/WebViewCallbacks.java +2 -0
- package/android/src/main/java/ee/forgr/capacitor_inappbrowser/WebViewDialog.java +262 -165
- package/dist/docs.json +150 -3
- package/dist/esm/definitions.d.ts +65 -3
- package/dist/esm/definitions.js.map +1 -1
- package/dist/esm/index.d.ts +20 -2
- package/dist/esm/index.js +79 -1
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/web.d.ts +1 -0
- package/dist/esm/web.js +4 -0
- package/dist/esm/web.js.map +1 -1
- package/dist/plugin.cjs.js +83 -0
- package/dist/plugin.cjs.js.map +1 -1
- package/dist/plugin.js +83 -0
- package/dist/plugin.js.map +1 -1
- package/ios/Sources/InAppBrowserPlugin/InAppBrowserPlugin.swift +64 -1
- package/ios/Sources/InAppBrowserPlugin/ProxySchemeHandler.swift +233 -0
- package/ios/Sources/InAppBrowserPlugin/WKWebView+SchemeHandling.swift +53 -0
- package/ios/Sources/InAppBrowserPlugin/WKWebViewController.swift +18 -1
- package/package.json +4 -2
package/dist/plugin.cjs.js
CHANGED
|
@@ -45,6 +45,84 @@ exports.InvisibilityMode = void 0;
|
|
|
45
45
|
const InAppBrowser = core.registerPlugin('InAppBrowser', {
|
|
46
46
|
web: () => Promise.resolve().then(function () { return web; }).then((m) => new m.InAppBrowserWeb()),
|
|
47
47
|
});
|
|
48
|
+
function arrayBufferToBase64(buffer) {
|
|
49
|
+
const bytes = new Uint8Array(buffer);
|
|
50
|
+
let binary = '';
|
|
51
|
+
for (let i = 0; i < bytes.byteLength; i++) {
|
|
52
|
+
binary += String.fromCharCode(bytes[i]);
|
|
53
|
+
}
|
|
54
|
+
return btoa(binary);
|
|
55
|
+
}
|
|
56
|
+
function headersToRecord(headers) {
|
|
57
|
+
const result = {};
|
|
58
|
+
headers.forEach((value, key) => {
|
|
59
|
+
result[key] = value;
|
|
60
|
+
});
|
|
61
|
+
return result;
|
|
62
|
+
}
|
|
63
|
+
function isProxyResponse(obj) {
|
|
64
|
+
return obj !== null && typeof obj === 'object' && 'status' in obj && 'headers' in obj && !(obj instanceof Response);
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Register a handler that intercepts all HTTP/HTTPS requests from the in-app browser webview.
|
|
68
|
+
*
|
|
69
|
+
* The callback receives a {@link ProxyRequest} for every request and must return one of:
|
|
70
|
+
* - A {@link ProxyResponse} object (recommended — use with CapacitorHttp for CORS-free fetching)
|
|
71
|
+
* - A fetch `Response` object
|
|
72
|
+
* - `null` to let the request pass through to its original destination
|
|
73
|
+
*
|
|
74
|
+
* **Platform note (Android):** Requests initiated directly by HTML elements (`<img>`,
|
|
75
|
+
* `<script>`, `<link>`, `<iframe>`, etc.) are intercepted via `shouldInterceptRequest`,
|
|
76
|
+
* which does not expose the request body. These requests will have an empty `body` field.
|
|
77
|
+
* In practice this only affects direct resource loads, which are always GET. Requests made
|
|
78
|
+
* via `fetch()` or `XMLHttpRequest` go through the JS bridge and include the full body.
|
|
79
|
+
*
|
|
80
|
+
* @since 9.0.0
|
|
81
|
+
*/
|
|
82
|
+
const addProxyHandler = (callback) => {
|
|
83
|
+
return InAppBrowser.addListener('proxyRequest', async (event) => {
|
|
84
|
+
try {
|
|
85
|
+
const result = await callback(event);
|
|
86
|
+
if (result === null) {
|
|
87
|
+
await InAppBrowser.handleProxyRequest({
|
|
88
|
+
requestId: event.requestId,
|
|
89
|
+
webviewId: event.webviewId,
|
|
90
|
+
response: null,
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
else if (isProxyResponse(result)) {
|
|
94
|
+
// ProxyResponse returned directly (e.g. from CapacitorHttp)
|
|
95
|
+
await InAppBrowser.handleProxyRequest({
|
|
96
|
+
requestId: event.requestId,
|
|
97
|
+
webviewId: event.webviewId,
|
|
98
|
+
response: result,
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
else {
|
|
102
|
+
// fetch Response object
|
|
103
|
+
const cloned = result.clone();
|
|
104
|
+
const buffer = await cloned.arrayBuffer();
|
|
105
|
+
const base64Body = arrayBufferToBase64(buffer);
|
|
106
|
+
await InAppBrowser.handleProxyRequest({
|
|
107
|
+
requestId: event.requestId,
|
|
108
|
+
webviewId: event.webviewId,
|
|
109
|
+
response: {
|
|
110
|
+
body: base64Body,
|
|
111
|
+
status: result.status,
|
|
112
|
+
headers: headersToRecord(result.headers),
|
|
113
|
+
},
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
catch (_e) {
|
|
118
|
+
await InAppBrowser.handleProxyRequest({
|
|
119
|
+
requestId: event.requestId,
|
|
120
|
+
webviewId: event.webviewId,
|
|
121
|
+
response: null,
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
});
|
|
125
|
+
};
|
|
48
126
|
|
|
49
127
|
class InAppBrowserWeb extends core.WebPlugin {
|
|
50
128
|
clearAllCookies() {
|
|
@@ -106,6 +184,10 @@ class InAppBrowserWeb extends core.WebPlugin {
|
|
|
106
184
|
async getPluginVersion() {
|
|
107
185
|
return { version: 'web' };
|
|
108
186
|
}
|
|
187
|
+
async handleProxyRequest() {
|
|
188
|
+
// No-op on web
|
|
189
|
+
return;
|
|
190
|
+
}
|
|
109
191
|
async updateDimensions(options) {
|
|
110
192
|
console.log('updateDimensions', options);
|
|
111
193
|
// Web platform doesn't support dimension control
|
|
@@ -152,4 +234,5 @@ var web = /*#__PURE__*/Object.freeze({
|
|
|
152
234
|
});
|
|
153
235
|
|
|
154
236
|
exports.InAppBrowser = InAppBrowser;
|
|
237
|
+
exports.addProxyHandler = addProxyHandler;
|
|
155
238
|
//# sourceMappingURL=plugin.cjs.js.map
|
package/dist/plugin.cjs.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugin.cjs.js","sources":["esm/definitions.js","esm/index.js","esm/web.js"],"sourcesContent":["export var BackgroundColor;\n(function (BackgroundColor) {\n BackgroundColor[\"WHITE\"] = \"white\";\n BackgroundColor[\"BLACK\"] = \"black\";\n})(BackgroundColor || (BackgroundColor = {}));\nexport var ToolBarType;\n(function (ToolBarType) {\n /**\n * Shows a simple toolbar with just a close button and share button\n * @since 0.1.0\n */\n ToolBarType[\"ACTIVITY\"] = \"activity\";\n /**\n * Shows a simple toolbar with just a close button\n * @since 7.6.8\n */\n ToolBarType[\"COMPACT\"] = \"compact\";\n /**\n * Shows a full navigation toolbar with back/forward buttons\n * @since 0.1.0\n */\n ToolBarType[\"NAVIGATION\"] = \"navigation\";\n /**\n * Shows no toolbar\n * @since 0.1.0\n */\n ToolBarType[\"BLANK\"] = \"blank\";\n})(ToolBarType || (ToolBarType = {}));\nexport var InvisibilityMode;\n(function (InvisibilityMode) {\n /**\n * WebView is aware it is hidden (dimensions may be zero).\n */\n InvisibilityMode[\"AWARE\"] = \"AWARE\";\n /**\n * WebView is hidden but reports fullscreen dimensions (uses alpha=0 to remain invisible).\n */\n InvisibilityMode[\"FAKE_VISIBLE\"] = \"FAKE_VISIBLE\";\n})(InvisibilityMode || (InvisibilityMode = {}));\n//# sourceMappingURL=definitions.js.map","import { registerPlugin } from '@capacitor/core';\nconst InAppBrowser = registerPlugin('InAppBrowser', {\n web: () => import('./web').then((m) => new m.InAppBrowserWeb()),\n});\nexport * from './definitions';\nexport { InAppBrowser };\n//# sourceMappingURL=index.js.map","import { WebPlugin } from '@capacitor/core';\nexport class InAppBrowserWeb extends WebPlugin {\n clearAllCookies() {\n console.log('clearAllCookies');\n return Promise.resolve();\n }\n clearCache() {\n console.log('clearCache');\n return Promise.resolve();\n }\n async open(options) {\n console.log('open', options);\n return options;\n }\n async clearCookies(options) {\n console.log('cleanCookies', options);\n return;\n }\n async getCookies(options) {\n // Web implementation to get cookies\n return options;\n }\n async openWebView(options) {\n console.log('openWebView', options);\n return options;\n }\n async executeScript({ code }) {\n console.log('code', code);\n return code;\n }\n async close() {\n console.log('close');\n return;\n }\n async hide() {\n console.log('hide');\n return;\n }\n async show() {\n console.log('show');\n return;\n }\n async setUrl(options) {\n console.log('setUrl', options.url);\n return;\n }\n async reload() {\n console.log('reload');\n return;\n }\n async postMessage(options) {\n console.log('postMessage', options);\n return options;\n }\n async goBack() {\n console.log('goBack');\n return;\n }\n async getPluginVersion() {\n return { version: 'web' };\n }\n async updateDimensions(options) {\n console.log('updateDimensions', options);\n // Web platform doesn't support dimension control\n return;\n }\n async openSecureWindow(options) {\n const w = 600;\n const h = 550;\n const settings = [\n ['width', w],\n ['height', h],\n ['left', screen.width / 2 - w / 2],\n ['top', screen.height / 2 - h / 2],\n ]\n .map((x) => x.join('='))\n .join(',');\n const popup = window.open(options.authEndpoint, 'Authorization', settings);\n if (typeof popup.focus === 'function') {\n popup.focus();\n }\n return new Promise((resolve, reject) => {\n const bc = new BroadcastChannel(options.broadcastChannelName || 'oauth-channel');\n bc.addEventListener('message', (event) => {\n if (event.data.startsWith(options.redirectUri)) {\n bc.close();\n resolve({ redirectedUri: event.data });\n }\n else {\n bc.close();\n reject(new Error('Redirect URI does not match, expected ' + options.redirectUri + ' but got ' + event.data));\n }\n });\n setTimeout(() => {\n bc.close();\n reject(new Error('The sign-in flow timed out'));\n }, 5 * 60000);\n });\n }\n}\n//# sourceMappingURL=web.js.map"],"names":["BackgroundColor","ToolBarType","InvisibilityMode","registerPlugin","WebPlugin"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"plugin.cjs.js","sources":["esm/definitions.js","esm/index.js","esm/web.js"],"sourcesContent":["export var BackgroundColor;\n(function (BackgroundColor) {\n BackgroundColor[\"WHITE\"] = \"white\";\n BackgroundColor[\"BLACK\"] = \"black\";\n})(BackgroundColor || (BackgroundColor = {}));\nexport var ToolBarType;\n(function (ToolBarType) {\n /**\n * Shows a simple toolbar with just a close button and share button\n * @since 0.1.0\n */\n ToolBarType[\"ACTIVITY\"] = \"activity\";\n /**\n * Shows a simple toolbar with just a close button\n * @since 7.6.8\n */\n ToolBarType[\"COMPACT\"] = \"compact\";\n /**\n * Shows a full navigation toolbar with back/forward buttons\n * @since 0.1.0\n */\n ToolBarType[\"NAVIGATION\"] = \"navigation\";\n /**\n * Shows no toolbar\n * @since 0.1.0\n */\n ToolBarType[\"BLANK\"] = \"blank\";\n})(ToolBarType || (ToolBarType = {}));\nexport var InvisibilityMode;\n(function (InvisibilityMode) {\n /**\n * WebView is aware it is hidden (dimensions may be zero).\n */\n InvisibilityMode[\"AWARE\"] = \"AWARE\";\n /**\n * WebView is hidden but reports fullscreen dimensions (uses alpha=0 to remain invisible).\n */\n InvisibilityMode[\"FAKE_VISIBLE\"] = \"FAKE_VISIBLE\";\n})(InvisibilityMode || (InvisibilityMode = {}));\n//# sourceMappingURL=definitions.js.map","import { registerPlugin } from '@capacitor/core';\nconst InAppBrowser = registerPlugin('InAppBrowser', {\n web: () => import('./web').then((m) => new m.InAppBrowserWeb()),\n});\nfunction arrayBufferToBase64(buffer) {\n const bytes = new Uint8Array(buffer);\n let binary = '';\n for (let i = 0; i < bytes.byteLength; i++) {\n binary += String.fromCharCode(bytes[i]);\n }\n return btoa(binary);\n}\nfunction headersToRecord(headers) {\n const result = {};\n headers.forEach((value, key) => {\n result[key] = value;\n });\n return result;\n}\nfunction isProxyResponse(obj) {\n return obj !== null && typeof obj === 'object' && 'status' in obj && 'headers' in obj && !(obj instanceof Response);\n}\n/**\n * Register a handler that intercepts all HTTP/HTTPS requests from the in-app browser webview.\n *\n * The callback receives a {@link ProxyRequest} for every request and must return one of:\n * - A {@link ProxyResponse} object (recommended — use with CapacitorHttp for CORS-free fetching)\n * - A fetch `Response` object\n * - `null` to let the request pass through to its original destination\n *\n * **Platform note (Android):** Requests initiated directly by HTML elements (`<img>`,\n * `<script>`, `<link>`, `<iframe>`, etc.) are intercepted via `shouldInterceptRequest`,\n * which does not expose the request body. These requests will have an empty `body` field.\n * In practice this only affects direct resource loads, which are always GET. Requests made\n * via `fetch()` or `XMLHttpRequest` go through the JS bridge and include the full body.\n *\n * @since 9.0.0\n */\nconst addProxyHandler = (callback) => {\n return InAppBrowser.addListener('proxyRequest', async (event) => {\n try {\n const result = await callback(event);\n if (result === null) {\n await InAppBrowser.handleProxyRequest({\n requestId: event.requestId,\n webviewId: event.webviewId,\n response: null,\n });\n }\n else if (isProxyResponse(result)) {\n // ProxyResponse returned directly (e.g. from CapacitorHttp)\n await InAppBrowser.handleProxyRequest({\n requestId: event.requestId,\n webviewId: event.webviewId,\n response: result,\n });\n }\n else {\n // fetch Response object\n const cloned = result.clone();\n const buffer = await cloned.arrayBuffer();\n const base64Body = arrayBufferToBase64(buffer);\n await InAppBrowser.handleProxyRequest({\n requestId: event.requestId,\n webviewId: event.webviewId,\n response: {\n body: base64Body,\n status: result.status,\n headers: headersToRecord(result.headers),\n },\n });\n }\n }\n catch (_e) {\n await InAppBrowser.handleProxyRequest({\n requestId: event.requestId,\n webviewId: event.webviewId,\n response: null,\n });\n }\n });\n};\nexport * from './definitions';\nexport { InAppBrowser, addProxyHandler };\n//# sourceMappingURL=index.js.map","import { WebPlugin } from '@capacitor/core';\nexport class InAppBrowserWeb extends WebPlugin {\n clearAllCookies() {\n console.log('clearAllCookies');\n return Promise.resolve();\n }\n clearCache() {\n console.log('clearCache');\n return Promise.resolve();\n }\n async open(options) {\n console.log('open', options);\n return options;\n }\n async clearCookies(options) {\n console.log('cleanCookies', options);\n return;\n }\n async getCookies(options) {\n // Web implementation to get cookies\n return options;\n }\n async openWebView(options) {\n console.log('openWebView', options);\n return options;\n }\n async executeScript({ code }) {\n console.log('code', code);\n return code;\n }\n async close() {\n console.log('close');\n return;\n }\n async hide() {\n console.log('hide');\n return;\n }\n async show() {\n console.log('show');\n return;\n }\n async setUrl(options) {\n console.log('setUrl', options.url);\n return;\n }\n async reload() {\n console.log('reload');\n return;\n }\n async postMessage(options) {\n console.log('postMessage', options);\n return options;\n }\n async goBack() {\n console.log('goBack');\n return;\n }\n async getPluginVersion() {\n return { version: 'web' };\n }\n async handleProxyRequest() {\n // No-op on web\n return;\n }\n async updateDimensions(options) {\n console.log('updateDimensions', options);\n // Web platform doesn't support dimension control\n return;\n }\n async openSecureWindow(options) {\n const w = 600;\n const h = 550;\n const settings = [\n ['width', w],\n ['height', h],\n ['left', screen.width / 2 - w / 2],\n ['top', screen.height / 2 - h / 2],\n ]\n .map((x) => x.join('='))\n .join(',');\n const popup = window.open(options.authEndpoint, 'Authorization', settings);\n if (typeof popup.focus === 'function') {\n popup.focus();\n }\n return new Promise((resolve, reject) => {\n const bc = new BroadcastChannel(options.broadcastChannelName || 'oauth-channel');\n bc.addEventListener('message', (event) => {\n if (event.data.startsWith(options.redirectUri)) {\n bc.close();\n resolve({ redirectedUri: event.data });\n }\n else {\n bc.close();\n reject(new Error('Redirect URI does not match, expected ' + options.redirectUri + ' but got ' + event.data));\n }\n });\n setTimeout(() => {\n bc.close();\n reject(new Error('The sign-in flow timed out'));\n }, 5 * 60000);\n });\n }\n}\n//# sourceMappingURL=web.js.map"],"names":["BackgroundColor","ToolBarType","InvisibilityMode","registerPlugin","WebPlugin"],"mappings":"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"}
|
package/dist/plugin.js
CHANGED
|
@@ -44,6 +44,84 @@ var capacitorInAppBrowser = (function (exports, core) {
|
|
|
44
44
|
const InAppBrowser = core.registerPlugin('InAppBrowser', {
|
|
45
45
|
web: () => Promise.resolve().then(function () { return web; }).then((m) => new m.InAppBrowserWeb()),
|
|
46
46
|
});
|
|
47
|
+
function arrayBufferToBase64(buffer) {
|
|
48
|
+
const bytes = new Uint8Array(buffer);
|
|
49
|
+
let binary = '';
|
|
50
|
+
for (let i = 0; i < bytes.byteLength; i++) {
|
|
51
|
+
binary += String.fromCharCode(bytes[i]);
|
|
52
|
+
}
|
|
53
|
+
return btoa(binary);
|
|
54
|
+
}
|
|
55
|
+
function headersToRecord(headers) {
|
|
56
|
+
const result = {};
|
|
57
|
+
headers.forEach((value, key) => {
|
|
58
|
+
result[key] = value;
|
|
59
|
+
});
|
|
60
|
+
return result;
|
|
61
|
+
}
|
|
62
|
+
function isProxyResponse(obj) {
|
|
63
|
+
return obj !== null && typeof obj === 'object' && 'status' in obj && 'headers' in obj && !(obj instanceof Response);
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Register a handler that intercepts all HTTP/HTTPS requests from the in-app browser webview.
|
|
67
|
+
*
|
|
68
|
+
* The callback receives a {@link ProxyRequest} for every request and must return one of:
|
|
69
|
+
* - A {@link ProxyResponse} object (recommended — use with CapacitorHttp for CORS-free fetching)
|
|
70
|
+
* - A fetch `Response` object
|
|
71
|
+
* - `null` to let the request pass through to its original destination
|
|
72
|
+
*
|
|
73
|
+
* **Platform note (Android):** Requests initiated directly by HTML elements (`<img>`,
|
|
74
|
+
* `<script>`, `<link>`, `<iframe>`, etc.) are intercepted via `shouldInterceptRequest`,
|
|
75
|
+
* which does not expose the request body. These requests will have an empty `body` field.
|
|
76
|
+
* In practice this only affects direct resource loads, which are always GET. Requests made
|
|
77
|
+
* via `fetch()` or `XMLHttpRequest` go through the JS bridge and include the full body.
|
|
78
|
+
*
|
|
79
|
+
* @since 9.0.0
|
|
80
|
+
*/
|
|
81
|
+
const addProxyHandler = (callback) => {
|
|
82
|
+
return InAppBrowser.addListener('proxyRequest', async (event) => {
|
|
83
|
+
try {
|
|
84
|
+
const result = await callback(event);
|
|
85
|
+
if (result === null) {
|
|
86
|
+
await InAppBrowser.handleProxyRequest({
|
|
87
|
+
requestId: event.requestId,
|
|
88
|
+
webviewId: event.webviewId,
|
|
89
|
+
response: null,
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
else if (isProxyResponse(result)) {
|
|
93
|
+
// ProxyResponse returned directly (e.g. from CapacitorHttp)
|
|
94
|
+
await InAppBrowser.handleProxyRequest({
|
|
95
|
+
requestId: event.requestId,
|
|
96
|
+
webviewId: event.webviewId,
|
|
97
|
+
response: result,
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
else {
|
|
101
|
+
// fetch Response object
|
|
102
|
+
const cloned = result.clone();
|
|
103
|
+
const buffer = await cloned.arrayBuffer();
|
|
104
|
+
const base64Body = arrayBufferToBase64(buffer);
|
|
105
|
+
await InAppBrowser.handleProxyRequest({
|
|
106
|
+
requestId: event.requestId,
|
|
107
|
+
webviewId: event.webviewId,
|
|
108
|
+
response: {
|
|
109
|
+
body: base64Body,
|
|
110
|
+
status: result.status,
|
|
111
|
+
headers: headersToRecord(result.headers),
|
|
112
|
+
},
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
catch (_e) {
|
|
117
|
+
await InAppBrowser.handleProxyRequest({
|
|
118
|
+
requestId: event.requestId,
|
|
119
|
+
webviewId: event.webviewId,
|
|
120
|
+
response: null,
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
});
|
|
124
|
+
};
|
|
47
125
|
|
|
48
126
|
class InAppBrowserWeb extends core.WebPlugin {
|
|
49
127
|
clearAllCookies() {
|
|
@@ -105,6 +183,10 @@ var capacitorInAppBrowser = (function (exports, core) {
|
|
|
105
183
|
async getPluginVersion() {
|
|
106
184
|
return { version: 'web' };
|
|
107
185
|
}
|
|
186
|
+
async handleProxyRequest() {
|
|
187
|
+
// No-op on web
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
108
190
|
async updateDimensions(options) {
|
|
109
191
|
console.log('updateDimensions', options);
|
|
110
192
|
// Web platform doesn't support dimension control
|
|
@@ -151,6 +233,7 @@ var capacitorInAppBrowser = (function (exports, core) {
|
|
|
151
233
|
});
|
|
152
234
|
|
|
153
235
|
exports.InAppBrowser = InAppBrowser;
|
|
236
|
+
exports.addProxyHandler = addProxyHandler;
|
|
154
237
|
|
|
155
238
|
return exports;
|
|
156
239
|
|
package/dist/plugin.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugin.js","sources":["esm/definitions.js","esm/index.js","esm/web.js"],"sourcesContent":["export var BackgroundColor;\n(function (BackgroundColor) {\n BackgroundColor[\"WHITE\"] = \"white\";\n BackgroundColor[\"BLACK\"] = \"black\";\n})(BackgroundColor || (BackgroundColor = {}));\nexport var ToolBarType;\n(function (ToolBarType) {\n /**\n * Shows a simple toolbar with just a close button and share button\n * @since 0.1.0\n */\n ToolBarType[\"ACTIVITY\"] = \"activity\";\n /**\n * Shows a simple toolbar with just a close button\n * @since 7.6.8\n */\n ToolBarType[\"COMPACT\"] = \"compact\";\n /**\n * Shows a full navigation toolbar with back/forward buttons\n * @since 0.1.0\n */\n ToolBarType[\"NAVIGATION\"] = \"navigation\";\n /**\n * Shows no toolbar\n * @since 0.1.0\n */\n ToolBarType[\"BLANK\"] = \"blank\";\n})(ToolBarType || (ToolBarType = {}));\nexport var InvisibilityMode;\n(function (InvisibilityMode) {\n /**\n * WebView is aware it is hidden (dimensions may be zero).\n */\n InvisibilityMode[\"AWARE\"] = \"AWARE\";\n /**\n * WebView is hidden but reports fullscreen dimensions (uses alpha=0 to remain invisible).\n */\n InvisibilityMode[\"FAKE_VISIBLE\"] = \"FAKE_VISIBLE\";\n})(InvisibilityMode || (InvisibilityMode = {}));\n//# sourceMappingURL=definitions.js.map","import { registerPlugin } from '@capacitor/core';\nconst InAppBrowser = registerPlugin('InAppBrowser', {\n web: () => import('./web').then((m) => new m.InAppBrowserWeb()),\n});\nexport * from './definitions';\nexport { InAppBrowser };\n//# sourceMappingURL=index.js.map","import { WebPlugin } from '@capacitor/core';\nexport class InAppBrowserWeb extends WebPlugin {\n clearAllCookies() {\n console.log('clearAllCookies');\n return Promise.resolve();\n }\n clearCache() {\n console.log('clearCache');\n return Promise.resolve();\n }\n async open(options) {\n console.log('open', options);\n return options;\n }\n async clearCookies(options) {\n console.log('cleanCookies', options);\n return;\n }\n async getCookies(options) {\n // Web implementation to get cookies\n return options;\n }\n async openWebView(options) {\n console.log('openWebView', options);\n return options;\n }\n async executeScript({ code }) {\n console.log('code', code);\n return code;\n }\n async close() {\n console.log('close');\n return;\n }\n async hide() {\n console.log('hide');\n return;\n }\n async show() {\n console.log('show');\n return;\n }\n async setUrl(options) {\n console.log('setUrl', options.url);\n return;\n }\n async reload() {\n console.log('reload');\n return;\n }\n async postMessage(options) {\n console.log('postMessage', options);\n return options;\n }\n async goBack() {\n console.log('goBack');\n return;\n }\n async getPluginVersion() {\n return { version: 'web' };\n }\n async updateDimensions(options) {\n console.log('updateDimensions', options);\n // Web platform doesn't support dimension control\n return;\n }\n async openSecureWindow(options) {\n const w = 600;\n const h = 550;\n const settings = [\n ['width', w],\n ['height', h],\n ['left', screen.width / 2 - w / 2],\n ['top', screen.height / 2 - h / 2],\n ]\n .map((x) => x.join('='))\n .join(',');\n const popup = window.open(options.authEndpoint, 'Authorization', settings);\n if (typeof popup.focus === 'function') {\n popup.focus();\n }\n return new Promise((resolve, reject) => {\n const bc = new BroadcastChannel(options.broadcastChannelName || 'oauth-channel');\n bc.addEventListener('message', (event) => {\n if (event.data.startsWith(options.redirectUri)) {\n bc.close();\n resolve({ redirectedUri: event.data });\n }\n else {\n bc.close();\n reject(new Error('Redirect URI does not match, expected ' + options.redirectUri + ' but got ' + event.data));\n }\n });\n setTimeout(() => {\n bc.close();\n reject(new Error('The sign-in flow timed out'));\n }, 5 * 60000);\n });\n }\n}\n//# sourceMappingURL=web.js.map"],"names":["BackgroundColor","ToolBarType","InvisibilityMode","registerPlugin","WebPlugin"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"plugin.js","sources":["esm/definitions.js","esm/index.js","esm/web.js"],"sourcesContent":["export var BackgroundColor;\n(function (BackgroundColor) {\n BackgroundColor[\"WHITE\"] = \"white\";\n BackgroundColor[\"BLACK\"] = \"black\";\n})(BackgroundColor || (BackgroundColor = {}));\nexport var ToolBarType;\n(function (ToolBarType) {\n /**\n * Shows a simple toolbar with just a close button and share button\n * @since 0.1.0\n */\n ToolBarType[\"ACTIVITY\"] = \"activity\";\n /**\n * Shows a simple toolbar with just a close button\n * @since 7.6.8\n */\n ToolBarType[\"COMPACT\"] = \"compact\";\n /**\n * Shows a full navigation toolbar with back/forward buttons\n * @since 0.1.0\n */\n ToolBarType[\"NAVIGATION\"] = \"navigation\";\n /**\n * Shows no toolbar\n * @since 0.1.0\n */\n ToolBarType[\"BLANK\"] = \"blank\";\n})(ToolBarType || (ToolBarType = {}));\nexport var InvisibilityMode;\n(function (InvisibilityMode) {\n /**\n * WebView is aware it is hidden (dimensions may be zero).\n */\n InvisibilityMode[\"AWARE\"] = \"AWARE\";\n /**\n * WebView is hidden but reports fullscreen dimensions (uses alpha=0 to remain invisible).\n */\n InvisibilityMode[\"FAKE_VISIBLE\"] = \"FAKE_VISIBLE\";\n})(InvisibilityMode || (InvisibilityMode = {}));\n//# sourceMappingURL=definitions.js.map","import { registerPlugin } from '@capacitor/core';\nconst InAppBrowser = registerPlugin('InAppBrowser', {\n web: () => import('./web').then((m) => new m.InAppBrowserWeb()),\n});\nfunction arrayBufferToBase64(buffer) {\n const bytes = new Uint8Array(buffer);\n let binary = '';\n for (let i = 0; i < bytes.byteLength; i++) {\n binary += String.fromCharCode(bytes[i]);\n }\n return btoa(binary);\n}\nfunction headersToRecord(headers) {\n const result = {};\n headers.forEach((value, key) => {\n result[key] = value;\n });\n return result;\n}\nfunction isProxyResponse(obj) {\n return obj !== null && typeof obj === 'object' && 'status' in obj && 'headers' in obj && !(obj instanceof Response);\n}\n/**\n * Register a handler that intercepts all HTTP/HTTPS requests from the in-app browser webview.\n *\n * The callback receives a {@link ProxyRequest} for every request and must return one of:\n * - A {@link ProxyResponse} object (recommended — use with CapacitorHttp for CORS-free fetching)\n * - A fetch `Response` object\n * - `null` to let the request pass through to its original destination\n *\n * **Platform note (Android):** Requests initiated directly by HTML elements (`<img>`,\n * `<script>`, `<link>`, `<iframe>`, etc.) are intercepted via `shouldInterceptRequest`,\n * which does not expose the request body. These requests will have an empty `body` field.\n * In practice this only affects direct resource loads, which are always GET. Requests made\n * via `fetch()` or `XMLHttpRequest` go through the JS bridge and include the full body.\n *\n * @since 9.0.0\n */\nconst addProxyHandler = (callback) => {\n return InAppBrowser.addListener('proxyRequest', async (event) => {\n try {\n const result = await callback(event);\n if (result === null) {\n await InAppBrowser.handleProxyRequest({\n requestId: event.requestId,\n webviewId: event.webviewId,\n response: null,\n });\n }\n else if (isProxyResponse(result)) {\n // ProxyResponse returned directly (e.g. from CapacitorHttp)\n await InAppBrowser.handleProxyRequest({\n requestId: event.requestId,\n webviewId: event.webviewId,\n response: result,\n });\n }\n else {\n // fetch Response object\n const cloned = result.clone();\n const buffer = await cloned.arrayBuffer();\n const base64Body = arrayBufferToBase64(buffer);\n await InAppBrowser.handleProxyRequest({\n requestId: event.requestId,\n webviewId: event.webviewId,\n response: {\n body: base64Body,\n status: result.status,\n headers: headersToRecord(result.headers),\n },\n });\n }\n }\n catch (_e) {\n await InAppBrowser.handleProxyRequest({\n requestId: event.requestId,\n webviewId: event.webviewId,\n response: null,\n });\n }\n });\n};\nexport * from './definitions';\nexport { InAppBrowser, addProxyHandler };\n//# sourceMappingURL=index.js.map","import { WebPlugin } from '@capacitor/core';\nexport class InAppBrowserWeb extends WebPlugin {\n clearAllCookies() {\n console.log('clearAllCookies');\n return Promise.resolve();\n }\n clearCache() {\n console.log('clearCache');\n return Promise.resolve();\n }\n async open(options) {\n console.log('open', options);\n return options;\n }\n async clearCookies(options) {\n console.log('cleanCookies', options);\n return;\n }\n async getCookies(options) {\n // Web implementation to get cookies\n return options;\n }\n async openWebView(options) {\n console.log('openWebView', options);\n return options;\n }\n async executeScript({ code }) {\n console.log('code', code);\n return code;\n }\n async close() {\n console.log('close');\n return;\n }\n async hide() {\n console.log('hide');\n return;\n }\n async show() {\n console.log('show');\n return;\n }\n async setUrl(options) {\n console.log('setUrl', options.url);\n return;\n }\n async reload() {\n console.log('reload');\n return;\n }\n async postMessage(options) {\n console.log('postMessage', options);\n return options;\n }\n async goBack() {\n console.log('goBack');\n return;\n }\n async getPluginVersion() {\n return { version: 'web' };\n }\n async handleProxyRequest() {\n // No-op on web\n return;\n }\n async updateDimensions(options) {\n console.log('updateDimensions', options);\n // Web platform doesn't support dimension control\n return;\n }\n async openSecureWindow(options) {\n const w = 600;\n const h = 550;\n const settings = [\n ['width', w],\n ['height', h],\n ['left', screen.width / 2 - w / 2],\n ['top', screen.height / 2 - h / 2],\n ]\n .map((x) => x.join('='))\n .join(',');\n const popup = window.open(options.authEndpoint, 'Authorization', settings);\n if (typeof popup.focus === 'function') {\n popup.focus();\n }\n return new Promise((resolve, reject) => {\n const bc = new BroadcastChannel(options.broadcastChannelName || 'oauth-channel');\n bc.addEventListener('message', (event) => {\n if (event.data.startsWith(options.redirectUri)) {\n bc.close();\n resolve({ redirectedUri: event.data });\n }\n else {\n bc.close();\n reject(new Error('Redirect URI does not match, expected ' + options.redirectUri + ' but got ' + event.data));\n }\n });\n setTimeout(() => {\n bc.close();\n reject(new Error('The sign-in flow timed out'));\n }, 5 * 60000);\n });\n }\n}\n//# sourceMappingURL=web.js.map"],"names":["BackgroundColor","ToolBarType","InvisibilityMode","registerPlugin","WebPlugin"],"mappings":"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"}
|
|
@@ -29,7 +29,7 @@ public class InAppBrowserPlugin: CAPPlugin, CAPBridgedPlugin {
|
|
|
29
29
|
case aware = "AWARE"
|
|
30
30
|
case fakeVisible = "FAKE_VISIBLE"
|
|
31
31
|
}
|
|
32
|
-
private let pluginVersion: String = "8.
|
|
32
|
+
private let pluginVersion: String = "8.3.0-alpha.1"
|
|
33
33
|
public let identifier = "InAppBrowserPlugin"
|
|
34
34
|
public let jsName = "InAppBrowser"
|
|
35
35
|
public let pluginMethods: [CAPPluginMethod] = [
|
|
@@ -50,6 +50,7 @@ public class InAppBrowserPlugin: CAPPlugin, CAPBridgedPlugin {
|
|
|
50
50
|
CAPPluginMethod(name: "updateDimensions", returnType: CAPPluginReturnPromise),
|
|
51
51
|
CAPPluginMethod(name: "getPluginVersion", returnType: CAPPluginReturnPromise),
|
|
52
52
|
CAPPluginMethod(name: "openSecureWindow", returnType: CAPPluginReturnPromise),
|
|
53
|
+
CAPPluginMethod(name: "handleProxyRequest", returnType: CAPPluginReturnPromise),
|
|
53
54
|
]
|
|
54
55
|
var navigationWebViewController: UINavigationController?
|
|
55
56
|
private var navigationControllers: [String: UINavigationController] = [:]
|
|
@@ -61,6 +62,7 @@ public class InAppBrowserPlugin: CAPPlugin, CAPBridgedPlugin {
|
|
|
61
62
|
var invisibilityMode: InvisibilityMode = .aware
|
|
62
63
|
var webViewController: WKWebViewController?
|
|
63
64
|
private var webViewControllers: [String: WKWebViewController] = [:]
|
|
65
|
+
private var proxySchemeHandlers: [String: ProxySchemeHandler] = [:]
|
|
64
66
|
private var webViewStack: [String] = []
|
|
65
67
|
private var activeWebViewId: String?
|
|
66
68
|
private weak var presentationContainerView: UIView?
|
|
@@ -95,6 +97,8 @@ public class InAppBrowserPlugin: CAPPlugin, CAPBridgedPlugin {
|
|
|
95
97
|
}
|
|
96
98
|
|
|
97
99
|
private func unregisterWebView(id: String) {
|
|
100
|
+
proxySchemeHandlers[id]?.cancelAllPendingTasks()
|
|
101
|
+
proxySchemeHandlers[id] = nil
|
|
98
102
|
webViewControllers[id] = nil
|
|
99
103
|
navigationControllers[id] = nil
|
|
100
104
|
webViewStack.removeAll { $0 == id }
|
|
@@ -593,6 +597,9 @@ public class InAppBrowserPlugin: CAPPlugin, CAPBridgedPlugin {
|
|
|
593
597
|
// Read disableOverscroll option (iOS only - controls WebView bounce effect)
|
|
594
598
|
let disableOverscroll = call.getBool("disableOverscroll", false)
|
|
595
599
|
|
|
600
|
+
// Read proxy option
|
|
601
|
+
let proxyRequests = call.getBool("proxyRequests") ?? false
|
|
602
|
+
|
|
596
603
|
// Validate dimension parameters
|
|
597
604
|
if width != nil && height == nil {
|
|
598
605
|
call.reject("Height must be specified when width is provided")
|
|
@@ -605,6 +612,13 @@ public class InAppBrowserPlugin: CAPPlugin, CAPBridgedPlugin {
|
|
|
605
612
|
return
|
|
606
613
|
}
|
|
607
614
|
|
|
615
|
+
// Create proxy handler before init so it's available during initWebview()
|
|
616
|
+
var proxyHandler: ProxySchemeHandler? = nil
|
|
617
|
+
if proxyRequests {
|
|
618
|
+
proxyHandler = ProxySchemeHandler(plugin: self, webviewId: webViewId)
|
|
619
|
+
self.proxySchemeHandlers[webViewId] = proxyHandler!
|
|
620
|
+
}
|
|
621
|
+
|
|
608
622
|
self.webViewController = WKWebViewController.init(
|
|
609
623
|
url: url,
|
|
610
624
|
headers: headers,
|
|
@@ -616,6 +630,8 @@ public class InAppBrowserPlugin: CAPPlugin, CAPBridgedPlugin {
|
|
|
616
630
|
enabledSafeTopMargin: enabledSafeTopMargin,
|
|
617
631
|
blockedHosts: blockedHosts,
|
|
618
632
|
authorizedAppLinks: authorizedAppLinks,
|
|
633
|
+
proxyRequests: proxyRequests,
|
|
634
|
+
proxySchemeHandler: proxyHandler
|
|
619
635
|
)
|
|
620
636
|
|
|
621
637
|
guard let webViewController = self.webViewController else {
|
|
@@ -1231,6 +1247,53 @@ public class InAppBrowserPlugin: CAPPlugin, CAPBridgedPlugin {
|
|
|
1231
1247
|
}
|
|
1232
1248
|
}
|
|
1233
1249
|
|
|
1250
|
+
@objc func handleProxyRequest(_ call: CAPPluginCall) {
|
|
1251
|
+
guard let requestId = call.getString("requestId") else {
|
|
1252
|
+
call.reject("requestId is required")
|
|
1253
|
+
return
|
|
1254
|
+
}
|
|
1255
|
+
|
|
1256
|
+
let webviewId = call.getString("webviewId")
|
|
1257
|
+
let responseObj = call.getObject("response")
|
|
1258
|
+
|
|
1259
|
+
// Find the handler
|
|
1260
|
+
var handler: ProxySchemeHandler?
|
|
1261
|
+
if let webviewId = webviewId {
|
|
1262
|
+
handler = proxySchemeHandlers[webviewId]
|
|
1263
|
+
} else if proxySchemeHandlers.count == 1 {
|
|
1264
|
+
handler = proxySchemeHandlers.values.first
|
|
1265
|
+
} else if proxySchemeHandlers.count > 1 {
|
|
1266
|
+
print("[InAppBrowser] handleProxyRequest: webviewId is nil but \(proxySchemeHandlers.count) webviews are active — cannot determine target, aborting")
|
|
1267
|
+
call.reject("webviewId is required when multiple webviews are open")
|
|
1268
|
+
return
|
|
1269
|
+
}
|
|
1270
|
+
|
|
1271
|
+
guard let proxyHandler = handler else {
|
|
1272
|
+
call.reject("No proxy handler found")
|
|
1273
|
+
return
|
|
1274
|
+
}
|
|
1275
|
+
|
|
1276
|
+
var responseDict: [String: Any]? = nil
|
|
1277
|
+
if let responseObj = responseObj {
|
|
1278
|
+
var dict: [String: Any] = [:]
|
|
1279
|
+
dict["status"] = responseObj["status"]
|
|
1280
|
+
dict["body"] = responseObj["body"]
|
|
1281
|
+
if let headers = responseObj["headers"] as? JSObject {
|
|
1282
|
+
var headersDict: [String: String] = [:]
|
|
1283
|
+
for (key, value) in headers {
|
|
1284
|
+
if let strValue = value as? String {
|
|
1285
|
+
headersDict[key] = strValue
|
|
1286
|
+
}
|
|
1287
|
+
}
|
|
1288
|
+
dict["headers"] = headersDict
|
|
1289
|
+
}
|
|
1290
|
+
responseDict = dict
|
|
1291
|
+
}
|
|
1292
|
+
|
|
1293
|
+
proxyHandler.handleResponse(requestId: requestId, responseData: responseDict)
|
|
1294
|
+
call.resolve()
|
|
1295
|
+
}
|
|
1296
|
+
|
|
1234
1297
|
@objc func close(_ call: CAPPluginCall) {
|
|
1235
1298
|
let isAnimated = call.getBool("isAnimated", true)
|
|
1236
1299
|
|
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
import Foundation
|
|
2
|
+
import WebKit
|
|
3
|
+
import Capacitor
|
|
4
|
+
|
|
5
|
+
public class ProxySchemeHandler: NSObject, WKURLSchemeHandler {
|
|
6
|
+
weak var plugin: InAppBrowserPlugin?
|
|
7
|
+
private var pendingTasks: [String: WKURLSchemeTask] = [:]
|
|
8
|
+
private var pendingBodies: [String: Data] = [:]
|
|
9
|
+
private var activeTasks: [Int: (requestId: String, schemeTask: WKURLSchemeTask, dataTask: URLSessionDataTask)] = [:]
|
|
10
|
+
private var stoppedRequests: Set<String> = []
|
|
11
|
+
private let taskLock = NSLock()
|
|
12
|
+
private let webviewId: String
|
|
13
|
+
private let proxyTimeoutSeconds: TimeInterval = 10
|
|
14
|
+
|
|
15
|
+
private static var session: URLSession = {
|
|
16
|
+
return URLSession(configuration: .default)
|
|
17
|
+
}()
|
|
18
|
+
|
|
19
|
+
init(plugin: InAppBrowserPlugin, webviewId: String) {
|
|
20
|
+
self.plugin = plugin
|
|
21
|
+
self.webviewId = webviewId
|
|
22
|
+
super.init()
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
public func webView(_ webView: WKWebView, start urlSchemeTask: WKURLSchemeTask) {
|
|
26
|
+
let request = urlSchemeTask.request
|
|
27
|
+
guard let url = request.url else {
|
|
28
|
+
urlSchemeTask.didFailWithError(NSError(
|
|
29
|
+
domain: "ProxySchemeHandler",
|
|
30
|
+
code: -1,
|
|
31
|
+
userInfo: [NSLocalizedDescriptionKey: "No URL in request"]
|
|
32
|
+
))
|
|
33
|
+
return
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
let requestId = UUID().uuidString
|
|
37
|
+
|
|
38
|
+
taskLock.lock()
|
|
39
|
+
pendingTasks[requestId] = urlSchemeTask
|
|
40
|
+
taskLock.unlock()
|
|
41
|
+
|
|
42
|
+
// Buffer body from stream if needed (stream can only be read once)
|
|
43
|
+
var base64Body: String? = nil
|
|
44
|
+
if let bodyData = request.httpBody {
|
|
45
|
+
base64Body = bodyData.base64EncodedString()
|
|
46
|
+
} else if let bodyStream = request.httpBodyStream {
|
|
47
|
+
let data = Data(reading: bodyStream)
|
|
48
|
+
if !data.isEmpty {
|
|
49
|
+
base64Body = data.base64EncodedString()
|
|
50
|
+
taskLock.lock()
|
|
51
|
+
pendingBodies[requestId] = data
|
|
52
|
+
taskLock.unlock()
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// Build headers dict
|
|
57
|
+
var headers: [String: String] = [:]
|
|
58
|
+
if let allHeaders = request.allHTTPHeaderFields {
|
|
59
|
+
headers = allHeaders
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
let eventData: [String: Any] = [
|
|
63
|
+
"requestId": requestId,
|
|
64
|
+
"url": url.absoluteString,
|
|
65
|
+
"method": request.httpMethod ?? "GET",
|
|
66
|
+
"headers": headers,
|
|
67
|
+
"body": base64Body as Any,
|
|
68
|
+
"webviewId": webviewId,
|
|
69
|
+
]
|
|
70
|
+
|
|
71
|
+
plugin?.notifyListeners("proxyRequest", data: eventData)
|
|
72
|
+
|
|
73
|
+
// Timeout: if JS never responds, fail the request
|
|
74
|
+
DispatchQueue.global().asyncAfter(deadline: .now() + proxyTimeoutSeconds) { [weak self] in
|
|
75
|
+
guard let self = self else { return }
|
|
76
|
+
self.taskLock.lock()
|
|
77
|
+
guard let task = self.pendingTasks.removeValue(forKey: requestId) else {
|
|
78
|
+
self.taskLock.unlock()
|
|
79
|
+
return
|
|
80
|
+
}
|
|
81
|
+
self.pendingBodies.removeValue(forKey: requestId)
|
|
82
|
+
self.taskLock.unlock()
|
|
83
|
+
|
|
84
|
+
task.didFailWithError(NSError(
|
|
85
|
+
domain: "ProxySchemeHandler",
|
|
86
|
+
code: NSURLErrorTimedOut,
|
|
87
|
+
userInfo: [NSLocalizedDescriptionKey: "Proxy handler did not respond within \(Int(self.proxyTimeoutSeconds)) seconds"]
|
|
88
|
+
))
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
public func webView(_ webView: WKWebView, stop urlSchemeTask: WKURLSchemeTask) {
|
|
93
|
+
taskLock.lock()
|
|
94
|
+
// Check pending (waiting for JS)
|
|
95
|
+
if let key = pendingTasks.first(where: { $0.value === urlSchemeTask })?.key {
|
|
96
|
+
pendingTasks.removeValue(forKey: key)
|
|
97
|
+
pendingBodies.removeValue(forKey: key)
|
|
98
|
+
stoppedRequests.insert(key)
|
|
99
|
+
}
|
|
100
|
+
// Check active network tasks (pass-through) — cancel the URLSessionDataTask
|
|
101
|
+
var networkTaskToCancel: URLSessionDataTask?
|
|
102
|
+
if let entry = activeTasks.first(where: { $0.value.schemeTask === urlSchemeTask }) {
|
|
103
|
+
networkTaskToCancel = entry.value.dataTask
|
|
104
|
+
activeTasks.removeValue(forKey: entry.key)
|
|
105
|
+
stoppedRequests.insert(entry.value.requestId)
|
|
106
|
+
}
|
|
107
|
+
taskLock.unlock()
|
|
108
|
+
networkTaskToCancel?.cancel()
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/// Called from handleProxyRequest plugin method with the JS response
|
|
112
|
+
func handleResponse(requestId: String, responseData: [String: Any]?) {
|
|
113
|
+
taskLock.lock()
|
|
114
|
+
let isStopped = stoppedRequests.remove(requestId) != nil
|
|
115
|
+
guard let urlSchemeTask = pendingTasks.removeValue(forKey: requestId) else {
|
|
116
|
+
taskLock.unlock()
|
|
117
|
+
return
|
|
118
|
+
}
|
|
119
|
+
let bufferedBody = pendingBodies.removeValue(forKey: requestId)
|
|
120
|
+
taskLock.unlock()
|
|
121
|
+
|
|
122
|
+
if isStopped { return }
|
|
123
|
+
|
|
124
|
+
if let responseData = responseData {
|
|
125
|
+
// JS provided a response — return it directly
|
|
126
|
+
let statusCode = responseData["status"] as? Int ?? 200
|
|
127
|
+
let headersDict = responseData["headers"] as? [String: String] ?? [:]
|
|
128
|
+
let base64Body = responseData["body"] as? String ?? ""
|
|
129
|
+
let bodyData = Data(base64Encoded: base64Body) ?? Data()
|
|
130
|
+
|
|
131
|
+
guard let url = urlSchemeTask.request.url,
|
|
132
|
+
let httpResponse = HTTPURLResponse(
|
|
133
|
+
url: url, statusCode: statusCode,
|
|
134
|
+
httpVersion: "HTTP/1.1", headerFields: headersDict
|
|
135
|
+
) else {
|
|
136
|
+
urlSchemeTask.didFailWithError(NSError(
|
|
137
|
+
domain: "ProxySchemeHandler", code: -2,
|
|
138
|
+
userInfo: [NSLocalizedDescriptionKey: "Failed to create response"]
|
|
139
|
+
))
|
|
140
|
+
return
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
urlSchemeTask.didReceive(httpResponse)
|
|
144
|
+
urlSchemeTask.didReceive(bodyData)
|
|
145
|
+
urlSchemeTask.didFinish()
|
|
146
|
+
} else {
|
|
147
|
+
// Null response = pass-through via URLSession
|
|
148
|
+
executePassThrough(requestId: requestId, urlSchemeTask: urlSchemeTask, bufferedBody: bufferedBody)
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
private func executePassThrough(requestId: String, urlSchemeTask: WKURLSchemeTask, bufferedBody: Data?) {
|
|
153
|
+
var request = urlSchemeTask.request
|
|
154
|
+
if request.httpBody == nil, let body = bufferedBody {
|
|
155
|
+
request.httpBody = body
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
let task = Self.session.dataTask(with: request) { [weak self, weak urlSchemeTask] data, response, error in
|
|
159
|
+
guard let urlSchemeTask = urlSchemeTask else { return }
|
|
160
|
+
guard let self = self else { return }
|
|
161
|
+
|
|
162
|
+
// Clean up active entry and check not stopped
|
|
163
|
+
self.taskLock.lock()
|
|
164
|
+
if let entry = self.activeTasks.first(where: { $0.value.requestId == requestId }) {
|
|
165
|
+
self.activeTasks.removeValue(forKey: entry.key)
|
|
166
|
+
}
|
|
167
|
+
let wasStopped = self.stoppedRequests.remove(requestId) != nil
|
|
168
|
+
self.taskLock.unlock()
|
|
169
|
+
if wasStopped { return }
|
|
170
|
+
|
|
171
|
+
if let error = error {
|
|
172
|
+
if (error as NSError).code != NSURLErrorCancelled {
|
|
173
|
+
urlSchemeTask.didFailWithError(error)
|
|
174
|
+
}
|
|
175
|
+
} else {
|
|
176
|
+
if let response = response {
|
|
177
|
+
urlSchemeTask.didReceive(response)
|
|
178
|
+
}
|
|
179
|
+
if let data = data {
|
|
180
|
+
urlSchemeTask.didReceive(data)
|
|
181
|
+
}
|
|
182
|
+
urlSchemeTask.didFinish()
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
taskLock.lock()
|
|
187
|
+
activeTasks[task.taskIdentifier] = (requestId: requestId, schemeTask: urlSchemeTask, dataTask: task)
|
|
188
|
+
taskLock.unlock()
|
|
189
|
+
|
|
190
|
+
task.resume()
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
func cancelAllPendingTasks() {
|
|
194
|
+
taskLock.lock()
|
|
195
|
+
let pending = pendingTasks
|
|
196
|
+
let active = activeTasks
|
|
197
|
+
pendingTasks.removeAll()
|
|
198
|
+
pendingBodies.removeAll()
|
|
199
|
+
activeTasks.removeAll()
|
|
200
|
+
stoppedRequests.removeAll()
|
|
201
|
+
taskLock.unlock()
|
|
202
|
+
|
|
203
|
+
for (_, entry) in active {
|
|
204
|
+
entry.dataTask.cancel()
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
for (_, task) in pending {
|
|
208
|
+
task.didFailWithError(NSError(
|
|
209
|
+
domain: "ProxySchemeHandler",
|
|
210
|
+
code: NSURLErrorCancelled,
|
|
211
|
+
userInfo: [NSLocalizedDescriptionKey: "WebView closed"]
|
|
212
|
+
))
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
extension Data {
|
|
218
|
+
init(reading input: InputStream) {
|
|
219
|
+
self.init()
|
|
220
|
+
input.open()
|
|
221
|
+
let bufferSize = 1024
|
|
222
|
+
let buffer = UnsafeMutablePointer<UInt8>.allocate(capacity: bufferSize)
|
|
223
|
+
while input.hasBytesAvailable {
|
|
224
|
+
let read = input.read(buffer, maxLength: bufferSize)
|
|
225
|
+
if read < 0 {
|
|
226
|
+
break
|
|
227
|
+
}
|
|
228
|
+
self.append(buffer, count: read)
|
|
229
|
+
}
|
|
230
|
+
buffer.deallocate()
|
|
231
|
+
input.close()
|
|
232
|
+
}
|
|
233
|
+
}
|