1

I want to load specific webpages inside a Safari browser INSIDE the app (i.e. not going outside the app), and it should exist within the same safari-environment, i.e. no regular webviews.

I have this SafariView to enable that in SwiftUI.

Now I want to load different urls from the same scene (The number varies, can be 0 to 20-ish).

When I open the SafariViews though only the first url is opened. When I click the second button the first url is loaded again.

import SwiftUI
import SafariServices

struct ContentView: View {
  @State private var showSafari = false
  
  var body: some View {
    VStack {
      Button(action: {
        showSafari = true
      }) {
        Text("Apple")
          .padding()
      }
      .fullScreenCover(isPresented: $showSafari) {
        SafariView(url: URL(string: "http://www.apple.com")!)
      }
      
      Button(action: {
        showSafari = true
      }) {
        Text("Google")
          .padding()
      }
      .fullScreenCover(isPresented: $showSafari) {
        SafariView(url: URL(string: "http://www.google.com")!)
      }
    }
  }
}

struct SafariView: UIViewControllerRepresentable {
  var url: URL
  
  func makeUIViewController(
    context: UIViewControllerRepresentableContext<SafariView>
  ) -> SFSafariViewController {
    return SFSafariViewController(url: url)
  }
  
  func updateUIViewController(
    _ uiViewController: SFSafariViewController,
    context: UIViewControllerRepresentableContext<SafariView>
  ) {}
}

What I am doing in another scene is creating 2 separate showSafari variables, there it seems to work, but in that case it is only ever 2 hard-coded urls being shown.

Is there something I am missing in this safari-implementation, or do I possibly need to work around this by creating an array of showSafari booleans?

Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
matthias_code
  • 833
  • 8
  • 21

1 Answers1

2

Try using .fullScreenCover(item:content:):

struct ContentView: View {
    @State private var safariURL: String?

    var body: some View {
        VStack {
            Button(action: {
                safariURL = "http://www.apple.com"
            }) {
                Text("Apple")
                    .padding()
            }

            Button(action: {
                safariURL = "http://www.google.com"
            }) {
                Text("Google")
                    .padding()
            }
        }
        .fullScreenCover(item: $safariURL) {
            if let url = URL(string: $0) {
                SafariView(url: url)
            }
        }
    }
}

Note that you need to pass some Identifiable variable in item. A possible solution is to conform String to Identifiable:

extension String: Identifiable {
    public var id: Self { self }
}
pawello2222
  • 46,897
  • 22
  • 145
  • 209