Created
April 20, 2025 07:48
-
-
Save CH3COOH/d038de1989906622a98e285d4e1231cf to your computer and use it in GitHub Desktop.
SwiftUIの `@Environment(\.openURL)` を使って URLをアプリ内ブラウザで開く
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// ContentView.swift | |
// SampleOpenUrl | |
// | |
// Created by KENJIWADA on 2025/04/20. | |
// | |
import SwiftUI | |
struct ContentView: View { | |
@Environment(\.openURL) private var openURL | |
private static let url = URL(string: "https://dev.classmethod.jp/author/wada-kenji/")! | |
var body: some View { | |
VStack(spacing: 24) { | |
Button(action: openSampleURL) { | |
VStack { | |
Text("Open Action") | |
} | |
} | |
Link("Open Link", destination: ContentView.url) | |
} | |
} | |
private func openSampleURL() { | |
openURL(ContentView.url) | |
} | |
} | |
#Preview { | |
ContentView() | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// SafariSheetModifier.swift | |
// SampleOpenUrl | |
// | |
// Created by KENJIWADA on 2025/04/20. | |
// | |
import SafariServices | |
import SwiftUI | |
/// URL をシート表示用に Identifiable に適合させるためのラッパー構造体 | |
/// - Note: sheet(item:) で使用するために必要 | |
struct IdentifiableURL: Identifiable { | |
let id = UUID() | |
let url: URL | |
init(_ url: URL) { | |
self.url = url | |
} | |
} | |
private struct SafariView: UIViewControllerRepresentable { | |
let url: URL | |
func makeUIViewController(context _: Context) -> SFSafariViewController { | |
let vc = SFSafariViewController(url: url) | |
vc.dismissButtonStyle = .close | |
vc.preferredControlTintColor = .systemPink | |
return vc | |
} | |
func updateUIViewController(_: SFSafariViewController, context _: Context) { | |
// SFSafariViewControllerは内部状態を管理するため、更新は不要 | |
} | |
} | |
struct SafariSheetModifier: ViewModifier { | |
@State private var identifiableURL: IdentifiableURL? | |
func body(content: Content) -> some View { | |
content | |
.environment(\.openURL, OpenURLAction { url in | |
// HTTP/HTTPS スキーム以外は標準の動作(ブラウザで開く等)にフォールバック | |
if url.scheme == "https" || url.scheme == "http" { | |
identifiableURL = IdentifiableURL(url) | |
return .handled | |
} else { | |
return .systemAction | |
} | |
}) | |
.sheet(item: $identifiableURL) { identifiableURL in | |
SafariView(url: identifiableURL.url) | |
} | |
} | |
} | |
extension View { | |
/// View に Safari シート表示機能を追加する | |
/// アプリ内で開かれる URL を SFSafariViewController で表示するようにする | |
func safariSheet() -> some View { | |
modifier(SafariSheetModifier()) | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// SampleOpenUrlApp.swift | |
// SampleOpenUrl | |
// | |
// Created by KENJIWADA on 2025/04/20. | |
// | |
import SwiftUI | |
@main | |
struct SampleOpenUrlApp: App { | |
var body: some Scene { | |
WindowGroup { | |
ContentView() | |
.safariSheet() // アプリ全体に Safari シート機能を適用 | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment