@capgo/capacitor-inappbrowser 8.21.2 → 8.22.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 +2 -1
- package/android/src/main/java/ee/forgr/capacitor_inappbrowser/CapgoInAppBrowserPlugin.java +1 -0
- package/android/src/main/java/ee/forgr/capacitor_inappbrowser/FileInputCaptureChooserSupport.java +150 -0
- package/android/src/main/java/ee/forgr/capacitor_inappbrowser/Options.java +10 -0
- package/android/src/main/java/ee/forgr/capacitor_inappbrowser/WebViewCustomFullscreenSupport.java +4 -0
- package/android/src/main/java/ee/forgr/capacitor_inappbrowser/WebViewDialog.java +87 -132
- package/dist/docs.json +20 -0
- package/dist/esm/definitions.d.ts +12 -0
- package/dist/esm/definitions.js.map +1 -1
- package/ios/Sources/InAppBrowserPlugin/InAppBrowserPlugin.swift +4 -4
- package/ios/Sources/InAppBrowserPlugin/NavigationBarShadowSupport.swift +33 -0
- package/ios/Sources/InAppBrowserPlugin/ShareActivityItemSource.swift +29 -0
- package/ios/Sources/InAppBrowserPlugin/WKWebViewController.swift +152 -40
- package/package.json +1 -1
|
@@ -43,9 +43,33 @@ private enum DownloadReservationStore {
|
|
|
43
43
|
static let lock = NSLock()
|
|
44
44
|
}
|
|
45
45
|
|
|
46
|
-
|
|
46
|
+
enum BlobDownloadSupport {
|
|
47
47
|
static let maxLegacyBytes = 512 * 1024
|
|
48
48
|
static let chunkBytes = 64 * 1024
|
|
49
|
+
/// Each active chunked session keeps a file handle open until finish, abort or teardown.
|
|
50
|
+
static let maxActiveSessions = 4
|
|
51
|
+
|
|
52
|
+
static func canStartSession(activeSessionCount: Int) -> Bool {
|
|
53
|
+
activeSessionCount < maxActiveSessions
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/// The declared blob size caps how many bytes a session may write, so a start without one is rejected.
|
|
57
|
+
static func expectedSize(from value: Any?) -> Int64? {
|
|
58
|
+
guard let size = (value as? NSNumber)?.int64Value, size >= 0 else {
|
|
59
|
+
return nil
|
|
60
|
+
}
|
|
61
|
+
return size
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/// Creates the empty destination file, then opens it for writing.
|
|
65
|
+
/// `FileHandle(forWritingTo:)` throws when the file does not exist yet, and
|
|
66
|
+
/// `uniqueDownloadDestination(for:)` only reserves the path without creating it.
|
|
67
|
+
static func openWriteHandle(at url: URL) throws -> FileHandle {
|
|
68
|
+
guard FileManager.default.createFile(atPath: url.path, contents: nil) else {
|
|
69
|
+
throw NSError(domain: "InAppBrowser", code: 1, userInfo: [NSLocalizedDescriptionKey: "Failed to create blob download file"])
|
|
70
|
+
}
|
|
71
|
+
return try FileHandle(forWritingTo: url)
|
|
72
|
+
}
|
|
49
73
|
}
|
|
50
74
|
|
|
51
75
|
/// Script message handlers registered on every in-app browser WKWebView.
|
|
@@ -64,6 +88,7 @@ enum ScriptMessageHandlerSupport {
|
|
|
64
88
|
"blobDownloadChunk",
|
|
65
89
|
"blobDownloadFinish",
|
|
66
90
|
"blobDownloadAbort",
|
|
91
|
+
"blobDownloadRejectAck",
|
|
67
92
|
"takeScreenshot",
|
|
68
93
|
"consoleMessageHandler",
|
|
69
94
|
"magicPrint",
|
|
@@ -532,6 +557,7 @@ open class WKWebViewController: UIViewController, WKScriptMessageHandler {
|
|
|
532
557
|
private var lastInjectedSafeAreaInsets: InjectedSafeAreaInsets?
|
|
533
558
|
private var downloadStates: [ObjectIdentifier: WKDownloadState] = [:]
|
|
534
559
|
private var blobDownloadSessions: [String: BlobDownloadSession] = [:]
|
|
560
|
+
private var rejectedBlobDownloadSessionIds: Set<String> = []
|
|
535
561
|
private var previewItemURL: URL?
|
|
536
562
|
|
|
537
563
|
func setHeaders(headers: [String: String]) {
|
|
@@ -874,7 +900,46 @@ open class WKWebViewController: UIViewController, WKScriptMessageHandler {
|
|
|
874
900
|
}
|
|
875
901
|
}
|
|
876
902
|
|
|
877
|
-
|
|
903
|
+
private func abortAllBlobDownloadSessions() {
|
|
904
|
+
for session in blobDownloadSessions.values {
|
|
905
|
+
cleanupBlobDownloadSession(session, deleteFile: true)
|
|
906
|
+
}
|
|
907
|
+
blobDownloadSessions.removeAll()
|
|
908
|
+
rejectedBlobDownloadSessionIds.removeAll()
|
|
909
|
+
}
|
|
910
|
+
|
|
911
|
+
private func signalBlobDownloadRejected(sessionId: String, reason: String) {
|
|
912
|
+
guard !sessionId.isEmpty else {
|
|
913
|
+
return
|
|
914
|
+
}
|
|
915
|
+
|
|
916
|
+
rejectedBlobDownloadSessionIds.insert(sessionId)
|
|
917
|
+
|
|
918
|
+
guard let webView else {
|
|
919
|
+
return
|
|
920
|
+
}
|
|
921
|
+
|
|
922
|
+
let escapedSessionId = sessionId
|
|
923
|
+
.replacingOccurrences(of: "\\", with: "\\\\")
|
|
924
|
+
.replacingOccurrences(of: "'", with: "\\'")
|
|
925
|
+
let escapedReason = reason
|
|
926
|
+
.replacingOccurrences(of: "\\", with: "\\\\")
|
|
927
|
+
.replacingOccurrences(of: "'", with: "\\'")
|
|
928
|
+
.replacingOccurrences(of: "\n", with: "\\n")
|
|
929
|
+
let script = """
|
|
930
|
+
(function() {
|
|
931
|
+
if (!window.__capgoBlobDownloadRejections) {
|
|
932
|
+
window.__capgoBlobDownloadRejections = {};
|
|
933
|
+
}
|
|
934
|
+
window.__capgoBlobDownloadRejections['\(escapedSessionId)'] = '\(escapedReason)';
|
|
935
|
+
})();
|
|
936
|
+
"""
|
|
937
|
+
|
|
938
|
+
DispatchQueue.main.async {
|
|
939
|
+
webView.evaluateJavaScript(script, completionHandler: nil)
|
|
940
|
+
}
|
|
941
|
+
}
|
|
942
|
+
|
|
878
943
|
private func abortBlobDownloadSession(sessionId: String, deleteFile: Bool) -> BlobDownloadSession? {
|
|
879
944
|
guard let session = blobDownloadSessions.removeValue(forKey: sessionId) else {
|
|
880
945
|
return nil
|
|
@@ -938,6 +1003,8 @@ open class WKWebViewController: UIViewController, WKScriptMessageHandler {
|
|
|
938
1003
|
return
|
|
939
1004
|
}
|
|
940
1005
|
|
|
1006
|
+
var reservedDestinationURL: URL?
|
|
1007
|
+
var shouldSignalRejection = true
|
|
941
1008
|
do {
|
|
942
1009
|
guard let jsonPayload = parseBlobBridgePayload(payload) else {
|
|
943
1010
|
throw NSError(domain: "InAppBrowser", code: 1, userInfo: [NSLocalizedDescriptionKey: "Blob download start payload is missing"])
|
|
@@ -949,13 +1016,22 @@ open class WKWebViewController: UIViewController, WKScriptMessageHandler {
|
|
|
949
1016
|
}
|
|
950
1017
|
|
|
951
1018
|
if blobDownloadSessions[sessionId] != nil {
|
|
1019
|
+
shouldSignalRejection = false
|
|
952
1020
|
throw NSError(domain: "InAppBrowser", code: 1, userInfo: [NSLocalizedDescriptionKey: "Blob download session already exists"])
|
|
953
1021
|
}
|
|
954
1022
|
|
|
1023
|
+
guard BlobDownloadSupport.canStartSession(activeSessionCount: blobDownloadSessions.count) else {
|
|
1024
|
+
throw NSError(domain: "InAppBrowser", code: 1, userInfo: [NSLocalizedDescriptionKey: "Too many active blob downloads"])
|
|
1025
|
+
}
|
|
1026
|
+
|
|
1027
|
+
guard let expectedSize = BlobDownloadSupport.expectedSize(from: jsonPayload["size"]) else {
|
|
1028
|
+
throw NSError(domain: "InAppBrowser", code: 1, userInfo: [NSLocalizedDescriptionKey: "Blob download size is missing"])
|
|
1029
|
+
}
|
|
1030
|
+
|
|
955
1031
|
let fileName = blobDownloadFileName(from: jsonPayload)
|
|
956
1032
|
let destinationURL = try uniqueDownloadDestination(for: fileName)
|
|
957
|
-
|
|
958
|
-
let
|
|
1033
|
+
reservedDestinationURL = destinationURL
|
|
1034
|
+
let fileHandle = try BlobDownloadSupport.openWriteHandle(at: destinationURL)
|
|
959
1035
|
blobDownloadSessions[sessionId] = BlobDownloadSession(
|
|
960
1036
|
destinationURL: destinationURL,
|
|
961
1037
|
sourceURL: jsonPayload["sourceUrl"] as? String,
|
|
@@ -964,7 +1040,16 @@ open class WKWebViewController: UIViewController, WKScriptMessageHandler {
|
|
|
964
1040
|
expectedSize: expectedSize
|
|
965
1041
|
)
|
|
966
1042
|
} catch {
|
|
967
|
-
|
|
1043
|
+
let sessionId = (parseBlobBridgePayload(payload)?["sessionId"] as? String) ?? ""
|
|
1044
|
+
if let reservedDestinationURL {
|
|
1045
|
+
try? FileManager.default.removeItem(at: reservedDestinationURL)
|
|
1046
|
+
releaseDownloadDestination(reservedDestinationURL)
|
|
1047
|
+
}
|
|
1048
|
+
let reason = error.localizedDescription
|
|
1049
|
+
if !sessionId.isEmpty && shouldSignalRejection {
|
|
1050
|
+
signalBlobDownloadRejected(sessionId: sessionId, reason: reason)
|
|
1051
|
+
}
|
|
1052
|
+
emitDownloadFailed(sourceURL: nil, error: "Failed to start blob download: \(reason)")
|
|
968
1053
|
}
|
|
969
1054
|
}
|
|
970
1055
|
|
|
@@ -983,6 +1068,7 @@ open class WKWebViewController: UIViewController, WKScriptMessageHandler {
|
|
|
983
1068
|
let base64 = jsonPayload["base64"] as? String ?? ""
|
|
984
1069
|
guard !base64.isEmpty, let data = Data(base64Encoded: base64) else {
|
|
985
1070
|
abortBlobDownloadSession(sessionId: sessionId, deleteFile: true)
|
|
1071
|
+
signalBlobDownloadRejected(sessionId: sessionId, reason: "Failed to save blob download")
|
|
986
1072
|
emitDownloadFailed(sourceURL: session.sourceURL, error: "Failed to save blob download")
|
|
987
1073
|
return
|
|
988
1074
|
}
|
|
@@ -997,7 +1083,9 @@ open class WKWebViewController: UIViewController, WKScriptMessageHandler {
|
|
|
997
1083
|
blobDownloadSessions[sessionId] = session
|
|
998
1084
|
} catch {
|
|
999
1085
|
abortBlobDownloadSession(sessionId: sessionId, deleteFile: true)
|
|
1000
|
-
|
|
1086
|
+
let reason = error.localizedDescription
|
|
1087
|
+
signalBlobDownloadRejected(sessionId: sessionId, reason: reason)
|
|
1088
|
+
emitDownloadFailed(sourceURL: session.sourceURL, error: "Failed to save blob download: \(reason)")
|
|
1001
1089
|
}
|
|
1002
1090
|
}
|
|
1003
1091
|
|
|
@@ -1008,8 +1096,15 @@ open class WKWebViewController: UIViewController, WKScriptMessageHandler {
|
|
|
1008
1096
|
|
|
1009
1097
|
guard let jsonPayload = parseBlobBridgePayload(payload),
|
|
1010
1098
|
let sessionId = jsonPayload["sessionId"] as? String,
|
|
1011
|
-
!sessionId.isEmpty
|
|
1012
|
-
|
|
1099
|
+
!sessionId.isEmpty else {
|
|
1100
|
+
emitDownloadFailed(sourceURL: nil, error: "Blob download session was not initialized")
|
|
1101
|
+
return
|
|
1102
|
+
}
|
|
1103
|
+
|
|
1104
|
+
guard let session = blobDownloadSessions.removeValue(forKey: sessionId) else {
|
|
1105
|
+
if rejectedBlobDownloadSessionIds.remove(sessionId) != nil {
|
|
1106
|
+
return
|
|
1107
|
+
}
|
|
1013
1108
|
emitDownloadFailed(sourceURL: nil, error: "Blob download session was not initialized")
|
|
1014
1109
|
return
|
|
1015
1110
|
}
|
|
@@ -1029,6 +1124,7 @@ open class WKWebViewController: UIViewController, WKScriptMessageHandler {
|
|
|
1029
1124
|
return
|
|
1030
1125
|
}
|
|
1031
1126
|
|
|
1127
|
+
releaseDownloadDestination(session.destinationURL)
|
|
1032
1128
|
previewDownloadedFile(session.destinationURL, mimeType: session.mimeType, sourceURL: session.sourceURL)
|
|
1033
1129
|
}
|
|
1034
1130
|
|
|
@@ -1049,6 +1145,15 @@ open class WKWebViewController: UIViewController, WKScriptMessageHandler {
|
|
|
1049
1145
|
)
|
|
1050
1146
|
}
|
|
1051
1147
|
|
|
1148
|
+
private func acknowledgeBlobDownloadRejectionPayload(_ payload: Any) {
|
|
1149
|
+
guard let jsonPayload = parseBlobBridgePayload(payload),
|
|
1150
|
+
let sessionId = jsonPayload["sessionId"] as? String,
|
|
1151
|
+
!sessionId.isEmpty else {
|
|
1152
|
+
return
|
|
1153
|
+
}
|
|
1154
|
+
rejectedBlobDownloadSessionIds.remove(sessionId)
|
|
1155
|
+
}
|
|
1156
|
+
|
|
1052
1157
|
private func handleBlobDownloadFromPage(blobUrl: String, mimeType: String?, contentDisposition: String?) {
|
|
1053
1158
|
guard handleDownloads, let webView else {
|
|
1054
1159
|
emitDownloadFailed(sourceURL: blobUrl, error: "Blob download requires an active WebView")
|
|
@@ -1092,6 +1197,18 @@ open class WKWebViewController: UIViewController, WKScriptMessageHandler {
|
|
|
1092
1197
|
: null;
|
|
1093
1198
|
const sessionId = 'blob-download-' + Date.now() + '-' + Math.random().toString(36).slice(2);
|
|
1094
1199
|
let fileName = fallbackFileName;
|
|
1200
|
+
if (!window.__capgoBlobDownloadRejections) {
|
|
1201
|
+
window.__capgoBlobDownloadRejections = {};
|
|
1202
|
+
}
|
|
1203
|
+
const blobDownloadRejectionReason = function(id) {
|
|
1204
|
+
return window.__capgoBlobDownloadRejections && window.__capgoBlobDownloadRejections[id];
|
|
1205
|
+
};
|
|
1206
|
+
const ensureBlobDownloadNotRejected = function(id) {
|
|
1207
|
+
const reason = blobDownloadRejectionReason(id);
|
|
1208
|
+
if (reason) {
|
|
1209
|
+
throw new Error(String(reason));
|
|
1210
|
+
}
|
|
1211
|
+
};
|
|
1095
1212
|
const readChunkAsBase64 = function(chunk) {
|
|
1096
1213
|
return new Promise(function(resolve, reject) {
|
|
1097
1214
|
const reader = new FileReader();
|
|
@@ -1123,10 +1240,15 @@ open class WKWebViewController: UIViewController, WKScriptMessageHandler {
|
|
|
1123
1240
|
mimeType: blob.type || fallbackMimeType,
|
|
1124
1241
|
size: blob.size
|
|
1125
1242
|
}));
|
|
1243
|
+
await new Promise(function(resolve) { setTimeout(resolve, 0); });
|
|
1244
|
+
ensureBlobDownloadNotRejected(sessionId);
|
|
1126
1245
|
for (let offset = 0; offset < blob.size; offset += chunkSize) {
|
|
1246
|
+
ensureBlobDownloadNotRejected(sessionId);
|
|
1127
1247
|
const base64 = await readChunkAsBase64(blob.slice(offset, offset + chunkSize));
|
|
1248
|
+
ensureBlobDownloadNotRejected(sessionId);
|
|
1128
1249
|
bridge.appendBlobDownloadChunk(JSON.stringify({ sessionId: sessionId, base64: base64 }));
|
|
1129
1250
|
}
|
|
1251
|
+
ensureBlobDownloadNotRejected(sessionId);
|
|
1130
1252
|
bridge.finishBlobDownload(JSON.stringify({ sessionId: sessionId }));
|
|
1131
1253
|
return;
|
|
1132
1254
|
}
|
|
@@ -1144,13 +1266,22 @@ open class WKWebViewController: UIViewController, WKScriptMessageHandler {
|
|
|
1144
1266
|
base64: base64
|
|
1145
1267
|
}));
|
|
1146
1268
|
})().catch(function(error) {
|
|
1269
|
+
const reason = String((error && error.message) || error || 'Blob download failed');
|
|
1270
|
+
if (blobDownloadRejectionReason(sessionId)) {
|
|
1271
|
+
delete window.__capgoBlobDownloadRejections[sessionId];
|
|
1272
|
+
if (bridge && bridge.acknowledgeBlobDownloadRejection) {
|
|
1273
|
+
bridge.acknowledgeBlobDownloadRejection(JSON.stringify({ sessionId: sessionId }));
|
|
1274
|
+
}
|
|
1275
|
+
console.error('Failed to capture blob download', error);
|
|
1276
|
+
return;
|
|
1277
|
+
}
|
|
1147
1278
|
if (bridge && bridge.abortBlobDownload) {
|
|
1148
1279
|
bridge.abortBlobDownload(JSON.stringify({
|
|
1149
1280
|
sessionId: sessionId,
|
|
1150
1281
|
fileName: fileName,
|
|
1151
1282
|
sourceUrl: blobUrl,
|
|
1152
1283
|
mimeType: fallbackMimeType,
|
|
1153
|
-
reason:
|
|
1284
|
+
reason: reason
|
|
1154
1285
|
}));
|
|
1155
1286
|
}
|
|
1156
1287
|
console.error('Failed to capture blob download', error);
|
|
@@ -1228,30 +1359,7 @@ open class WKWebViewController: UIViewController, WKScriptMessageHandler {
|
|
|
1228
1359
|
navigationBar.backgroundColor = color
|
|
1229
1360
|
navigationBar.barTintColor = color
|
|
1230
1361
|
navigationBar.isTranslucent = false
|
|
1231
|
-
|
|
1232
|
-
navigationBar.shadowImage = UIImage()
|
|
1233
|
-
navigationBar.setValue(true, forKey: "hidesShadow")
|
|
1234
|
-
|
|
1235
|
-
if #available(iOS 13.0, *) {
|
|
1236
|
-
let appearance = UINavigationBarAppearance()
|
|
1237
|
-
appearance.configureWithOpaqueBackground()
|
|
1238
|
-
appearance.backgroundColor = color
|
|
1239
|
-
appearance.backgroundEffect = nil
|
|
1240
|
-
appearance.shadowColor = .clear
|
|
1241
|
-
appearance.shadowImage = UIImage()
|
|
1242
|
-
|
|
1243
|
-
if let titleTextAttributes = navigationBar.titleTextAttributes {
|
|
1244
|
-
appearance.titleTextAttributes = titleTextAttributes
|
|
1245
|
-
}
|
|
1246
|
-
if let largeTitleTextAttributes = navigationBar.largeTitleTextAttributes {
|
|
1247
|
-
appearance.largeTitleTextAttributes = largeTitleTextAttributes
|
|
1248
|
-
}
|
|
1249
|
-
|
|
1250
|
-
navigationBar.standardAppearance = appearance
|
|
1251
|
-
navigationBar.compactAppearance = appearance
|
|
1252
|
-
navigationBar.scrollEdgeAppearance = appearance
|
|
1253
|
-
navigationBar.compactScrollEdgeAppearance = appearance
|
|
1254
|
-
}
|
|
1362
|
+
NavigationBarShadowSupport.hideShadow(on: navigationBar, backgroundColor: color)
|
|
1255
1363
|
}
|
|
1256
1364
|
|
|
1257
1365
|
// Make status bar background with colored view underneath
|
|
@@ -1440,6 +1548,7 @@ open class WKWebViewController: UIViewController, WKScriptMessageHandler {
|
|
|
1440
1548
|
}
|
|
1441
1549
|
|
|
1442
1550
|
deinit {
|
|
1551
|
+
abortAllBlobDownloadSessions()
|
|
1443
1552
|
NotificationCenter.default.removeObserver(self)
|
|
1444
1553
|
webView?.removeObserver(self, forKeyPath: estimatedProgressKeyPath)
|
|
1445
1554
|
if websiteTitleInNavigationBar {
|
|
@@ -1859,6 +1968,8 @@ open class WKWebViewController: UIViewController, WKScriptMessageHandler {
|
|
|
1859
1968
|
finishBlobDownloadPayload(message.body)
|
|
1860
1969
|
} else if message.name == "blobDownloadAbort" {
|
|
1861
1970
|
abortBlobDownloadPayload(message.body)
|
|
1971
|
+
} else if message.name == "blobDownloadRejectAck" {
|
|
1972
|
+
acknowledgeBlobDownloadRejectionPayload(message.body)
|
|
1862
1973
|
} else if message.name == "consoleMessageHandler" {
|
|
1863
1974
|
if let messageBody = message.body as? [String: Any] {
|
|
1864
1975
|
emit("consoleMessage", data: ConsoleMessageSupport.normalizePayload(from: messageBody))
|
|
@@ -2019,6 +2130,9 @@ open class WKWebViewController: UIViewController, WKScriptMessageHandler {
|
|
|
2019
2130
|
},
|
|
2020
2131
|
abortBlobDownload: function(payload) {
|
|
2021
2132
|
window.webkit.messageHandlers.blobDownloadAbort.postMessage(payload);
|
|
2133
|
+
},
|
|
2134
|
+
acknowledgeBlobDownloadRejection: function(payload) {
|
|
2135
|
+
window.webkit.messageHandlers.blobDownloadRejectAck.postMessage(payload);
|
|
2022
2136
|
}\(extraControls)\(screenshotControls)
|
|
2023
2137
|
});
|
|
2024
2138
|
if (!window.__capgoInAppBrowserWindowCloseInstalled) {
|
|
@@ -2155,6 +2269,7 @@ open class WKWebViewController: UIViewController, WKScriptMessageHandler {
|
|
|
2155
2269
|
userContentController.add(weakHandler, name: "blobDownloadChunk")
|
|
2156
2270
|
userContentController.add(weakHandler, name: "blobDownloadFinish")
|
|
2157
2271
|
userContentController.add(weakHandler, name: "blobDownloadAbort")
|
|
2272
|
+
userContentController.add(weakHandler, name: "blobDownloadRejectAck")
|
|
2158
2273
|
if allowScreenshotsFromWebPage {
|
|
2159
2274
|
userContentController.add(weakHandler, name: "takeScreenshot")
|
|
2160
2275
|
}
|
|
@@ -2255,11 +2370,6 @@ open class WKWebViewController: UIViewController, WKScriptMessageHandler {
|
|
|
2255
2370
|
|
|
2256
2371
|
let webView = WKWebView(frame: .zero, configuration: webConfiguration)
|
|
2257
2372
|
|
|
2258
|
-
// if webView.responds(to: Selector(("setInspectable:"))) {
|
|
2259
|
-
// // Fix: https://stackoverflow.com/questions/76216183/how-to-debug-wkwebview-in-ios-16-4-1-using-xcode-14-2/76603043#76603043
|
|
2260
|
-
// webView.perform(Selector(("setInspectable:")), with: isInspectable)
|
|
2261
|
-
// }
|
|
2262
|
-
|
|
2263
2373
|
if #available(iOS 16.4, *) {
|
|
2264
2374
|
webView.isInspectable = isInspectable
|
|
2265
2375
|
}
|
|
@@ -2667,6 +2777,7 @@ public extension WKWebViewController {
|
|
|
2667
2777
|
|
|
2668
2778
|
func cleanupWebView() {
|
|
2669
2779
|
setBrowserFullscreen(false)
|
|
2780
|
+
abortAllBlobDownloadSessions()
|
|
2670
2781
|
guard let webView = self.webView else { return }
|
|
2671
2782
|
webView.stopLoading()
|
|
2672
2783
|
previewItemURL = nil
|
|
@@ -3227,8 +3338,9 @@ fileprivate extension WKWebViewController {
|
|
|
3227
3338
|
|
|
3228
3339
|
// Separated the actual sharing functionality
|
|
3229
3340
|
private func showShareSheet(items: [Any], sender: AnyObject) {
|
|
3230
|
-
let
|
|
3231
|
-
|
|
3341
|
+
let subject = self.shareSubject ?? self.title
|
|
3342
|
+
let activityItems = items.map { ShareActivityItemSource(item: $0, subject: subject) }
|
|
3343
|
+
let activityViewController = UIActivityViewController(activityItems: activityItems, applicationActivities: nil)
|
|
3232
3344
|
if let barButtonItem = sender as? UIBarButtonItem {
|
|
3233
3345
|
activityViewController.popoverPresentationController?.barButtonItem = barButtonItem
|
|
3234
3346
|
}
|