SwiftUI中WKWebView点击登录链接重定向功能失效问题
iOS SwiftUI WKWebView 点击Sign In链接重定向实现方案
需求说明
- 开发面向iOS平台的内嵌WebView应用
- 实现效果:用户点击页面内的sign in链接时自动触发重定向,后续可将生成的用户token拼接在重定向链接后
- 测试阶段重定向目标地址:
https://nu.nl - 现有代码无法触发重定向,需要修正
原有代码
ContentView.swift
import SwiftUI import Foundation import WebKit struct ContentView: View { var body: some View { WebView(url: URL(string:"https://ferocity.bytemountains.com/client")!) .frame(maxWidth: .infinity, maxHeight: .infinity) .edgesIgnoringSafeArea(.all) } } struct ContentView_Previews: PreviewProvider { static var previews: some View { ContentView() } }
WebView.swift(原有错误实现)
import Foundation import SwiftUI import WebKit struct WebView: UIViewRepresentable { let url: URL let webView = WKWebView() func makeUIView(context: Context) -> some UIView { let request = URLRequest(url: url) webView.load(request) return webView } func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Swift.Void) { if(navigationAction.navigationType == .other) { if navigationAction.request.url != nil { //do what you need with url webView.load(URLRequest(url: URL(string: "https://nu.nl/")!)) } decisionHandler(.cancel) return } decisionHandler(.allow) } func updateUIView(_ uiView: UIViewType, context: Context) { } }
问题根因
- 未给WKWebView设置
navigationDelegate,实现的decidePolicyFor代理方法根本不会被系统调用 - 代理方法直接写在UIViewRepresentable结构体中,没有通过SwiftUI要求的Coordinator协调器绑定代理,方法不属于WKWebView的代理回调
- 导航拦截逻辑错误:判断
navigationType == .other会拦截首次页面加载请求,导致初始页面都无法正常渲染,也没有针对性判断是否为sign in链接,会无差别拦截所有非点击触发的导航行为
修复后代码
直接替换原有WebView.swift的内容即可,代码里已经预留了token拼接的位置,后续直接替换对应逻辑就能用:
import Foundation import SwiftUI import WebKit struct WebView: UIViewRepresentable { let url: URL // 可配置重定向目标地址,后续拼接token直接修改这个url即可 private let redirectTarget = URL(string: "https://nu.nl/")! func makeCoordinator() -> Coordinator { Coordinator(self) } func makeUIView(context: Context) -> WKWebView { let webView = WKWebView() // 绑定导航代理 webView.navigationDelegate = context.coordinator webView.load(URLRequest(url: url)) return webView } func updateUIView(_ uiView: WKWebView, context: Context) {} // 协调器实现WKNavigationDelegate代理 class Coordinator: NSObject, WKNavigationDelegate { let parent: WebView init(_ parent: WebView) { self.parent = parent } func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) { // 只拦截用户主动点击链接触发的导航 guard navigationAction.navigationType == .linkActivated, let requestUrl = navigationAction.request.url else { decisionHandler(.allow) return } // 判断是否为sign in链接,可根据实际页面的链接路径/特征修改判断条件 if requestUrl.absoluteString.contains("signin") || requestUrl.absoluteString.contains("sign-in") { // 后续拼接token可在此处修改redirectUrl,比如: // var components = URLComponents(url: parent.redirectTarget, resolvingAgainstBaseURL: false)! // components.queryItems = [URLQueryItem(name: "token", value: "你的用户token值")] // let redirectUrl = components.url! webView.load(URLRequest(url: parent.redirectTarget)) decisionHandler(.cancel) return } decisionHandler(.allow) } } }
注意事项
- sign in链接的判断条件需要根据你实际页面的链接格式调整,比如如果sign in链接的固定路径是
/login,就把判断条件改成匹配对应路径即可 - 拼接token时优先用
URLComponents处理,避免url格式错误 - 如果需要处理http域名的加载,记得在Info.plist里添加App Transport Security的相关配置,否则非https链接会被系统拦截
内容的提问来源于stack exchange,提问作者Jens
相关产品推荐
相关产品推荐

