SwiftUI: How do I make a button open a URL in safari?
iOS 14.0+
Using Link:
Link("Some label", destination: URL(string: "https://www.mylink.com")!)
Older versions
Button(action: {
if let url = URL(string: "https://www.mylink.com") {
UIApplication.shared.open(url)
}
}) {
Text("Some label")
}
How to create tappable url/phone number in SwiftUI
Using iOS 14 / Xcode 12.0 beta 5
Use new link feature in SwiftUI for phone and email links.
// Link that will open Safari on iOS devices
Link("Apple", destination: URL(string: "https://www.apple.com")!)
// Clickable telphone number
Link("(800)555-1212", destination: URL(string: "tel:8005551212")!)
// Clickable Email Address
Link("apple@me.com", destination: URL(string: "mailto:apple@me.com")!)
How to load a webpage in an ovally inside a SwiftUI App vs loading in safari
You need to wrap the SFSafariViewController (which is from UIKit) into SwiftUI, since it isn't possible to do this natively right now. You should use UIViewControllerRepresentable to do this.
import SwiftUI
import SafariServices
struct MyView: View {
@State var showStackoverflow:Bool = false
var body: some View {
Button(action: { self.showStackoverflow = true }) {
Text("Open stackoverflow")
}
.sheet(isPresented: self.$showStackoverflow) {
SFSafariViewWrapper(url: URL(string: "https://stackoverflow.com")!)
}
}
}
struct SFSafariViewWrapper: UIViewControllerRepresentable {
let url: URL
func makeUIViewController(context: UIViewControllerRepresentableContext<Self>) -> SFSafariViewController {
return SFSafariViewController(url: url)
}
func updateUIViewController(_ uiViewController: SFSafariViewController, context: UIViewControllerRepresentableContext<SFSafariViewWrapper>) {
return
}
}
Swift Open Link in Safari
It's not "baked in to Swift", but you can use standard UIKit
methods to do it. Take a look at UIApplication's openUrl(_:)
(deprecated) and open(_:options:completionHandler:)
.
Swift 4 + Swift 5 (iOS 10 and above)
guard let url = URL(string: "https://stackoverflow.com") else { return }
UIApplication.shared.open(url)
Swift 3 (iOS 9 and below)
guard let url = URL(string: "https://stackoverflow.com") else { return }
UIApplication.shared.openURL(url)
Swift 2.2
guard let url = URL(string: "https://stackoverflow.com") else { return }
UIApplication.sharedApplication().openURL(url)
Open certain links in Safari from WKWebView
You can use a Coordinator in your UIViewRepresentatable
to act as a navigation delegate for the WKWebView
:
struct TrainerTab: UIViewRepresentable {
let request: String
private let hostingUrl: String = "https://page.tld"
func makeCoordinator() -> Coordinator {
Coordinator()
}
func makeUIView(context: Context) -> WKWebView {
return WKWebView()
}
func updateUIView(_ uiView: WKWebView, context: Context) {
uiView.navigationDelegate = context.coordinator
let url = "\(hostingUrl)/\(request)"
uiView.load(URLRequest(url: URL(string: url)!))
}
class Coordinator : NSObject, WKNavigationDelegate {
func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
guard let url = navigationAction.request.url else {
decisionHandler(.allow)
}
//make some conditions based on the URL here
if myCondition {
decisionHandler(.cancel)
UIApplication.shared.open(url)
} else {
decisionHandler(.allow)
}
}
}
}
Open non-URL string in Safari (e.g. Search)
You can use x-web-search://
scheme with x-web-search://?[SearchValue]
.
Sample code:
let urlStr = "x-web-search://?[SearchValue]"
if let url = URL(string: urlStr) {
if UIApplication.shared.canOpenURL(url) {
UIApplication.shared.open(url, options: [:]) { didEnd in
print("Did End: \(didEnd)")
}
} else {
print("Can't open URL")
}
} else {
print("Isn't URL")
}
SwiftUI on app load - redirect to web URL
You can use NavigationView
with pre-selected NavigationLink
: this will open as soon as the view appears.
Display your main app only after NavigationLink
is closed with if
.
struct ContentView: View {
var body: some View {
MainApp()
.onAppear {
UIApplication.shared.open(URL(string: "https://stackoverflow.com/")!)
}
}
}
struct MainApp: View {
var body: some View {
Text("hello")
}
}
Is it possible to open a markdown link in our app instead of Safari?
The SwiftUI environment includes a URL handler which, by default, opens links in Safari, but you can provide your own handler to override this.
Text("Hello! Example of a markdown with a link [example](https://example.com)")
.environment(\.openURL, OpenURLAction { url in
// ... set state that will cause your web view to be loaded...
return .handled
})
The OpenURLAction
has to return a value of type OpenURLAction.Result
- here, .handled
tells the system that you have dealt with the URL yourself so the OS doesn't have to do anything else.
You could also include certain logic such that if (for example) the URLs pointed to specific hosts, you handled them, but everything else should open in Safari; in that case, you'd return .handled
for the URLs you're taking responsibility for, and .systemAction
for any URL where the default behaviour should be used.
Other return types include .discarded
to tell the app to ignore the tap on the link, and a version of .systemAction
that allows you to redefine the link that opens in Safari. I don't think either fit your use case here, though.
This post on fivestars.blog goes into more detail. Also check out the openURL
and OpenURLAction
documentation.
Related Topics
How to Open a Screen Directly in Xcuitest
Add Constraints to Generic Parameters in Extension
Swiftui Label Text and Image Vertically Misaligned
How to Avoid That My Swift Async Method Runs on the Main Thread in Swiftui
Swift Switch Statement Considered All Cases of Int, But Compiler Still Display Error
How to Generate a Binding for Each Array Element
Swiftui Present Alert with Input Field
How to Bring Nswindow to Front and to the Current Space
How to Save Document to "Files" App in Swift
Continuously Train Coreml Model After Shipping
Modal View Closes When Selecting an Image in Uiwebview iOS
If the Swift 'Guard' Statement Must Exit Scope, What Is the Definition of Scope
Alamofire Type 'Parameterencoding' Has No Member 'Url' Swift 3
Extension for Generic Type 'Unsafemutablepointer<Uint8>'
Nstimer.Scheduledtimerwithtimeinterval in Swift Playground
Opposite of _Conversion in Swift to Assign to a Value of a Different Type
Why Is the Alert Triggering Out of Order If Value Is Not Updated