SwiftUI WebView pro iOS 26: Kompletní průvodce zobrazením webu

Nativní SwiftUI WebView v iOS 26 konečně řeší zobrazení webového obsahu bez UIKit wrapperů. Naučte se používat WebView a WebPage pro načítání stránek, spouštění JavaScriptu, řízení navigace a vlastní URL schémata.

Konec éry UIViewRepresentable pro webový obsah

Ruku na srdce — pokud jste někdy potřebovali zobrazit webovou stránku uvnitř SwiftUI aplikace, víte, jaký to byl boj. Vytvořit UIViewRepresentable wrapper kolem WKWebView, řešit delegáty, aktualizace stavu, koordinátory… Bylo to zbytečně složité na něco tak základního.

V iOS 26 to Apple konečně vyřešil. Představil nativní WebView přímo ve SwiftUI — jednoduchý, deklarativní a plně integrovaný do ekosystému. Jeden řádek kódu a máte plnohodnotný webový prohlížeč ve vaší aplikaci. Vážně, jeden řádek.

Pojďme si projít všechno od základního použití až po pokročilé věci jako spouštění JavaScriptu, řízení navigace nebo vlastní URL schémata.

Požadavky a import

Nativní WebView vyžaduje iOS 26 (případně macOS 26 nebo visionOS 3) jako minimální cílovou platformu. Kromě SwiftUI je nutné importovat i framework WebKit:

import SwiftUI
import WebKit

Pokud vaše aplikace cílí na starší verze iOS, budete muset nadále používat WKWebView přes UIViewRepresentable. Nebojte, k tomu se vrátíme na konci článku.

Základní zobrazení webové stránky

Nejjednodušší způsob, jak zobrazit webovou stránku ve SwiftUI, je předat URL přímo do WebView:

import SwiftUI
import WebKit

struct ContentView: View {
    var body: some View {
        WebView(url: URL(string: "https://www.swift.org"))
    }
}

A to je celé. Plně funkční webový prohlížeč — se scrollováním, fungujícími odkazy, videem i JavaScriptem. Parametr url je navíc volitelný (URL?), takže žádný force unwrap.

Pro plné využití obrazovky stačí přidat .ignoresSafeArea():

struct FullScreenWebView: View {
    var body: some View {
        WebView(url: URL(string: "https://www.swift.org"))
            .ignoresSafeArea()
    }
}

WebPage: Kdy potřebujete víc kontroly

Jednoduchý WebView(url:) je fajn pro statické zobrazení, ale co když chcete sledovat průběh načítání, zjistit titul stránky, spouštět JavaScript nebo řídit navigaci? Přesně na to je třída WebPage.

WebPage je Observable třída, takže automaticky aktualizuje vaše SwiftUI views, když se změní její vlastnosti. Vytvoříte ji jako @State property a předáte do WebView:

struct WebPageDemoView: View {
    @State private var page = WebPage()

    var body: some View {
        VStack {
            // Zobrazení titulu a URL stránky
            if let title = page.title {
                Text(title)
                    .font(.headline)
            }

            if let url = page.url {
                Text(url.absoluteString)
                    .font(.caption)
                    .foregroundStyle(.secondary)
            }

            WebView(page)
                .ignoresSafeArea()
        }
        .onAppear {
            if let url = URL(string: "https://www.swift.org") {
                page.load(URLRequest(url: url))
            }
        }
    }
}

Klíčové vlastnosti WebPage

Protože WebPage je Observable, všechny tyto vlastnosti automaticky spouštějí překreslení:

  • page.title — aktuální titul stránky (String?)
  • page.url — aktuální URL (URL?)
  • page.estimatedProgress — průběh načítání od 0.0 do 1.0 (Double)
  • page.isLoading — zda se stránka právě načítá (Bool)
  • page.backForwardList — historie navigace pro zpětnou/dopřednou navigaci

Sledování průběhu načítání

Asi nejčastější požadavek — ukázat uživateli, jak daleko je načítání. S WebPage je to opravdu triviální:

struct ProgressWebView: View {
    @State private var page = WebPage()

    var body: some View {
        VStack(spacing: 0) {
            if page.isLoading {
                ProgressView(value: page.estimatedProgress)
                    .progressViewStyle(.linear)
            }

            WebView(page)
                .ignoresSafeArea()
        }
        .onAppear {
            if let url = URL(string: "https://www.apple.com") {
                page.load(URLRequest(url: url))
            }
        }
    }
}

Vlastnost estimatedProgress se plynule aktualizuje během načítání, takže ProgressView reaguje v reálném čase. Jakmile stránka doběhne, isLoading se přepne na false a progress bar prostě zmizí. Žádný ruční state management.

Navigační ovládání: Zpět, vpřed, obnovit

Přidání navigačních tlačítek je díky WebPage celkem přímočaré:

struct BrowserView: View {
    @State private var page = WebPage()

    var body: some View {
        VStack(spacing: 0) {
            if page.isLoading {
                ProgressView(value: page.estimatedProgress)
                    .progressViewStyle(.linear)
            }

            WebView(page)
                .ignoresSafeArea()

            HStack {
                Button("Zpět") {
                    if let item = page.backForwardList.backItem {
                        page.load(item)
                    }
                }
                .disabled(page.backForwardList.backItem == nil)

                Button("Vpřed") {
                    if let item = page.backForwardList.forwardItem {
                        page.load(item)
                    }
                }
                .disabled(page.backForwardList.forwardItem == nil)

                Spacer()

                Button("Obnovit") {
                    page.reload()
                }

                Button("Stop") {
                    page.stopLoading()
                }
                .disabled(!page.isLoading)
            }
            .padding()
        }
        .onAppear {
            if let url = URL(string: "https://www.swift.org") {
                page.load(URLRequest(url: url))
            }
        }
    }
}

Navigace zpět a vpřed používá backForwardList — stejný koncept jako u klasického WKWebView, ale plně integrovaný do reaktivního modelu SwiftUI. Pokud jste někdy psali delegáta jen proto, abyste zjistili, jestli je tlačítko Zpět aktivní, tohle vás potěší.

View modifikátory pro WebView

SwiftUI WebView přichází s vlastní sadou modifikátorů pro přizpůsobení chování:

WebView(page)
    .webViewBackForwardNavigationGestures(.enabled)
    .webViewMagnificationGestures(.enabled)
    .webViewLinkPreviews(.disabled)
    .webViewContentBackground(.hidden)

Tady je přehled toho, co máte k dispozici:

ModifikátorPopis
webViewBackForwardNavigationGesturesPovolí/zakáže gesta pro přejetí zpět/vpřed
webViewMagnificationGesturesPovolí/zakáže gesto pinch-to-zoom
webViewLinkPreviewsPovolí/zakáže náhledy odkazů při dlouhém stisku
webViewContentBackgroundSkryje pozadí stránky pro vlastní SwiftUI pozadí
webViewScrollPositionNapojí scroll pozici na ScrollPosition binding
webViewOnScrollGeometryChangeReaguje na změny scroll geometrie
findNavigatorZobrazí/skryje rozhraní pro hledání na stránce

Transparentní pozadí

Modifikátor webViewContentBackground(.hidden) se hodí, když chcete za webový obsah umístit vlastní SwiftUI pozadí. Třeba gradient:

WebView(page)
    .webViewContentBackground(.hidden)
    .background(
        LinearGradient(
            colors: [.blue, .purple],
            startPoint: .top,
            endPoint: .bottom
        )
    )

Hledání na stránce

Implementace funkce „Najít na stránce" je překvapivě jednoduchá — osobně jsem čekal, že to bude složitější:

struct SearchableWebView: View {
    @State private var page = WebPage()
    @State private var showFind = false

    var body: some View {
        WebView(page)
            .findNavigator(isPresented: $showFind)
            .toolbar {
                Button("Hledat") {
                    showFind.toggle()
                }
            }
            .onAppear {
                if let url = URL(string: "https://www.swift.org") {
                    page.load(URLRequest(url: url))
                }
            }
    }
}

Spouštění JavaScriptu

Tady to začíná být opravdu zajímavé. Komunikace s webovým obsahem přes JavaScript je jedna z nejsilnějších stránek nového WebView. Metoda callJavaScript na WebPage podporuje async/throws:

struct JavaScriptDemoView: View {
    @State private var page = WebPage()
    @State private var pageTitle = ""

    var body: some View {
        VStack {
            Text("Titul stránky: \(pageTitle)")
                .font(.headline)

            WebView(page)
                .ignoresSafeArea()
        }
        .onAppear {
            if let url = URL(string: "https://www.swift.org") {
                page.load(URLRequest(url: url))
            }
        }
        .task {
            // Počkáme, až se stránka načte
            while page.isLoading {
                try? await Task.sleep(for: .milliseconds(100))
            }

            // Spustíme JavaScript
            do {
                let result = try await page.callJavaScript("document.title")
                if let title = result as? String {
                    pageTitle = title
                }
            } catch {
                print("Chyba JS: \(error)")
            }
        }
    }
}

Pokročilý příklad: Extrakce obsahu stránky

Představte si, že chcete z načtené stránky vytáhnout všechny nadpisy a vytvořit z nich navigační menu. S callJavaScript a pojmenovanými argumenty to jde elegantně:

struct TableOfContentsView: View {
    @State private var page = WebPage()
    @State private var headers: [(id: String, title: String)] = []

    var body: some View {
        HStack {
            // Sidebar s obsahem
            List(headers, id: \.id) { header in
                Button(header.title) {
                    Task {
                        try? await page.callJavaScript(
                            "document.getElementById(arguments.sectionId)?.scrollIntoView({behavior: 'smooth'})",
                            arguments: ["sectionId": header.id]
                        )
                    }
                }
            }
            .frame(width: 250)

            // Webový obsah
            WebView(page)
        }
        .task {
            if let url = URL(string: "https://www.swift.org/documentation/") {
                page.load(URLRequest(url: url))
            }

            while page.isLoading {
                try? await Task.sleep(for: .milliseconds(100))
            }

            await extractHeaders()
        }
    }

    private func extractHeaders() async {
        let js = """
            const headers = document.querySelectorAll("h2, h3")
            return [...headers].map(h => ({
                id: h.id || h.textContent.replaceAll(" ", "-").toLowerCase(),
                title: h.textContent
            }))
            """
        do {
            let result = try await page.callJavaScript(js)
            if let items = result as? [[String: Any]] {
                headers = items.compactMap { item in
                    guard let id = item["id"] as? String,
                          let title = item["title"] as? String else { return nil }
                    return (id: id, title: title)
                }
            }
        } catch {
            print("Chyba při extrakci nadpisů: \(error)")
        }
    }
}

Za zmínku stojí, že callJavaScript přijímá pojmenované argumenty přes parametr arguments — v JavaScriptu jsou pak dostupné přes objekt arguments. Výsledek je typu Any?, takže ho musíte přetypovat.

Načítání lokálního HTML

Kromě vzdálených URL můžete načíst i lokální HTML — ať už jako řetězec nebo ze souboru v bundle:

struct LocalHTMLView: View {
    @State private var page = WebPage()

    var body: some View {
        WebView(page)
            .onAppear {
                let html = """
                    <!DOCTYPE html>
                    <html>
                    <head>
                        <meta charset="utf-8">
                        <meta name="viewport" content="width=device-width, initial-scale=1">
                        <style>
                            body {
                                font-family: -apple-system, system-ui;
                                padding: 20px;
                                color: #333;
                            }
                            h1 { color: #007AFF; }
                        </style>
                    </head>
                    <body>
                        <h1>Ahoj ze SwiftUI!</h1>
                        <p>Toto je lokální HTML obsah načtený přes WebPage.</p>
                    </body>
                    </html>
                    """
                page.load(
                    html: html,
                    baseURL: Bundle.main.resourceURL!
                )
            }
    }
}

Použití Bundle.main.resourceURL! jako baseURL umožňuje HTML odkazovat na soubory v bundle — styly CSS, obrázky, skripty. Šikovné, pokud stavíte hybridní aplikaci s částí UI v HTML.

Řízení navigace s NavigationDeciding

Protokol WebPage.NavigationDeciding vám dává plnou kontrolu nad tím, kam se uživatel může z vašeho WebView dostat. Klasický případ: chcete povolit navigaci v rámci vaší domény, ale externí odkazy otevřít v Safari.

class AppNavigationDecider: WebPage.NavigationDeciding {
    let allowedHost: String

    init(allowedHost: String) {
        self.allowedHost = allowedHost
    }

    func decidePolicy(
        for action: WebPage.NavigationAction,
        preferences: inout WebPage.NavigationPreferences
    ) async -> WKNavigationActionPolicy {
        guard let url = action.request.url else { return .cancel }

        // Povolíme navigaci v rámci naší domény
        if url.host == allowedHost {
            return .allow
        }

        // Externí odkazy otevřeme v Safari
        await UIApplication.shared.open(url)
        return .cancel
    }
}

struct ControlledWebView: View {
    @State private var page: WebPage

    init() {
        let decider = AppNavigationDecider(allowedHost: "www.swift.org")
        _page = State(initialValue: WebPage(navigationDecider: decider))
    }

    var body: some View {
        WebView(page)
            .ignoresSafeArea()
            .onAppear {
                if let url = URL(string: "https://www.swift.org") {
                    page.load(URLRequest(url: url))
                }
            }
    }
}

NavigationDeciding umožňuje specifikovat politiky pro různé fáze navigace — před zahájením, po obdržení odpovědi nebo při potřebě autentizace. Pro hybridní aplikace je to neocenitelné.

Vlastní URL schémata

Pro pokročilé hybridní aplikace nabízí WebPage podporu vlastních URL schémat přes protokol URLSchemeHandler. Můžete tak načítat lokální zdroje přes vlastní schéma (a vyhnout se bezpečnostním omezením u file://):

struct LocalContentSchemeHandler: URLSchemeHandler {
    func reply(
        for request: URLRequest
    ) -> some AsyncSequence<URLSchemeTaskResult, any Error> {
        AsyncThrowingStream { continuation in
            guard
                let fileName = request.url?.host,
                let bundleURL = Bundle.main.url(
                    forResource: fileName,
                    withExtension: nil
                ),
                let data = try? Data(contentsOf: bundleURL)
            else {
                continuation.finish(
                    throwing: URLError(.badURL)
                )
                return
            }

            let response = URLResponse(
                url: request.url!,
                mimeType: "text/html",
                expectedContentLength: data.count,
                textEncodingName: "utf-8"
            )

            continuation.yield(.response(response))
            continuation.yield(.data(data))
            continuation.finish()
        }
    }
}

struct CustomSchemeView: View {
    @State private var page: WebPage

    init() {
        let scheme = URLScheme("moje-app")!
        var config = WebPage.Configuration()
        config.urlSchemeHandlers[scheme] = LocalContentSchemeHandler()
        _page = State(initialValue: WebPage(configuration: config))
    }

    var body: some View {
        WebView(page)
            .onAppear {
                if let url = URL(string: "moje-app://index.html") {
                    page.load(URLRequest(url: url))
                }
            }
    }
}

Vlastní URL schémata se hodí hlavně pro:

  • Načítání lokálního HTML/CSS/JS obsahu z bundle
  • Offline-first hybridní aplikace
  • Bezpečné oddělení lokálních zdrojů od vzdáleného obsahu

Konfigurace WebPage

Třída WebPage.Configuration umožňuje přizpůsobit chování webového obsahu ještě před jeho načtením:

var config = WebPage.Configuration()

// Přizpůsobení user agent řetězce
config.applicationNameForUserAgent = "MojeAplikace/1.0"

// Povolení AirPlay pro média
config.allowsAirPlayForMediaPlayback = true

// Detekce typů dat (telefony, adresy, odkazy)
config.dataDetectorTypes = [.phoneNumber, .link, .address]

let page = WebPage(configuration: config)

Důležité — konfiguraci musíte nastavit před vytvořením instance WebPage. Po inicializaci ji už nelze měnit.

Sledování scroll pozice

Modifikátor webViewScrollPosition umožňuje napojit pozici scrollu na SwiftUI ScrollPosition. To otevírá zajímavé možnosti — třeba synchronizaci scrollu s dalšími UI prvky nebo vytvoření „scroll to top" tlačítka:

struct ScrollTrackingWebView: View {
    @State private var page = WebPage()
    @State private var scrollPosition = ScrollPosition()
    @State private var currentOffset: CGFloat = 0

    var body: some View {
        VStack {
            Text("Scroll offset: \(Int(currentOffset)) px")
                .font(.caption)
                .padding(.horizontal)

            WebView(page)
                .webViewScrollPosition($scrollPosition)
                .webViewOnScrollGeometryChange(
                    for: CGFloat.self,
                    of: \.contentOffset.y
                ) { _, newValue in
                    currentOffset = newValue
                }
                .ignoresSafeArea()
        }
        .onAppear {
            if let url = URL(string: "https://www.swift.org/documentation/") {
                page.load(URLRequest(url: url))
            }
        }
    }
}

Programatický scroll na konkrétní pozici je taky jednoduchý:

withAnimation(.easeInOut(duration: 0.25)) {
    scrollPosition.scrollTo(y: 500)
}

Sledování navigačních událostí

Pro komplexnější scénáře má WebPage property navigations — je to AsyncSequence navigačních událostí. Můžete tak reagovat na různé fáze navigace a třeba zobrazit stavovou zprávu:

struct EventTrackingWebView: View {
    @State private var page = WebPage()
    @State private var statusMessage = "Připraven"

    var body: some View {
        VStack {
            Text(statusMessage)
                .font(.caption)
                .foregroundStyle(.secondary)

            WebView(page)
                .ignoresSafeArea()
        }
        .onAppear {
            if let url = URL(string: "https://www.swift.org") {
                page.load(URLRequest(url: url))
            }
        }
        .task {
            await observeNavigation()
        }
    }

    private func observeNavigation() async {
        let eventStream = Observations { page.navigations }
        for await observation in eventStream {
            do {
                for try await event in observation {
                    switch event {
                    case .startedProvisionalNavigation:
                        statusMessage = "Načítání..."
                    case .committed:
                        statusMessage = "Vykreslování obsahu..."
                    case .finished:
                        statusMessage = "Hotovo"
                    case .receivedServerRedirect:
                        statusMessage = "Přesměrování..."
                    @unknown default:
                        break
                    }
                }
            } catch {
                statusMessage = "Chyba: \(error.localizedDescription)"
            }
        }
    }
}

WebView vs WKWebView vs SFSafariViewController: Kdy co použít

S příchodem nativního WebView máte teď tři možnosti pro zobrazení webového obsahu. Každá má své místo a je dobré vědět, kdy sáhnout po které:

VlastnostSwiftUI WebViewWKWebViewSFSafariViewController
Nativní SwiftUIAnoVyžaduje UIViewRepresentableVyžaduje UIViewControllerRepresentable
Přizpůsobitelné UIAnoPlná kontrolaMinimální
Spouštění JavaScriptuAno (přes WebPage)AnoNe
Sdílení cookies se SafariNeNeAno
Password AutoFillNeNeAno
Minimální iOS verzeiOS 26iOS 8iOS 9
Podpora macOSAno (macOS 26)AnoNe

Takže v kostce:

  • SwiftUI WebView — pro nové aplikace cílící na iOS 26+, kde chcete čistý deklarativní kód
  • WKWebView — pokud potřebujete podporu starších verzí iOS nebo plnou kontrolu nad konfigurací
  • SFSafariViewController — když chcete poskytnout kompletní Safari zážitek včetně sdílených cookies a doplňování hesel (typicky pro OAuth přihlašování)

Migrace z WKWebView na nativní WebView

Pokud máte existující kód s UIViewRepresentable wrapperem kolem WKWebView, migrace je překvapivě přímočará. Podívejte se na ten rozdíl:

Starý přístup (před iOS 26)

// Starý přístup — desítky řádků boilerplate kódu
struct LegacyWebView: UIViewRepresentable {
    let url: URL

    func makeUIView(context: Context) -> WKWebView {
        let webView = WKWebView()
        webView.navigationDelegate = context.coordinator
        return webView
    }

    func updateUIView(_ webView: WKWebView, context: Context) {
        webView.load(URLRequest(url: url))
    }

    func makeCoordinator() -> Coordinator {
        Coordinator()
    }

    class Coordinator: NSObject, WKNavigationDelegate {
        func webView(
            _ webView: WKWebView,
            didFinish navigation: WKNavigation!
        ) {
            // Stránka načtena
        }

        func webView(
            _ webView: WKWebView,
            didFail navigation: WKNavigation!,
            withError error: Error
        ) {
            // Chyba
        }
    }
}

Nový přístup (iOS 26+)

// Nový přístup — čistý, deklarativní, bezpečný
struct ModernWebView: View {
    @State private var page = WebPage()

    var body: some View {
        WebView(page)
            .onAppear {
                page.load(URLRequest(url: URL(string: "https://www.swift.org")!))
            }
    }
}

Méně kódu, žádné koordinátory, žádné delegáty, a plná typová bezpečnost díky Swift concurrency. Upřímně, tohle je jeden z těch případů, kdy nové API opravdu stojí za ten přechod.

Praktický příklad: Mini prohlížeč

Na závěr si pojďme postavit kompletní mini prohlížeč, který kombinuje všechny techniky z tohoto článku. Je to trochu delší kus kódu, ale výsledek stojí za to:

struct MiniBrowserView: View {
    @State private var page = WebPage()
    @State private var urlText = "https://www.swift.org"
    @State private var showFind = false

    var body: some View {
        NavigationStack {
            VStack(spacing: 0) {
                // Adresní řádek
                HStack {
                    TextField("URL adresa", text: $urlText)
                        .textFieldStyle(.roundedBorder)
                        .textInputAutocapitalization(.never)
                        .autocorrectionDisabled()
                        .onSubmit {
                            loadURL()
                        }

                    Button("Jít") {
                        loadURL()
                    }
                    .buttonStyle(.bordered)
                }
                .padding(.horizontal)
                .padding(.vertical, 8)

                // Progress bar
                if page.isLoading {
                    ProgressView(value: page.estimatedProgress)
                        .progressViewStyle(.linear)
                }

                // Webový obsah
                WebView(page)
                    .webViewBackForwardNavigationGestures(.enabled)
                    .webViewMagnificationGestures(.enabled)
                    .findNavigator(isPresented: $showFind)
                    .ignoresSafeArea(edges: .bottom)
            }
            .navigationTitle(page.title ?? "Prohlížeč")
            .navigationBarTitleDisplayMode(.inline)
            .toolbar {
                ToolbarItemGroup(placement: .bottomBar) {
                    Button(action: {
                        if let item = page.backForwardList.backItem {
                            page.load(item)
                        }
                    }) {
                        Image(systemName: "chevron.left")
                    }
                    .disabled(page.backForwardList.backItem == nil)

                    Button(action: {
                        if let item = page.backForwardList.forwardItem {
                            page.load(item)
                        }
                    }) {
                        Image(systemName: "chevron.right")
                    }
                    .disabled(page.backForwardList.forwardItem == nil)

                    Spacer()

                    Button(action: { showFind.toggle() }) {
                        Image(systemName: "doc.text.magnifyingglass")
                    }

                    if page.isLoading {
                        Button(action: { page.stopLoading() }) {
                            Image(systemName: "xmark")
                        }
                    } else {
                        Button(action: { page.reload() }) {
                            Image(systemName: "arrow.clockwise")
                        }
                    }
                }
            }
        }
        .onAppear {
            loadURL()
        }
    }

    private func loadURL() {
        var finalURL = urlText
        if !finalURL.hasPrefix("http://") && !finalURL.hasPrefix("https://") {
            finalURL = "https://" + finalURL
        }
        if let url = URL(string: finalURL) {
            page.load(URLRequest(url: url))
        }
    }
}

Adresní řádek, progress bar, navigace zpět/vpřed, obnovení stránky, hledání na stránce a podpora gest. To vše v čistém SwiftUI — bez jediného řádku UIKit kódu. Kdyby mi to někdo řekl před pár lety, nevěřil bych.

Často kladené otázky

Mohu použít SwiftUI WebView na starších verzích iOS?

Bohužel ne. Nativní WebView je dostupný pouze od iOS 26 (macOS 26, visionOS 3). Pro starší verze musíte nadále používat WKWebView zabalený v UIViewRepresentable. Dobrá zpráva je, že oba přístupy mohou koexistovat ve stejném projektu — stačí použít #available(iOS 26, *) pro podmíněné využití nového API.

Jaký je rozdíl mezi WebView a WebPage?

WebView je SwiftUI view — vizuální komponenta, která zobrazuje webový obsah na obrazovce. WebPage je Observable model, který ten obsah representuje a dává vám API pro jeho ovládání. Jednoduchý WebView(url:) stačí pro statické zobrazení, ale pro jakoukoliv interakci potřebujete WebPage.

Podporuje nový WebView spouštění JavaScriptu?

Ano, přes třídu WebPage a metodu callJavaScript(_:arguments:). Je asynchronní a throwable, takže se přirozeně integruje se Swift concurrency. Výsledek je typu Any?, který musíte přetypovat na očekávaný typ. Podporuje taky pojmenované argumenty, což je příjemné pro čitelnost kódu.

Mohu ve WebView zobrazit lokální HTML soubory?

Jasně. WebPage podporuje načítání lokálního HTML přes metodu load(html:baseURL:). Jako baseURL doporučuju použít Bundle.main.resourceURL, což umožní HTML odkazovat na další soubory v bundle (CSS, obrázky, skripty). Pro sofistikovanější řešení můžete využít vlastní URL schémata přes URLSchemeHandler.

Jak se SwiftUI WebView liší od SFSafariViewController?

SFSafariViewController poskytuje kompletní Safari zážitek — sdílení cookies, automatické doplňování hesel, blokování obsahu. Nedá se ale přizpůsobit ani z něj extrahovat data. SwiftUI WebView naopak nabízí plnou kontrolu nad zobrazením a interakcí, podporuje JavaScript a je nativně integrován do SwiftUI. Jednoduché pravidlo: SFSafariViewController pro zobrazení externích webů (třeba OAuth login), WebView pro integraci webového obsahu do vaší aplikace.

O Autorovi Editorial Team

Our team of expert writers and editors.