在 SwiftUI 中使用SFSafariViewController:在 APP 中打开网页

SFSafariViewController 可用于让用户在应用程序内而不是在外部浏览器中打开网页。虽然视图控制器非常适合 UIKit,但在 SwiftUI 应用程序中直接使用它还是有一定的挑战性的。

每当遇到仅 UIKit 解决方案可用的情况时,你可能想知道如何编写包装器并使 UIKit 类可用于 SwiftUI 视图。理想情况下,它是可重复使用的,以便你以后可以重复使用它。下面让我们来深入了解一下!

创建 SFSafariViewController 的 SwiftUI 包装器

我们通过实现 SFSafariViewControllerUIViewControllerRepresentable 协议来开始。该协议允许我们创建一个包装 UIKit 视图控制器的 SwiftUI 视图:

swift 复制代码
struct SFSafariView: UIViewControllerRepresentable {
    let url: URL

    func makeUIViewController(context: UIViewControllerRepresentableContext<Self>) -> SFSafariViewController {
        return SFSafariViewController(url: url)
    }

    func updateUIViewController(_ uiViewController: SFSafariViewController, context: UIViewControllerRepresentableContext<SFSafariView>) { }
}

通过上面的代码我们可以看到, 我们需要实现 UIViewControllerRepresentable 的两个函数:

  • makeUIViewController(context:) :调用该函数来创建 UIViewController 的实例。
  • updateUIViewController(_:context:) :将调用该函数以便使用来自 SwiftUI 的最新信息,用其更新 UIViewController 的状态。

在我们的例子中,我们只需使用给定的 URL 实例化 SFSafariViewController 即可。所以 updateUIViewController(_:context:) 函数体内并没有编写代码。

创建可重用的视图修改器

我比较倾向于从一开始就编写可重用的代码,这样可以方便我的代码被重用。我甚至有一个专用的扩展包,我可以轻松地在不同的应用程序中重复使用它,这样当我遇到以前遇到的问题时,我就可以更快地编写应用程序。

在我们的例子中,还需要一个视图修饰符来捕获通常在外部浏览器中打开的任何链接。这些链接可以在 SwiftUI 中用下面的代码生成:

css 复制代码
struct SwiftUILinksView: View {
    var body: some View {
        VStack(spacing: 20) {
            // 普通链接
            Link("SwiftUI Link Example", destination: URL(string: "https://www.xxx.com")!)
            // Markdown 中的链接
            Text("Markdown link example: [xxx](https://www.xxx.com)")
        }
    }
}

解决方案的关键就是在环境视图修饰符中使用 openURL 环境属性。视图修饰符的代码如下所示:

swift 复制代码
private struct SafariViewControllerViewModifier: ViewModifier {
    @State private var urlToOpen: URL?

    func body(content: Content) -> some View {
        content
            .environment(\.openURL, OpenURLAction { url in
                // 捕获任何即将在外部浏览器中打开的 URL。将其用我们的 SFSafariView 打开
                urlToOpen = url
                return .handled
            })
            .sheet(isPresented: $urlToOpen.mappedToBool(), onDismiss: {
                urlToOpen = nil
            }, content: {
                SFSafariView(url: urlToOpen!)
            })
    }
}

我们使用视图修饰符来捕获任何传出 URL 并将它们用作 sheet 的输入。该 sheet 将使用我们之前创建的 SFSafariView,通过 SFSafariViewController 在应用程序内呈现 URL。

需要注意的是,我们正在使用 Binding 一个扩展,该扩展允许将任何可选绑定映射到布尔绑定:

swift 复制代码
extension Binding where Value == Bool {
    init(binding: Binding<(some Any)?>) {
        self.init(
            get: {
                binding.wrappedValue != nil
            },
            set: { newValue in
                guard newValue == false else { return }
                binding.wrappedValue = nil
            }
        )
    }
}

extension Binding {
    func mappedToBool<Wrapped>() -> Binding<Bool> where Value == Wrapped? {
        Binding<Bool>(binding: self)
    }
}

这是我在编写 SwiftUI 解决方案时经常重复使用的最喜欢的扩展之一。

最后缺少的部分是一个好用的视图扩展,这可以更轻松地访问我们的逻辑:

scss 复制代码
extension View {}
    func handleOpenURLInApp() -> some View {
        modifier(SafariViewControllerViewModifier())
    }
}

在 SwiftUI 中展示 SFSafariViewController

现在我们已经有了所有的逻辑,我们可以开始在 SwiftUI 的 SFSafariViewController 中呈现任何传入的 URL。我们可以通过在 VStack 上使用视图的扩展方法来做到这一点:

css 复制代码
struct SwiftUILinksView: View {
    var body: some View {
        VStack(spacing: 20) {
            Link("SwiftUI Link Example", destination: URL(string: "https://www.xxx.com")!)

            Text("Markdown link example: [RocketSim](https://www.xxx.com)")
        }
            .handleOpenURLInApp()
    }
}
相关推荐
比格丽巴格丽抱11 小时前
flutter项目苹果编译运行打包上线
flutter·ios
网络安全-老纪12 小时前
iOS应用网络安全之HTTPS
web安全·ios·https
1024小神15 小时前
tauri2.0版本开发苹果ios和安卓android应用,环境搭建和最后编译为apk
android·ios·tauri
lzhdim16 小时前
iPhone 17 Air看点汇总:薄至6mm 刷新苹果轻薄纪录
ios·iphone
安和昂16 小时前
【iOS】知乎日报第四周总结
ios
麦田里的守望者江18 小时前
KMP 中的 expect 和 actual 声明
android·ios·kotlin
_黎明20 小时前
【Swift】字符串和字符
开发语言·ios·swift
ZVAyIVqt0UFji1 天前
iOS屏幕共享技术实践
macos·ios·objective-c·cocoa
hfxns_1 天前
iOS 18.2 Beta 4开发者预览版发布,相机新增辅助功能
ios
AirDroid_cn1 天前
如何控制自己玩手机的时间?两台苹果手机帮助自律
ios·智能手机·ipad·手机使用技巧·苹果手机使用技巧