You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在SFSafariViewWrapper中获取用户操作SafariView时变更的URL

解决方案

你当前使用的SFSafariViewWrapper是基础封装,没有配置URL变化的监听回调,我们需要针对场景改造实现,同时注意系统SFSafariViewController的公开API没有直接提供URL变更回调,下面是两种常用实现方案:

方案1:适用于OAuth授权等需获取重定向URL的场景(官方推荐)

如果你的需求是监听用户完成特定操作后的回调URL(比如登录授权后的重定向),优先使用系统提供的ASWebAuthenticationSession,不需要自行封装SafariView,系统会自动处理回调逻辑,示例代码:

import AuthenticationServices

// 替换为你后台配置的重定向URL专属scheme
let callbackScheme = "yourapp"

struct AuthView: View {
    @State var session: ASWebAuthenticationSession?
    
    var body: some View {
        Button("打开授权页") {
            guard let authURL = URL(string: "https://你的授权页面地址") else { return }
            session = ASWebAuthenticationSession(url: authURL, callbackURLScheme: callbackScheme) { callbackURL, error in
                guard error == nil, let callbackURL = callbackURL else {
                    // 可自行添加错误处理逻辑
                    return
                }
                // 此处直接获取到变更后的回调URL
                print("拿到回调URL:\(callbackURL)")
            }
            session?.presentationContextProvider = self
            session?.start()
        }
    }
}

extension AuthView: ASWebAuthenticationPresentationContextProviding {
    func presentationAnchor(for session: ASWebAuthenticationSession) -> ASPresentationAnchor {
        ASPresentationAnchor()
    }
}

方案2:需要实时监听SafariView所有URL变化的场景

如果你确实需要监听用户在Safari弹窗内的所有页面跳转URL,可以通过KVO监听SFSafariViewController内部webView的URL属性,先改造你的SFSafariViewWrapper封装:

import SwiftUI
import SafariServices

struct SFSafariViewWrapper: UIViewControllerRepresentable {
    let url: URL
    // 定义URL变化的回调闭包
    var onURLChange: (URL) -> Void
    
    func makeUIViewController(context: Context) -> SFSafariViewController {
        let safariVC = SFSafariViewController(url: url)
        safariVC.delegate = context.coordinator
        context.coordinator.safariVC = safariVC
        return safariVC
    }
    
    func updateUIViewController(_ uiViewController: SFSafariViewController, context: Context) {}
    
    func makeCoordinator() -> Coordinator {
        Coordinator(self)
    }
    
    class Coordinator: NSObject, SFSafariViewControllerDelegate {
        let parent: SFSafariViewWrapper
        var safariVC: SFSafariViewController?
        var urlObservation: NSKeyValueObservation?
        
        init(_ parent: SFSafariViewWrapper) {
            self.parent = parent
            super.init()
            // 添加KVO监听URL变更
            urlObservation = safariVC?.observe(\.webView.url, options: [.new]) { [weak self] _, change in
                guard let newURL = change.newValue as? URL else { return }
                self?.parent.onURLChange(newURL)
            }
        }
        
        deinit {
            // 移除监听避免内存泄漏
            urlObservation?.invalidate()
        }
    }
}

改造后你的原有调用代码可修改为如下形式,即可拿到每次变更的URL:

Button(action: {self.showLogin = true}) {
    Text("OpenURL")
}
.sheet(isPresented: self.$showLogin) {
    SFSafariViewWrapper(url: URL(string: "https://google.com")!) { newURL in
        // 此处可拿到每次页面跳转后的新URL
        print("页面URL已变更:\(newURL)")
    }
}

注意:该方案用到了SFSafariViewController的私有属性webView,若后续苹果调整私有API结构可能会失效,提交App Store审核有极小概率被拒

内容的提问来源于stack exchange,提问作者Martin Poláček

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.29 17:18:02