UIActivityViewController在SwiftUI中无法正常工作?疑似存在严重Bug
兄弟,你遇到的这个问题我之前也踩过坑!确实和SwiftUI与UIKit模态视图的交互兼容性脱不了干系,尤其是第三方ShareExtension(比如WhatsApp的)和SwiftUI的sheet/fullScreenCover呈现机制之间的生命周期冲突。那些错误日志本质是WhatsApp的分享扩展连接被意外中断,根源往往是SwiftUI没处理好UIActivityViewController的模态生命周期。
下面是几个亲测有效的解决方案,按优先级尝试:
1. 先切真机测试!(最容易忽略的前提)
WhatsApp的ShareExtension在模拟器上基本没法正常工作,很多时候模拟器上的异常只是因为扩展根本没被正确加载。先换到真机跑一遍,排除环境问题再说。
2. 绕开SwiftUI模态,用UIKit原生方式呈现
SwiftUI的sheet/fullScreenCover和UIActivityViewController这种UIKit原生模态控制器嵌套时,很容易出现生命周期冲突。我们可以自定义一个UIViewControllerRepresentable,直接用UIKit的present方法来显示分享控制器:
struct ActivityView: UIViewControllerRepresentable { let shareItems: [Any] @Binding var isShowing: Bool func makeCoordinator() -> Coordinator { Coordinator(parent: self) } func makeUIViewController(context: Context) -> UIViewController { // 用一个空白的UIViewController作为容器 UIViewController() } func updateUIViewController(_ uiViewController: UIViewController, context: Context) { if isShowing { let activityVC = UIActivityViewController( activityItems: shareItems, applicationActivities: nil ) // 处理分享完成后的关闭逻辑 activityVC.completionWithItemsHandler = { _, _, _, _ in self.isShowing = false } // 设置代理,处理用户手动关闭的情况 activityVC.presentationController?.delegate = context.coordinator uiViewController.present(activityVC, animated: true) } else { uiViewController.dismiss(animated: true) } } class Coordinator: NSObject, UIAdaptivePresentationControllerDelegate { let parent: ActivityView init(parent: ActivityView) { self.parent = parent } func presentationControllerDidDismiss(_ presentationController: UIPresentationController) { parent.isShowing = false } } }
然后在你的SwiftUI视图里这么用:
struct ContentView: View { @State private var showShareSheet = false var body: some View { Button("分享到WhatsApp") { showShareSheet = true } // 把ActivityView作为背景嵌入,避免影响主视图布局 .background( ActivityView(shareItems: ["这是测试分享内容"], isShowing: $showShareSheet) ) } }
这种方式完全绕开了SwiftUI的模态系统,用UIKit原生的逻辑来管理分享控制器的生命周期,对第三方扩展的兼容性要好得多。
3. 如果非要用SwiftUI模态,试试fullScreenCover替代sheet
如果你不想改太多代码,也可以尝试把sheet换成fullScreenCover,有时候这种全屏模态的呈现方式能减少和UIKit组件的冲突:
struct ContentView: View { @State private var showShareSheet = false var body: some View { Button("分享") { showShareSheet = true } .fullScreenCover(isPresented: $showShareSheet) { ActivityViewController(activityItems: ["测试内容"]) .ignoresSafeArea() } } } // 基础的UIActivityViewController封装 struct ActivityViewController: UIViewControllerRepresentable { let activityItems: [Any] func makeUIViewController(context: Context) -> UIActivityViewController { let controller = UIActivityViewController(activityItems: activityItems, applicationActivities: nil) // 可以排除不需要的分享选项,减少冲突概率 controller.excludedActivityTypes = [.addToReadingList, .assignToContact] return controller } func updateUIViewController(_ uiViewController: UIActivityViewController, context: Context) {} }
4. 检查Info.plist的URL Scheme配置
虽然不是直接导致连接中断的原因,但确保你的App配置了WhatsApp的URL Scheme(whatsapp://),有时候缺少这个会导致分享流程异常。在Info.plist的LSApplicationQueriesSchemes数组里添加whatsapp即可。
总之,这类问题的核心就是SwiftUI和UIKit在模态生命周期管理上的差异,尤其是涉及第三方扩展的场景,用UIKit原生的呈现方式往往能解决问题。
内容的提问来源于stack exchange,提问作者codewithfeeling

