SwiftUI 暂时没有相应的WebView组件,只能用UIKit来实现WebView功能。
要实现加载进度条,目前有两种方法:
- UIViewRepresentable 包装, 加载正常,返回再次进来崩溃
struct CoscoWebView: UIViewRepresentable {
typealias UIViewType = WKWebView
let urlString: String?
@State var webView = WKWebView()
@Binding var progress: Float
func makeUIView(context: Context) -> WKWebView {
context.coordinator.addProgressObserver()
let config = WKWebViewConfiguration()
// 不做此配置设置, 大多数网页是可以正常打开的
// 但对于百度官网,会出现手机可以打开而ipad白屏(不断的在代理方法didStart 和 didFinish之间循环)
config.defaultWebpagePreferences.preferredContentMode = .mobile
let wk = WKWebView(frame: UIScreen.main.bounds, configuration: config)
wk.navigationDelegate = context.coordinator
webView = wk
return webView
}
func updateUIView(_ uiView: WKWebView, context: Context) {
if let safeString = urlString {
// 路径中出现某些特殊字符(如 = 等...),会返回nil,此处需要编码
if let url = URL(string: safeString.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) ?? "") {
let request = URLRequest(url: url)
uiView.load(request)
}
}
}
func makeCoordinator() -> Coordinator {
Coordinator(self)
}
}
extension CoscoWebView {
class Coordinator: NSObject, WKNavigationDelegate {
var parent: CoscoWebView
init(_ parent: CoscoWebView) {
self.parent = parent
}
func addProgressObserver() {
parent.webView.addObserver(self, forKeyPath: #keyPath(WKWebView.estimatedProgress), options: .new, context: nil)
}
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
if let o = object as? WKWebView, o == parent.webView {
if keyPath == #keyPath(WKWebView.estimatedProgress) {
self.parent.progress = Float(parent.webView.estimatedProgress)
}
}
}
func webView(_ webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!) {
print("开始加载")
}
func webView(_ webView: WKWebView, didFail navigation: WKNavigation!, withError error: Error) {
print(error)
}
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
print("web 加载完成")
}
}
}
- 用ViewController 添加WKWebView,再用UIViewControllerRepresentable包装
class WebController: UIViewController, WKNavigationDelegate {
var path: String?
var webView = WKWebView()
var line = UIView() // 进度条线
override func viewDidLoad() {
super.viewDidLoad()
let config = WKWebViewConfiguration()
config.defaultWebpagePreferences.preferredContentMode = .mobile
webView = WKWebView(frame: UIScreen.main.bounds, configuration: config)
webView.navigationDelegate = self
self.view.addSubview(webView)
// 监听加载进度
self.webView.addObserver(self, forKeyPath: #keyPath(WKWebView.estimatedProgress), options: .new, context: nil)
// 进度条
line = UIView(frame: CGRect(x: 0, y: 0, width: 110, height: 10))
line.backgroundColor = UIColor.blue
self.view.addSubview(line)
}
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
if let web = object as? WKWebView, web == self.webView {
line.frame.size.width = (web.estimatedProgress) * web.frame.size.width
}
}
func webView(_ webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!) {
print("开始加载web")
}
func webView(_ webView: WKWebView, didFail navigation: WKNavigation!, withError error: Error) {
print("加载失败-:", error.localizedDescription.description)
self.line.removeFromSuperview()
}
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
print("加载成功~")
self.line.removeFromSuperview()
}
}
struct XWWebView: UIViewControllerRepresentable {
typealias UIViewControllerType = WebController
var path: String?
func makeUIViewController(context: Context) -> WebController {
let c = WebController()
c.path = path
return WebController()
}
func updateUIViewController(_ uiViewController: WebController, context: Context) {
guard let url = path else { return }
let request = URLRequest(url: URL(string: url)!)
uiViewController.webView.load(request)
}
}