Following several tutorials (Medium for example) you can open a share sheet like this:
Button(action: {
let url = URL(string: "https://apple.com")
let av = UIActivityViewController(activityItems: [url!], applicationActivities: nil)
UIApplication.shared.windows.first?.rootViewController?.present(av, animated: true, completion: nil)
}) {
Text("Share Me")
}
However, this does not work within a presented sheet.
BaseView, with example of working share sheet and code to open Sheet:
struct BaseView: View {
...
@State var isSheetViewShowing = false
...
var body: some View {
// Open sheet view where share sheet does not work.
Button(action: {
isSheetViewShowing.toggle()
}) {
Text("Show sheet view")
}
Text("")
.frame(width: 0, height: 0)
.sheet(isPresented: $isSheetViewShowing) {
SheetView(showSheetView: $isSheetViewShowing)
}
// Below share Sheet works!
Button(action: {
let url = URL(string: "https://apple.com")
let av = UIActivityViewController(activityItems: [url!], applicationActivities: nil)
UIApplication.shared.windows.first?.rootViewController?.present(av, animated: true, completion: nil)
}) {
Text("Share Me")
}
}
}
Opened SheetView, where same code does not work:
struct SheetView: View {
...
@Binding var showSheetView: Bool
...
var body: some View {
// Below share Sheet does not work anymore!
Button(action: {
let url = URL(string: "https://apple.com")
let av = UIActivityViewController(activityItems: [url!], applicationActivities: nil)
UIApplication.shared.windows.first?.rootViewController?.present(av, animated: true, completion: nil)
}) {
Text("Share Me")
}
}
}
How to accomplish showing share sheet from within sheetview? Does the intent to share something have to be passed to BaseView (and/ or does SheetView have to be closed) and then called a share sheet from there? (I would appreciate a solution directly from SheetView)
The problem is in trying to show second sheet from root controller. It already has one attached, so rejects another (which is Activity in this case).
The solution is to use own controller, placed in opened our sheet as a presenter for activity.
Here is a simple demo. Tested with Xcode 13 / iOS 15.
struct SheetView: View {
@Binding var showSheetView: Bool
@State private var isShare = false
var body: some View {
// Below share Sheet - now works!
Button(action: {
isShare = true // present activity
}) {
Text("Share Me")
}
.background(SharingViewController(isPresenting: $isShare) {
let url = URL(string: "https://apple.com")
let av = UIActivityViewController(activityItems: [url!], applicationActivities: nil)
// For iPad
if UIDevice.current.userInterfaceIdiom == .pad {
av.popoverPresentationController?.sourceView = UIView()
}
av.completionWithItemsHandler = { _, _, _, _ in
isShare = false // required for re-open !!!
}
return av
})
}
}
struct SharingViewController: UIViewControllerRepresentable {
@Binding var isPresenting: Bool
var content: () -> UIViewController
func makeUIViewController(context: Context) -> UIViewController {
UIViewController()
}
func updateUIViewController(_ uiViewController: UIViewController, context: Context) {
if isPresenting {
uiViewController.present(content(), animated: true, completion: nil)
}
}
}