fix(apple): restore macOS approval modal and sandboxed file sharing

Approval modal: since the Share/QR sheet auto-opens after creating a transfer,
it is always up when a receiver request arrives, and macOS silently drops a sheet
presented while another is still dismissing — so the approval sheet never appeared.
Drive the approval sheet from explicit state (not a constant binding) and, on
macOS, defer its presentation one dismiss-beat after closing the Share/QR sheet so
the hand-off is serialized. Still a non-dismissable sheet; iOS timing unchanged.

Sandboxed file sharing: the macOS picker released its security scope immediately,
so the core's later import failed with EPERM under the App Store sandbox (the
non-sandboxed .dmg was unaffected). Capture a security-scoped bookmark at pick
time and re-acquire access across shareFiles() — during which the core imports the
bytes — mirroring the receive-folder scoped-access pattern.
This commit is contained in:
2026-07-27 15:01:01 +02:00
parent cc194f6a7b
commit a0ebd7c71b
5 changed files with 56 additions and 6 deletions

View File

@@ -107,9 +107,15 @@ enum PickerSupport {
)
#else
let size = isDirectory ? nil : (try? url.resourceValues(forKeys: [.fileSizeKey]))?.fileSize.map { UInt64($0) }
// Capture a security-scoped bookmark while the picker's scope is still held,
// so the core can re-acquire access to open the file at import time (under
// the App Store sandbox). Non-sandboxed builds don't need it but it's harmless.
let bookmark = try? url.bookmarkData(
options: .withSecurityScope, includingResourceValuesForKeys: nil, relativeTo: nil
)
return PickedShareFile(
value: url.path, displayName: url.lastPathComponent, sizeBytes: size,
isTemporaryCopy: false, isDirectory: isDirectory
isTemporaryCopy: false, isDirectory: isDirectory, securityScopeBookmark: bookmark
)
#endif
}