24

I am trying to create a share sheet to share a Text, it was working fine in iOS 14 but in iOS 15 it tells me that

'windows' was deprecated in iOS 15.0: Use UIWindowScene.windows on a relevant window scene instead.

how can I make it work on iOS 15 with SwiftUI

Button {
    let TextoCompartido = "Hola  "
    
    let AV = UIActivityViewController(activityItems: [TextoCompartido], applicationActivities: nil)
    
    UIApplication.shared.windows.first?.rootViewController?.present(AV, animated: true, completion: nil)
}
Olcay Ertaş
  • 5,987
  • 8
  • 76
  • 112
Jesus M
  • 241
  • 1
  • 2
  • 4
  • You should try this UIApplication.shared.connectedScenes.first?.delegate?.window – Raja Kishan Nov 09 '21 at 03:41
  • 2
    Does this answer your question? [Showing 'UIActivityViewController' in SwiftUI](https://stackoverflow.com/questions/56533564/showing-uiactivityviewcontroller-in-swiftui) – jnpdx Nov 09 '21 at 07:03

5 Answers5

15

I think you would be best served using SwiftUI APIs directly. Generally, I would follow these steps.

  1. Create SwiftUI View named ActivityView that adheres to UIViewControllerRepresentable. This will allow you to bring UIActivityViewController to SwiftUI.
  2. Create an Identifiable struct to contain the text you'd like to display in the ActivityView. Making this type will allow you to use the SwiftUI sheet API and leverage SwiftUI state to tell the app when a new ActivityView to be shown.
  3. Create an optional @State variable that will hold on to your Identifiable text construct. When this variable changes, the sheet API will perform the callback.
  4. When the button is tapped, update the state of the variable set in step 3.
  5. Use the sheet API to create an ActivityView which will be presented to your user.

The code below should help get you started.


import UIKit
import SwiftUI

// 1. Activity View
struct ActivityView: UIViewControllerRepresentable {
    let text: String

    func makeUIViewController(context: UIViewControllerRepresentableContext<ActivityView>) -> UIActivityViewController {
        return UIActivityViewController(activityItems: [text], applicationActivities: nil)
    }

    func updateUIViewController(_ uiViewController: UIActivityViewController, context: UIViewControllerRepresentableContext<ActivityView>) {}
}

// 2. Share Text
struct ShareText: Identifiable {
    let id = UUID()
    let text: String
}

struct ContentView: View {
    // 3. Share Text State
    @State var shareText: ShareText?
    
    var body: some View {
        VStack {
            Button("Show Activity View") {
                // 4. New Identifiable Share Text
                shareText = ShareText(text: "Hola ")
            }
            .padding()
        }
        // 5. Sheet to display Share Text
        .sheet(item: $shareText) { shareText in
            ActivityView(text: shareText.text)
        }
    }
}
esreli
  • 4,993
  • 2
  • 26
  • 40
  • I couldn't get the optional `@State` variable to compile, so i ended up using the following solution wich is very similar but uses a bool: https://stackoverflow.com/a/58341956/2107610 – bbjay Jul 08 '22 at 17:06
5

iOS 16 includes the ShareLink view which works like this:

Gallery(...)
   .toolbar {
      ShareLink(item: image, preview: SharePreview("Birthday Effects"))
   }

Source: https://developer.apple.com/videos/play/wwdc2022/10052/

Time code offset: 25 minutes 28 seconds

Daniel
  • 8,794
  • 4
  • 48
  • 71
1

To avoid warning, change the way you retrieve the window scene. Do the following:

Button {
   let TextoCompartido = "Hola  "
                                
   let AV = UIActivityViewController(activityItems: [TextoCompartido], applicationActivities: nil)
    
   let scenes = UIApplication.shared.connectedScenes
   let windowScene = scenes.first as? UIWindowScene
    
   windowScene?.keyWindow?.rootViewController?.present(AV, animated: true, completion: nil)

}
Alessandro Pace
  • 206
  • 4
  • 8
  • 2
    This code works very well for me, for the second time, third time, etc... However, for the first time (after deploying on a phone or simulator) it freezes the UI for a long while and I see such messages on the console like "[Default] Task ... couldn't find entitlement CopresenceCore.Entitlement.publicAPI error nil". Any ideas what's wrong? – adamsfamily May 03 '22 at 15:59
  • 1
    warp it with a DispatchQueue.main.async {} – Hezy Ziv Feb 16 '23 at 09:36
1

Tested in in iOS 15 with SwiftUI

 func shareViaActionSheet() {
        if vedioData.vedioURL != nil {
            let activityVC = UIActivityViewController(activityItems: [vedioData.vedioURL as Any], applicationActivities: nil)
            UIApplication.shared.currentUIWindow()?.rootViewController?.present(activityVC, animated: true, completion: nil)
        }
    }

To avoid iOS 15 method deprecation warning use this extension

public extension UIApplication {
    func currentUIWindow() -> UIWindow? {
        let connectedScenes = UIApplication.shared.connectedScenes
            .filter { $0.activationState == .foregroundActive }
            .compactMap { $0 as? UIWindowScene }
        
        let window = connectedScenes.first?
            .windows
            .first { $0.isKeyWindow }
        return window
    }
}
0

you could try the following using the answer from: How to get rid of message " 'windows' was deprecated in iOS 15.0: Use UIWindowScene.windows on a relevant window scene instead" with AdMob banner?

Note that your code works for me, but the compiler give the deprecation warning.

public extension UIApplication {
    func currentUIWindow() -> UIWindow? {
        let connectedScenes = UIApplication.shared.connectedScenes
            .filter({
                $0.activationState == .foregroundActive})
            .compactMap({$0 as? UIWindowScene})
        
        let window = connectedScenes.first?
            .windows
            .first { $0.isKeyWindow }

        return window
        
    }
}

struct ContentView: View {
    let TextoCompartido = "Hola  "
    
    var body: some View {
        Button(action: {
            let AV = UIActivityViewController(activityItems: [TextoCompartido], applicationActivities: nil)
 
 UIApplication.shared.currentUIWindow()?.rootViewController?.present(AV, animated: true, completion: nil)
            
// This works for me, but the compiler give the deprecation warning
// UIApplication.shared.windows.first?.rootViewController?.present(AV, animated: true, completion: nil)
        }) {
            Text("Hola click me")
        }
    }
}
  • 1
    I would be very wary to follow this advice because you should not be able to depend on SwiftUI leveraging UIKit in the same way in subsequent releases. – esreli May 10 '22 at 02:36