Stateful WebView for SwiftUI.

Overview

Stateful SwiftUI WebView for iOS and MacOS

Fully functional, SwiftUI-ready WebView for iOS 13+ and MacOS 10.15+. Actions and state are both delivered via SwiftUI @Bindings, meaking it dead-easy to integrate into any existing SwiftUI View.

Preview iOS

Preview macOS

Installation

This component is distributed as a Swift package.

Sample usage

  • The action binding is used to control the WebView - whichever action you want it to perform, just set the variable's value to it. Available actions:
    • idle - does nothing and can be used as the default value.
    • load(URLRequest) - loads the given request.
    • loadHTML(String) - loads custom HTML string.
    • reload
    • goBack
    • goForward
  • The state binding reports back the current state of the WebView. Available data:
    • isLoading - true if the WebView is currently loading a page.
    • pageTitle - the title of the currently loaded page, or nil if it can't be obtained.
    • pageHTML - the HTML code of the page content. Set htmlInState: true in WebView initializer to receive this update.
    • error - set if an error ocurred while loading the page, nil otherwise.
    • canGoBack
    • canGoForward
  • The optional restrictedPages array allows you to specify hosts which the web view won't load.
  • htmlInState dictates if the state update will contain pageHTML. This is disabled by default as it's a costly operation.
import SwiftUIWebView

struct WebViewTest: View {
    @State private var action = WebViewAction.idle
    @State private var state = WebViewState.empty
    @State private var address = "https://www.google.com"
    
    var body: some View {
        VStack {
            titleView
            navigationToolbar
            errorView
            Divider()
            WebView(action: $action,
                    state: $state,
                    restrictedPages: ["apple.com"])
            Spacer()
        }
    }
    
    private var titleView: some View {
        Text(state.pageTitle ?? "Load a page")
            .font(.system(size: 24))
    }
    
    private var navigationToolbar: some View {
        HStack(spacing: 10) {
            TextField("Address", text: $address)
            if state.isLoading {
                if #available(iOS 14, macOS 10.15, *) {
                    ProgressView()
                        .progressViewStyle(CircularProgressViewStyle())
                } else {
                    Text("Loading")
                }
            }
            Spacer()
            Button("Go") {
                if let url = URL(string: address) {
                    action = .load(URLRequest(url: url))
                }
            }
            Button(action: {
                action = .reload
            }) {
                Image(systemName: "arrow.counterclockwise")
                    .imageScale(.large)
            }
            if state.canGoBack {
                Button(action: {
                    action = .goBack
                }) {
                    Image(systemName: "chevron.left")
                        .imageScale(.large)
                }
            }
            if state.canGoForward {
                Button(action: {
                    action = .goForward
                }) {
                Image(systemName: "chevron.right")
                    .imageScale(.large)
                    
                }
            }
        }.padding()
    }
    
    private var errorView: some View {
        Group {
            if let error = state.error {
                Text(error.localizedDescription)
                    .foregroundColor(.red)
            }
        }
    }
}

Recipe

For a more detailed description of the code, visit this recipe. Check out SwiftUIRecipes.com for more SwiftUI recipes!

Comments
  • Potential multiple executions of go back and go forward

    Potential multiple executions of go back and go forward

    When setting .action to .goBack resp. .goForward it is possible that the corresponding go-back resp. go-forward action is executed more than once. This behavior is already exhibited by the small browser app. I believe this is due to DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) { action = .idle } which leaves a window open for multiple executions. Unfortunately the simple action = .idle leads to warnings claiming undefined behavior.

    opened by psco 5
  • Missing canGoBack state update

    Missing canGoBack state update

    It appears that the canGoBack state is not always updated when it changes. This can result e.g. in a go-back-button not being shown even though go-back would be possible. As a fix I suggest to extend the state update logic in public func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) to cover an update to canGoBack besides the update to isLoading. Probably canGoForward should be handled similarly.

    opened by psco 3
  • Save Cookies

    Save Cookies

    Hello, it would be great to be able to give the option to save and read the cookies, I will integrate this Liberia in my application and I will use it to log in to a website and save the cookies to use them in HTTP requests, because said website does not contain an API. Thanks for the contribution 💚

    opened by The0verlay 2
  • 'mediaPlaybackRequiresUserAction' was deprecated in iOS 9.0

    'mediaPlaybackRequiresUserAction' was deprecated in iOS 9.0

    I consistently get a warning from Xcode Version 13.2.1 (13C100) when compiling a project against SwiftUIWebView 1.0.3:

    swiftui-webview/Sources/SwiftUIWebView/SwiftUIWebView.swift:214:23: 'mediaPlaybackRequiresUserAction' was deprecated in iOS 9.0
    
    opened by fletch29 2
  • Links with target=

    Links with target="_blank" not loading

    Hello,

    When clicking on a link with the target="_blank" attribute nothing happens.

    Appears some special logic needs to be added to a delegate method to allow this to work. https://stackoverflow.com/questions/66700248/how-to-open-urls-with-target-blank-in-safari-wkwebview-webkit

    opened by WingedToaster 1
  • Add ability to grab pageURL as a state object

    Add ability to grab pageURL as a state object

    Love your work on this, makes it so much easier for me to implement swiftui webview. I was playing around with it to see if I can save the page's url but because the your webview package is constructed on load i couldnt use the general " webView.url" call.

    I added the following code on your WebViewCoordinator extension after calling " public internal(set) var pageURL: String? " on your WebViewState constructor

    webView.evaluateJavaScript("document.URL.toString()") { (response, error) in if let url = response as? String { var newState = self.webView.state newState.pageURL = url self.webView.state = newState } }

    Think itd be a great function to have especially for newbies like me so they dont have to go chasing around the code trying to figure out how to load the url : )

    opened by DaeheeCodes 1
  • Possibly missing setLoading(false)

    Possibly missing setLoading(false)

    I think there should also be a setLoading(false) after decisionHandler(.cancel). I'm quite sure for the second occurrence (i.e. where the scheme handler is invoked) but cannot really tell for the first case as I have removed this feature for my case.

    I noticed this with a scheme handler for itms-apps which just invokes the app store: When returning from the app store the loading wheel was still spinning.

    opened by psco 1
  • Keyboard Support

    Keyboard Support

    Entering text using the Magic Keyboard does not work. No text is entered, nor does pasting via keyboard shortcuts.

    I am using an iPad Pro with a Magic Keyboard on Swift Playgrounds 4.1. May not be supported but wanted to mention it.

    opened by vikemosabe 0
Owner
Gordan Glavaš
Gordan Glavaš
A SwiftUI implementation of React Hooks. Enhances reusability of stateful logic and gives state and lifecycle to function view.

SwiftUI Hooks A SwiftUI implementation of React Hooks. Enhances reusability of stateful logic and gives state and lifecycle to function view. Introduc

Ryo Aoyama 441 Jan 6, 2023
Example usage of FingerprintJS Pro inside a iOS WebView.

FingerprintJS Pro iOS Integrations An example app and packages demonstrating FingerprintJS Pro capabilities on the iOS platform. The repository illust

FingerprintJS 34 Nov 30, 2022
Example usage of FingerprintJS Pro inside a iOS WebView.

FingerprintJS Pro iOS Integrations An example app and packages demonstrating FingerprintJS Pro capabilities on the iOS platform. The repository illust

FingerprintJS 34 Nov 30, 2022
Single Webview project for xcode in swift

Single Webview project for xcode in swift An xcode project that with single webview(UIWebView) that opens external URL, for hybrid web app debug or te

null 0 Dec 11, 2021
🎲 100% SwiftUI 2.0, classic 2048 game [SwiftUI 2.0, iOS 14.0+, iPadOS 14.0+, macOS 11.0+, Swift 5.3].

swiftui-2048 If you like the project, please give it a star ⭐ It will show the creator your appreciation and help others to discover the repo. ✍️ Abou

Astemir Eleev 174 Dec 17, 2022
A simple SwiftUI Application to demonstrate creation of UI using SwiftUI.

WatchShop_UI A simple SwiftUI Application to demonstrate creation of UI using SwiftUI. How to run the project ? Fork the project. Run the project usin

Shubham Kr. Singh 12 Apr 15, 2022
E-commerce app built in SwiftUI. Built in the course SwiftUI Masterclass in Udemy.

Touchdown-SwiftUI E-commerce app built in SwiftUI. Built in the course SwiftUI Masterclass in Udemy. Main components and concepts used: @EnvironmentOb

Jorge Martinez 5 Aug 18, 2022
A multiplatform SwiftUI project demonstrating various SwiftUI features.

WikiDemo A multiplatform SwiftUI project demonstrating various SwiftUI features, including creating a master-detail interface. It's a multiplatform ve

Swift Dev Journal 6 Oct 17, 2022
SwiftUI Projects from Udemy SwiftUI Masterclass

SwiftUI Masterclass Repos: AsyncImage (N/A) Fructus (finished): an app for getting information about different fruits. Data comes from json files. Afr

Patrick Spafford 1 Mar 3, 2022
Best architecture for SwiftUI + CombineBest architecture for SwiftUI + Combine

Best architecture for SwiftUI + Combine The content of the presentation: First of the proposed architectures - MVP + C Second of the proposed architec

Kyrylo Triskalo 3 Sep 1, 2022
Weather-swiftui - An example of using SwiftUI

weather-swiftui An example of using SwiftUI Installation Get openweather api key

null 0 Jan 1, 2022
Orbit-swiftui - Orbit design system implemented in SwiftUI for iOS

Orbit is a SwiftUI component library which provides developers the easiest possi

Kiwi.com 37 Jan 3, 2023
SwiftUI Resume - A simple resume writed by swiftUI + Combine

SwiftUI_Resume a simple "resume" writed by swiftUI + Combine

null 15 Apr 27, 2022
SwiftUI-MSALSample - Sample project to login with MSAL using SwiftUI

SwiftUI-MSALSample I could not find a good walkthrough on how to implement MSAL

Rob Evans 10 Nov 7, 2022
100-Days-of-SwiftUI - Studying through Paul Hudson's 100 Days of SwiftUI

Hacking with SwiftUI 100 Days of SwiftUI Studying through Paul Hudson's "100 Day

Dean Thompson 3 Aug 29, 2022
Matthew Asaminew 0 Jan 25, 2022
SwiftUI-Card - Simple card ui designed using SwiftUI

SwiftUI - Card Simple card ui designed using SwiftUI Preview

bahri hırfanoğlu 0 Feb 5, 2022
Swiftui-pressed-states-example - Examples of Pressed States in SwiftUI

Examples of Pressed States in SwiftUI pressed-states.mp4

Philip Davis 6 Nov 15, 2022
IOS15-SwiftUI-InAppPurchaseDemo - In-App Purchase Demo app written with SwiftUI

iOS15-SwiftUI-InAppPurchaseDemo In-App Purchase Demo app written with SwiftUI If

null 5 Jul 20, 2022