iOS沙盒环境调用分享菜单时出现异常报错
iOS分享图片功能异常修复方案
环境信息
- Xcode 15.3
- Swift 5.10
- iOS 17.4.1(真机测试)
问题现象
点击待办项中的图片打开全屏查看器后,点击底部分享按钮无任何响应,日志输出权限及弹窗冲突类错误,核心错误如下:
Attempt to present <UIActivityViewController: 0x10582e800> on <_TtGC7SwiftUI19UIHostingControllerGVS_15ModifiedContentVS_7AnyViewVS_12RootModifier__: 0x10301e800> (from <_TtGC7SwiftUI19UIHostingControllerGVS_15ModifiedContentVS_7AnyViewVS_12RootModifier__: 0x10301e800>) which is already presenting <_TtGC7SwiftUI29PresentationHostingControllerVS_7AnyView_: 0x10700ee00>.
问题原因
代码直接使用rootViewController弹出分享表,但此时rootViewController已经弹出了全屏图片查看器(fullScreenCover),iOS不允许同一控制器同时present两个弹窗,必须在当前最顶层的presented控制器上发起新的present操作。
修复方案
方案1:获取顶层控制器弹出分享表
添加UIViewController扩展,用于定位当前活跃的最顶层控制器:
extension UIViewController { static func topMostViewController() -> UIViewController? { let keyWindow = UIApplication.shared.connectedScenes .filter { $0.activationState == .foregroundActive } .first(where: { $0 is UIWindowScene }) .flatMap({ $0 as? UIWindowScene })?.windows .first(where: { $0.isKeyWindow }) var topController = keyWindow?.rootViewController while let presentedViewController = topController?.presentedViewController { topController = presentedViewController } return topController } }
修改shareImage方法,使用顶层控制器弹出分享表:
private func shareImage(_ image: UIImage) { let activityController = UIActivityViewController(activityItems: [image], applicationActivities: nil) guard let topController = UIViewController.topMostViewController() else { return } topController.present(activityController, animated: true, completion: nil) }
方案2:SwiftUI原生sheet方式(更贴合SwiftUI风格)
创建UIActivityViewController的SwiftUI包装器:
struct ActivityViewController: UIViewControllerRepresentable { var activityItems: [Any] var applicationActivities: [UIActivity]? = nil func makeUIViewController(context: Context) -> UIActivityViewController { UIActivityViewController(activityItems: activityItems, applicationActivities: applicationActivities) } func updateUIViewController(_ uiViewController: UIActivityViewController, context: Context) {} }
在ContentView中添加状态变量控制分享弹窗:
@State private var sharedImage: UIImage? = nil
修改图片查看器内的分享按钮逻辑:
Button(action: { sharedImage = uiImage }) { Label("Share", systemImage: "square.and.arrow.up") .foregroundColor(.blue) } .buttonStyle(.plain)
最后在ContentView的body末尾添加sheet:
.sheet(item: $sharedImage) { image in ActivityViewController(activityItems: [image]) }
关键代码片段(方案1示例)
// 顶层控制器扩展 extension UIViewController { static func topMostViewController() -> UIViewController? { let keyWindow = UIApplication.shared.connectedScenes .filter { $0.activationState == .foregroundActive } .first(where: { $0 is UIWindowScene }) .flatMap({ $0 as? UIWindowScene })?.windows .first(where: { $0.isKeyWindow }) var topController = keyWindow?.rootViewController while let presentedViewController = topController?.presentedViewController { topController = presentedViewController } return topController } } struct ContentView: View { // 原有状态变量、查询属性保持不变 private func shareImage(_ image: UIImage) { let activityController = UIActivityViewController(activityItems: [image], applicationActivities: nil) guard let topController = UIViewController.topMostViewController() else { return } topController.present(activityController, animated: true, completion: nil) } // 原有视图、方法逻辑保持不变 }
内容的提问来源于stack exchange,提问作者domid
相关产品推荐
相关产品推荐

