SwiftUI打开网页
所属分类:ios | 发布于 2023-06-05 23:47:17
在做iOS开发中,打开网页是个常见的需求,比如,要打开的用户协议和隐私政策等页面是h5页面。
打开浏览器主要有两种场景:
1、通过外部浏览器打开网页
2、在App内部打开网页
本篇我们就基于Swift和SwiftUI,分别实现这两种场景。
通过外部浏览器打开网页
目前看到的是有两种方法来打开外部浏览器
方法一:使用Link
struct ContentView: View {
var body: some View {
Link("Baidu", destination: URL(string: "https://baidu.com")!)
}
}
方法二:使用环境变量openUrl
struct OpenBrowserWithOpenURL: View {
@Environment(\.openURL) var openURL
var body: some View {
Button("Open Baidu") {
openURL(URL(string: "https://baidu.com")!)
}
}
}
在App内部打开网页
在SwiftUI中,没有打开网页的接口,要实现打开网页的功能,需要借助WebKit组件桥接WKWebView。
1、桥接WKWebView初步使用
这里分为两步
1.1、创建WebView结构体
创建WebView结构体,实现UIViewRepresentable协议,用来桥接WKWebView
import SwiftUI
// 1
import WebKit
struct WebView: UIViewRepresentable {
// 2
let url: URL
// 3
func makeUIView(context: Context) -> WKWebView {
return WKWebView()
}
// 4
func updateUIView(_ webView: WKWebView, context: Context) {
let request = URLRequest(url: url)
webView.load(request)
}
}
1.2、使用WebView打开网页
在创建实现了UIViewRepresentable协议的WebView结构体后,就可以向使用其它View组件一样使用它。
struct ContentView: View {
// 1
@State private var isPresentWebView = false
var body: some View {
Button("Open WebView") {
// 2
isPresentWebView = true
}
.sheet(isPresented: $isPresentWebView) {
NavigationStack {
// 3
WebView(url: URL(string: "https://baidu.com")!)
.ignoresSafeArea()
.navigationTitle("Baidu In App")
.navigationBarTitleDisplayMode(.inline)
}
}
}
}
1.3、存在的问题
上面的代码是可以打开网页了,但是一个问题:无法关闭sheet。
-
This method should not be called on the main thread as it may lead to UI unresponsiveness.
- 无法关闭sheet
在App内打开网页进阶版
在上面我已经实现了最基础了桥接WebKit下的WKWebView来打开网页,但实际使用的时候,我们还需要一些精细化的控制,大白话就是app与打开的网页的交互。
- 通过@Binding属性,可以将值从SwiftUI传递到UIView控件
- 反过来,SwiftUI想要获取UIView控件的数据,那就需要使用Coordinator
关于UIViewRepresentable和Coordinator的介绍和使用,可以看这篇文章:SwiftUI中使用"UIViewRepresentable"桥接UIKit View
进阶版会引入WebViewModel类,这是一个ObservableObject类,进阶版的使用也分为三步:
1、创建WebViewModel类
import Foundation
import WebKit
class WebViewModel: ObservableObject {
@Published var isLoading: Bool = false
@Published var canGoBack: Bool = false
@Published var shouldGoBack: Bool = false
@Published var title: String = ""
var urlString = ""
func setUrlString(urlString: String) {
self.urlString = urlString
}
}
2、创建WebView结构体
import SwiftUI
import WebKit
struct WebView: UIViewRepresentable {
@ObservedObject var model: WebViewModel
func makeUIView(context: Context) -> WKWebView {
guard let url = URL(string: self.model.urlString) else {
return WKWebView()
}
let request = URLRequest(url: url)
let webView = WKWebView()
webView.navigationDelegate = context.coordinator
webView.load(request)
return webView
}
func updateUIView(_ webView: WKWebView, context: Context) {
if model.shouldGoBack {
webView.goBack()
model.setShouldGoBackToFalse()
}
}
func makeCoordinator() -> Coordinator {
Coordinator(self, model)
}
}
extension WebView {
class Coordinator: NSObject, WKNavigationDelegate {
@ObservedObject private var model: WebViewModel
private let parent: WebView
init(_ parent: WebView, _ model: WebViewModel) {
self.parent = parent
self.model = model
}
func webView(_ webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!) {
model.isLoading = true
}
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
model.isLoading = false
model.title = webView.title ?? ""
model.canGoBack = webView.canGoBack
}
func webView(_ webView: WKWebView, didFail navigation: WKNavigation!, withError error: Error) {
model.isLoading = false
}
}
}