Link control was launched with iOS 14 and makes it easy for us to launch web page from a URL.
For example, following code will launch DevTechie.com website using URL(go check it out while you are at it 😉)
struct WebPageExample: View {
var body: some View {
Link("DevTechie", destination: URL(string: "https://www.devtechie.com")!)
}
}
This is all fine but with this approach your user is leaving the app and we don’t know if they will come back or be lost in world wide web 😆
We can solve this problem easily, by keeping user inside our app even when they click on a web link. For this, we will need WebKit and its WebView. SwiftUI doesn’t support WebView natively(yet) but we have an easy way to get around it.
We will create UIViewRepresentable for WebView.
Start with import of WebKit
import WebKit
Next, we will create struct called SwiftUIWebView which will conform to UIViewRepresentable protocol as shown below:
struct SwiftUIWebView: UIViewRepresentable { typealias UIViewType = WKWebView func makeUIView(context: Context) -> WKWebView {
} func updateUIView(_ uiView: WKWebView, context: Context) {
}
}
UIViewRepresentable requires two functions to be implemented, called makeUIView and updateUIView
makeUIView function will return instance of WKWebView. We will also create an initializer and load DevTechie.com inside the webview.
struct SwiftUIWebView: UIViewRepresentable {
typealias UIViewType = WKWebView
let webView: WKWebView
init() {
webView = WKWebView(frame: .zero)
webView.load(URLRequest(url: URL(string: "https://www.devtechie.com")!))
}
func makeUIView(context: Context) -> WKWebView {
webView
}
func updateUIView(_ uiView: WKWebView, context: Context) {
}
}
Our SwiftUIWebView is ready so let’s use it in our ContentView
struct WebPageExample: View {
var body: some View {
SwiftUIWebView()
}
}
Building Web Browser
So far we have built a mini web browser but it doesn’t do much except loading a predefined url. How about changing it to a browser where user can type url, go back and forward on a button click?
Let’s build a view model for our webView. This model class will have urlString, we will create a webView and load defined URL inside the webView as shown below:
final class SwiftUIWebViewModel: ObservableObject {
@Published var urlString = "https://www.devtechie.com"
let webView: WKWebView
init() {
webView = WKWebView(frame: .zero)
}
func loadUrl() {
guard let url = URL(string: urlString) else {
return
}
webView.load(URLRequest(url: url))
}
}
Let’s modify our SwiftUIWebView to take webView as a init parameter. This will be done by simply removing init from the previous implementation of SwiftUIWebView and making the view more simple.
struct SwiftUIWebView: UIViewRepresentable {
typealias UIViewType = WKWebView
let webView: WKWebView
func makeUIView(context: Context) -> WKWebView {
webView
}
func updateUIView(_ uiView: WKWebView, context: Context) {
}
}
We will use this model with our WebView as below:
struct WebPageExample: View {
@StateObject private var model = SwiftUIWebViewModel()
var body: some View {
SwiftUIWebView(webView: model.webView)
.onAppear {
model.loadUrl()
}
}
}
Our view is still working the same but now it can support dynamic URL.
Let’s add address bar to our browser. We will add a VStack and add SwiftUIWebView along with a HStack to hold TextField and Go Button as shown below:
struct WebPageExample: View {
@StateObject private var model = SwiftUIWebViewModel()
var body: some View {
VStack {
SwiftUIWebView(webView: model.webView)
HStack {
TextField("Enter url", text: $model.urlString)
.textFieldStyle(.roundedBorder)
Button("Go") {
model.loadUrl()
}
}
.padding()
}
}
}
We will add two functions back and forward to our model as well.
func back() {
webView.goBack()
}func forward() {
webView.goForward()
}
We will use these to go back and forward for our mini web browser. Complete code is listed below:
struct WebPageExample: View {
@StateObject private var model = SwiftUIWebViewModel()
var body: some View {
VStack {
SwiftUIWebView(webView: model.webView)
Group {
HStack {
TextField("Enter url", text: $model.urlString)
.textFieldStyle(.roundedBorder)
Button("Go") {
model.loadUrl()
}
}
HStack {
Spacer()
Button(action: { model.back() }) {
Image(systemName: "arrow.backward")
}
Button(action: { model.forward() }) {
Image(systemName: "arrow.forward")
}
}
}
.padding(.horizontal)
.padding(.vertical, 5)
}
}
}final class SwiftUIWebViewModel: ObservableObject {
@Published var urlString = "https://www.devtechie.com"
let webView: WKWebView
init() {
webView = WKWebView(frame: .zero)
}
func loadUrl() {
guard let url = URL(string: urlString) else {
return
}
webView.load(URLRequest(url: url))
}
func back() {
webView.goBack()
}
func forward() {
webView.goForward()
}
}
With that we have reached the end of this article. Thank you once again for reading. Don’t forget to subscribe our weekly newsletter at