From 04fb3acecc071fe73981302ee9c9bb58082b8f18 Mon Sep 17 00:00:00 2001 From: yumoqing Date: Fri, 17 Jul 2026 21:21:16 +0800 Subject: [PATCH] fix(iOS): use UIKit UIActivityViewController directly instead of SwiftUI .sheet MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit SwiftUI multiple .sheet modifiers can conflict — replaced the pendingExportURL sheet binding with a direct UIKit UIActivityViewController presentation from the key window's root VC. This bypasses any SwiftUI sheet stack issues. Also added copyLocalFile() for local file recording (FileManager.copyItem instead of URLSession.download which fails on file:// URLs). --- Sources/PlayerBridge.swift | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/Sources/PlayerBridge.swift b/Sources/PlayerBridge.swift index 83ba4ba..94396bb 100644 --- a/Sources/PlayerBridge.swift +++ b/Sources/PlayerBridge.swift @@ -178,10 +178,10 @@ final class PlayerBridge: ObservableObject { #if os(iOS) hlsRecorder.onRecordingSaved = { [weak self] url in - NSLog("[MiniPlayer] onRecordingSaved called, setting pendingExportURL: %@", url.lastPathComponent) + NSLog("[MiniPlayer] onRecordingSaved called: %@", url.lastPathComponent) self?.showToast("Saved: \(url.lastPathComponent)") - self?.pendingExportURL = url - NSLog("[MiniPlayer] pendingExportURL set to: %@", url.lastPathComponent) + // 直接用 UIKit present,不依赖 SwiftUI sheet binding + self?.presentShareSheet(for: url) } hlsRecorder.onError = { [weak self] msg in self?.showToast(msg) @@ -190,6 +190,26 @@ final class PlayerBridge: ObservableObject { } #if os(iOS) + /// 直接通过 UIKit present UIActivityViewController,绕过 SwiftUI sheet 可能的多 sheet 冲突 + func presentShareSheet(for url: URL) { + guard let windowScene = UIApplication.shared.connectedScenes + .compactMap({ $0 as? UIWindowScene }) + .first(where: { $0.activationState == .foregroundActive }) + ?? UIApplication.shared.connectedScenes.compactMap({ $0 as? UIWindowScene }).first + else { return } + + var topVC = windowScene.keyWindow?.rootViewController + ?? windowScene.windows.first(where: { !$0.isHidden && $0.bounds.size != .zero })?.rootViewController + while let presented = topVC?.presentedViewController { topVC = presented } + + let activityVC = UIActivityViewController(activityItems: [url], applicationActivities: nil) + activityVC.completionWithItemsHandler = { _, _, _, _ in + // 录制完成后可以删掉临时文件?不,用户可能需要再次分享 + } + topVC?.present(activityVC, animated: true) + NSLog("[MiniPlayer] presentShareSheet: presented for %@", url.lastPathComponent) + } + /// 配置 AVAudioSession,支持后台音频和 PiP private func ensureAudioSession() { let session = AVAudioSession.sharedInstance()