Technologische Neuigkeiten, Bewertungen und Tipps!

Eine ausführliche Anleitung zu WKWebView

Hinweis: Der folgende Artikel hilft Ihnen weiter: Eine ausführliche Anleitung zu WKWebView

Zurück zum Blog

Sie verwenden WKWebView, um interaktive Webinhalte in Ihrer App anzuzeigen. Ideal zum Anzeigen von HTML-Markup, gestalteten Textinhalten oder vollständigen Webseiten. Es ist, als ob Sie einen kleinen Webbrowser direkt in Ihrer App hätten!

In diesem Tutorial lernen Sie:

  • So verwenden Sie WKWebView mit Swift
  • So reagieren Sie auf Ereignisse und Benutzerinteraktionen mit der Delegation
  • Warum WKWebView nützlich ist und in welchen Szenarien
  • Einige schnelle Tipps, z. B. das Ermitteln der Inhaltsgröße einer Webseite

Die WKWebView-Komponente ist ein Ersatz für die ältere UIWebView-Komponente. Seit iOS 12 ist UIWebView in den iOS SDKs veraltet und wurde durch WKWebView ersetzt. Wenn Ihre App UIWebView verwendet, müssen Sie sie aktualisieren, um WKWebView zu verwenden. Keine Sorge, UIWebView und WKWebView sind von Natur aus ähnlich!

Mit der WKWebView-Klasse können Sie interaktive Webinhalte in Ihrer iOS-App anzeigen, ähnlich wie in einem In-App-Browser. Es ist Teil des WebKit-Frameworks und WKWebView verwendet dieselbe Browser-Engine wie Safari auf iOS und Mac.

Das Hinzufügen einer Webansicht zu Ihrer App ist so einfach wie das Hinzufügen eines UIView oder UIButton zu Ihrem Ansichtscontroller im Interface Builder. Hier ist wie:

  1. Öffnen Sie im Interface Builder das XIB oder Storyboard, zu dem Sie die Webansicht hinzufügen möchten
  2. Suchen Sie die Webansicht oder WKWebView in der Objektbibliothek unten links im Interface Builder
  3. Ziehen Sie ein WKWebView-Objekt per Drag-and-Drop aus der Objektbibliothek auf die Leinwand Ihres View-Controllers und passen Sie dessen Größe und Position an

Es wird empfohlen, in Ihrer View-Controller-Klasse einen Outlet für die Webansicht zu erstellen, z. B.:

@IBOutlet schwache Variable webView:WKWebView?

Vergessen Sie nicht, die Steckdose im Interface Builder anzuschließen! Und Sie müssen auch das WebKit-Framework oben in Ihrem View-Controller importieren:

WebKit importieren

Eindrucksvoll! Laden wir einige interaktive Webinhalte in dieses WKWebView-Objekt.

Zuerst erstellen wir eine Instanz von URLRequest mit den Informationen über die URL, die wir laden möchten. So was:

let request = URLRequest(url: URL(string: „https://learnappmaking.com“)!)

Folgendes passiert:

  • Wir erstellen eine URL-Instanz, indem wir ihr eine URL-Zeichenfolge https://learnappmaking.com bereitstellen. Die Initialisierungs-URL (Zeichenfolge:) kann fehlschlagen, sodass sie Null zurückgibt, wenn die bereitgestellte Zeichenfolge eine ungültige URL ist.
  • Wir sind zu 100 % sicher, dass wir eine gültige URL angegeben haben, daher verwenden wir Force Unwrapping, um das Optionale auszupacken.
  • Das URL-Objekt wird dann dem URLRequest-Initialisierer bereitgestellt, der dann der Anforderungskonstante ein URLRequest-Objekt zuweist.

Als Nächstes verwenden wir diese Anfrage, um die URL in die Webansicht zu laden. So was:

webView?.load(Anfrage)

Angenommen, Sie verwenden ein WKWebView in Ihrem View-Controller, würden Sie den obigen Code zur Funktion viewDidLoad() hinzufügen. So was:

Funktion viewDidLoad() überschreiben
{
super.viewDidLoad()

let request = URLRequest(url: URL(string: „https://learnappmaking.com“)!)

webView?.load(Anfrage)
}

Wenn Sie Ihre App ausführen, werden Sie sehen, dass die Webseite angezeigt wird! Und es ist vollständig interaktiv, sodass Sie wie in einem normalen Browser auf der Webseite navigieren können.

Die einfachste Form einer Webansicht ist wirklich das Nötigste! Sie können jedoch über eine Reihe von Eigenschaften, Objekten und Delegate-Protokollen mit der Webansicht interagieren.

Eine WKWebView-Webansicht verfügt über zwei Hauptdelegatenprotokolle und -eigenschaften:

  • navigationDelegate vom Typ WKNavigationDelegate, das auf Navigationsereignisse reagiert
  • uiDelegate vom Typ WKUIDelegate, das auf Benutzerinteraktionsereignisse reagiert

Von diesen beiden Delegatenprotokollen wird das WKNavigationDelegate wahrscheinlich am häufigsten verwendet. Lassen Sie uns also an einigen Seitennavigationsereignissen teilnehmen! Wir werden dies mit diesen Delegate-Funktionen tun:

  • webView(_:didStartProvisionalNavigation:)
  • webView(_:didCommit:)
  • webView(_:didFinish:)
  • webView(_:didFail:withError:)
  • webView(_:didFailProvisionalNavigation:withError:)

Lassen Sie uns zunächst das Protokoll übernehmen und den WebView-Delegaten festlegen. Hier ist wie:

  1. Fügen Sie das WKNavigationDelegate-Protokoll zur Klassendeklaration Ihres View-Controllers hinzu, etwa: class WebViewController: UIViewController, WKNavigationDelegate
  2. Setzen Sie die Eigenschaft navigationDelegate von webView auf self, bevor Sie die Webanforderung laden, etwa: webView?.navigationDelegate = self

Als nächstes implementieren Sie die fünf zuvor beschriebenen Delegate-Funktionen. Setzen Sie ihre Funktionskörper auf print(#function), damit wir die Reihenfolge sehen können, in der die Funktionen aufgerufen werden.

So was:

func webView(_ webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!)
{
print(#Funktion)
}

Wiederholen Sie dies für die anderen vier Delegate-Funktionen.

Zum Schluss führen Sie die App aus! In der Konsole sehen Sie die Reihenfolge, in der die Delegate-Funktionen aufgerufen werden:

  1. webView(_:didStartProvisionalNavigation:)
  2. webView(_:didCommit:)
  3. webView(_:didFinish:)

Die erste Funktion webView(_:didStartProvisionalNavigation:) wird aufgerufen, wenn die Webansicht mit der Navigation zu einer Seite beginnt. Zu diesem Zeitpunkt wurde die URL-Anfrage gerade an den Webserver gesendet und es ist noch keine Antwort eingegangen.

Die zweite webView(_:didCommit:)-Funktion wird aufgerufen, wenn die Webansicht beginnt, Daten vom Webserver zu empfangen. An diesem Punkt wird versucht, den HTML-Code der Webseite zu laden, da Daten eingehen.

Die dritte Funktion webView(_:didFinish:) wird aufgerufen, wenn die Navigation beendet ist und alle Daten eingegangen sind. Dieses Ereignis fällt normalerweise mit dem JavaScript-Ereignis DOMContentLoaded zusammen, aber beachten Sie, dass auch webView(_:didFinish:) aufgerufen werden kann bevor das HTML-DOM fertig ist.

Wann werden die Fehlerfunktionen aufgerufen? Lass es uns herausfinden!

  • Ändern Sie zunächst die Webseiten-URL der Webansicht in http://example.com
  • Fügen Sie dann print(error) zu den beiden Fehlerfunktionen hinzu. damit wir die Fehlermeldung sehen können
  • Führen Sie abschließend die App erneut aus

In der Konsole sollte nun eine Fehlermeldung angezeigt werden:

Die Ressource konnte nicht geladen werden, da die App Transport Security-Richtlinie die Verwendung einer sicheren Verbindung erfordert.
Dies liegt daran, dass Sie unter iOS standardmäßig nur HTTPS-URLs laden dürfen. Sie können keine HTTP-URL laden, wie wir es getan haben, ohne die sogenannten App Transport Security-Einstellungen zu ändern.

Wofür nutzen Sie also all diese Delegate-Funktionen?

  • Sie können einen Netzwerkaktivitäts-Spinner anzeigen, wenn eine Seitennavigation beginnt
  • Und stoppen Sie die Netzwerkaktivitätsanzeige, wenn die Navigation stoppt
  • Sie können einen Alert-Controller-Dialog anzeigen, wenn Fehler auftreten

Und das ist noch nicht alles, Sie können beispielsweise die Funktion webView(_:decidePolicyFor:decisionHandler:) verwenden, um zu entscheiden, ob eine Seitennavigation erlaubt ist. Und Sie können auf Weiterleitungen und HTTP-Authentifizierungsherausforderungen reagieren und die Wiederherstellung nach einem Absturz nutzen.

Eine Webseite und eine App sind zwei unterschiedliche Umgebungen. Technisch gesehen „weiß“ eine Webseite nicht, dass sie in einem WKWebView ausgeführt wird. Und umgekehrt können Sie vollwertige Web-Apps erstellen, die in Safari unter iOS ausgeführt werden.

Wie interagiert man mit einer Webseite in einem WKWebView? Sie haben mehrere Möglichkeiten.

Einfache Navigation und Interaktionen erfolgen direkt mit Funktionen in der Webview-Instanz, wie zum Beispiel:

  • Load(_:mimeType:characterEncodingName:baseURL:) und LoadHTMLString(_:baseURL:), um Webseiten und HTML direkt zu laden
  • geschätzter Fortschritt, isLoading und hasOnlySecureContent, um den Status der Webseite abzurufen
  • reload() und stopLoading() zum Neuladen bzw. Stoppen des Ladens der Seite
  • goBack(), goForward() und go(to:) für verlaufsbasierte Navigation, wie ein normaler Webbrowser
  • canGoBack, canGoForward und backForwardList, um Informationen zum Navigationsverlauf zu erhalten

Und dann gibt es natürlich noch JavaScript. JavaScript wird zum Codieren von Dingen in Webbrowsern verwendet. JavaScript ist in einem WKWebView standardmäßig aktiviert und Sie können damit tausendundeine Dinge tun. Leider ist die JavaScript-basierte Interaktion zwischen der Webansicht und Ihrer App … gelinde gesagt interessant.

Evaluierung von JavaScript

Ihnen steht eine Funktion zur Verfügung: evaluierenJavaScript(_:completionHandler:). Wenn Sie diese Funktion für eine WKWebView-Instanz aufrufen, wird eine JavaScript-Zeichenfolge an die Webseite gesendet und ausgewertet. Wenn die Auswertung abgeschlossen ist, wird das Ergebnis mit dem „CompletionHandler“-Abschluss zurückgegeben.

Wir werden etwas JavaScript ausführen. Ändern Sie die Funktion webView(_:didFinish:) wie folgt:

func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!)
{
webView.evaluateJavaScript(“navigator.userAgent”,CompletionHandler: { Ergebnis, Fehler in

if let userAgent = result as? Zeichenfolge {
print(userAgent)
}
})
}
Folgendes passiert, wenn die Webansicht die Navigation beendet:

  • Wir senden einen JavaScript-String an die Webansicht. Der navigator.userAgent ist eine Browsereigenschaft, die den User Agent String enthält, einen Text, der den Typ/das Modell des Browsers identifiziert, der die Webseite lädt.
  • Wenn das JavaScript ausgewertet wurde, wird das Ergebnis einem Vervollständigungshandler bereitgestellt. Wir haben einen einfachen Abschluss bereitgestellt, der die userAgent-Konstante ausgibt, wenn es sich um einen Wert vom Typ String handelt.

Sie können nahezu jede Art von JavaScript-Code auswerten. Das bedeutet, dass Sie Elemente untersuchen, die Werte von Eigenschaften überprüfen und Ereignishandler zuweisen können.

Der Nachteil dieses Ansatzes besteht darin, dass es nur eine Möglichkeit gibt: Sie können JavaScript in die Webseite einfügen, aber Sie können nicht in der Webansicht selbst auf Ereignisse reagieren, die in der Webansicht stattfinden.

JavaScript mit WKUserScript

Sie können einen alternativen Ansatz für die Arbeit mit JavaScript und WKWebView verwenden, nämlich die Verwendung eines WKUserScript. Hier ist wie:

let config = WKWebViewConfiguration()
let js = „document.addEventListener(‘click’, function(){ window.webkit.messageHandlers.clickListener.postMessage(‘Mein Hovercraft ist voller Aale!’); })“
let script = WKUserScript(Quelle: js, Injektionszeit: .atDocumentEnd, forMainFrameOnly: false)

config.userContentController.addUserScript(script)
config.userContentController.add(self, Name: „clickListener“)

webView = WKWebView(frame: view.bounds, Konfiguration: config)
view.addSubview(webView!)

Stellen Sie als Nächstes sicher, dass Sie das WKScriptMessageHandler-Delegatprotokoll in die Klassendeklaration Ihres View-Controllers übernehmen. Und fügen Sie Ihrem View Controller die folgende Funktion hinzu:

func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage)
{
print(message.body)
}

was geschieht hier?

Der rote Faden hier ist, dass wir manuell eine Instanz von WKWebView erstellen und ihr ein WKWebViewConfiguration-Objekt zuweisen. Dieses Konfigurationsobjekt erhält ein WKUserScript-Objekt, das JavaScript-Code enthält.

Der JavaScript-Code fügt der Webseite einen Ereignis-Listener hinzu. Dadurch wird jedes Mal, wenn ein Klickereignis auf der Webseite auftritt, eine Nachricht an den clickListener-Nachrichtenhandler gesendet.

Das Benutzerskript wird auch an denselben clickListener-Handler angehängt. Wenn also die Meldung „Mein Luftkissenfahrzeug ist voller Aale!“ erscheint. Wird an den Nachrichtenhandler gesendet, wird die Delegate-Funktion userContentController(_:didReceive:) auf Ihrem View-Controller aufgerufen. Dadurch wird effektiv eine Nachricht von der Webseite an Ihre iOS-App gesendet, und das war vorher nicht möglich!

Wenn Sie das obige Codebeispiel mit dem Code verwenden, den Sie zuvor in diesem Tutorial geschrieben haben, stellen Sie sicher, dass Sie zuerst den Ausgang deaktivieren und die WKWebView-Instanz von Ihrem Ansichtscontroller im Interface Builder entfernen.

Der Nutzen von WKWebView geht über die Anzeige einfacher Webseiten in Ihrer App hinaus. Schließlich können Sie das meiste, was Sie auf einer Webseite tun können, nativ in Ihrer iOS-App programmieren – warum also überhaupt Webansichten verwenden?

Ein besonders nützliches Szenario ist, wenn Sie ein Layout oder eine Benutzeroberfläche mit HTML erstellen möchten. Stellen Sie sich vor, Sie erstellen eine Rezept-App und möchten detaillierte Informationen zum Rezept in einem Detailansicht-Controller anzeigen.

Sie könnten die gesamte Benutzeroberfläche nativ erstellen, mit Ansichten, Schaltflächen und Beschriftungen. Sie können dieselbe Benutzeroberfläche auch mit HTML und CSS erstellen. Sie könnten die Rezept-HTML-Seiten sogar auf einem Webserver speichern und sie im laufenden Betrieb aktualisieren.

Die WKWebView-Funktion, die Sie an dieser Stelle benötigen, ist loadHTMLString(_:baseURL:). Mit dieser Funktion können Sie HTML direkt in der Webansicht laden.

So was:

webView.loadHTMLString(“Bis dann und vielen Dank für all die Fische!“, baseURL: null)

Dadurch wird in der Webansicht eine fette Textzeichenfolge angezeigt. Und natürlich können Sie in der Webansicht jede Art von HTML und CSS laden.

Mit dem Parameter baseURL können Sie eine Basis-URL für die Webseite festlegen, z. B. das HTML-Tag. Jede URL auf der Webseite wird relativ von Ihrer Basis-URL geladen.

Denken Sie daran, dass jede HTML-Seite und benötigt

Tags, obwohl eine Webansicht auch ohne sie einwandfrei funktioniert.

Hier ist ein nützlicher Ausschnitt, der ein anfängliches Ansichtsfenster festlegt und die iOS-Standardschriftart „San Francisco“ verwendet:

\(html)

Wenn Sie das obige Snippet Ihrer Webansicht zuweisen, stellen Sie sicher, dass die Variable „html“ den HTML-String Ihrer Seite enthält.

Und hier ist noch etwas … Stellen Sie sich vor, Sie erstellen Ihre Rezept-App und möchten eine Webansicht unter einigen nativen Ansichten anzeigen, beispielsweise einer Bildansicht und einigen Beschriftungen. Sie fügen diese Ansichten, einschließlich der Webansicht, in einer Scroll-Ansicht hinzu, sodass der Benutzer den gesamten Ansichtenstapel von oben nach unten scrollen kann.

Sie haben nun ein Problem, denn sowohl die Scroll-Ansicht als auch die Web-Ansicht können scrollen!

Die Lösung lautet hier wie folgt:

  • Fixieren Sie die Webansicht mithilfe der Auto-Layout-Einschränkungen an der Vorder-, Hinter-, Ober- und Unterkante
  • Geben Sie der Webansicht eine dynamische Höhenbeschränkung, dh verbinden Sie die Beschränkung mit dem Ausgang, damit Sie dessen konstante Eigenschaft festlegen können
  • Ermitteln Sie die innere Inhaltsgröße der Webseite und stellen Sie die Höhe der Webansicht dynamisch so ein, dass sie mit der Höhe der Webseite übereinstimmt (mit der Einschränkung).
  • Deaktivieren Sie optional das Scrollen in der Webansicht

Infolgedessen passt sich die Größe der Webansicht an die Höhe des inneren Inhalts an. Dies passt vertikal in die Scroll-Ansicht, sodass Sie jetzt von oben nach unten scrollen können, ohne in der Webansicht selbst scrollen zu müssen.

Stellen Sie zunächst sicher, dass Sie die Einschränkungen Ihrer Webansicht eingerichtet und einen Outlet vom Typ NSLayoutConstraint für die heightConstraint der Webansicht selbst hinzugefügt haben.

Fügen Sie dann den folgenden Code zu Ihrem View-Controller hinzu:

webView.evaluateJavaScript(“document.readyState”, completionHandler: { result, error in

wenn Ergebnis == Null || Fehler != Null {
zurückkehren
}

webView.evaluateJavaScript(“document.body.offsetHeight”,CompletionHandler: { Ergebnis, Fehler in
Wenn Höhe = Ergebnis als? CGFloat {
self.heightConstraint?.constant = Höhe
}
})
})

Beispielcode, angepasst von IvanMih.

Der obige Code wertet zwei Bits von JavaScript aus. Es liest zuerst den readyState der Webseite und dann die offsetHeight des Dokumentkörpers. Dies entspricht der Höhe der Webseite, die wir anschließend verwenden, um die heightConstraint für die Webansicht festzulegen.

Der obige Code funktioniert einwandfrei mit iOS 12 und Swift 5. Leider enthalten Webseiten normalerweise viele bewegliche Teile, sodass Ihr Kilometerstand variieren kann. Wichtig ist, die Höhe der Webseite so spät wie möglich, aber nicht später, zu bewerten. Sie möchten die Inhaltshöhe erhalten, sobald die Seite vollständig geladen ist.

Damit ist unsere Erkundung von WKWebView abgeschlossen. Die Webansicht ist eine ziemlich leistungsstarke Komponente, wenn auch die Arbeit damit schwierig ist.

Wir haben uns das Laden einer einfachen Webseite in WKWebView und das Reagieren auf Navigationsereignisse angesehen. Sie haben mit zwei Methoden JavaScript in die Seite eingefügt und einfache Befehle zum Navigieren und Überprüfen der Webansicht verwendet. Und wir haben uns verschiedene Szenarien angesehen, in denen eine Webansicht nützlich sein könnte.