@@ -11,16 +11,91 @@ struct UpdaterView: View {
1111struct UpdaterWebView : UIViewRepresentable {
1212 let url : URL
1313
14+ func makeCoordinator( ) -> Coordinator {
15+ Coordinator ( parent: self )
16+ }
17+
1418 func makeUIView( context: Context ) -> WKWebView {
15- let webView = WKWebView ( )
16- let request = URLRequest ( url: url)
17- webView. load ( request)
19+ // Configure the web view
20+ let config = WKWebViewConfiguration ( )
21+ config. allowsInlineMediaPlayback = true
22+ config. preferences. javaScriptEnabled = true
23+
24+ let webView = WKWebView ( frame: . zero, configuration: config)
25+ webView. navigationDelegate = context. coordinator
26+ webView. uiDelegate = context. coordinator
27+ webView. allowsBackForwardNavigationGestures = true
28+
29+ // Load request
30+ webView. load ( URLRequest ( url: url) )
1831 return webView
1932 }
2033
2134 func updateUIView( _ uiView: WKWebView , context: Context ) {
22- // Reload if needed
23- let request = URLRequest ( url: url)
24- uiView. load ( request)
35+ // Only reload if the URL changed; avoids flicker
36+ if uiView. url != url {
37+ uiView. load ( URLRequest ( url: url) )
38+ }
39+ }
40+
41+ // MARK: - Coordinator
42+ class Coordinator : NSObject , WKNavigationDelegate , WKUIDelegate {
43+ let parent : UpdaterWebView
44+
45+ init ( parent: UpdaterWebView ) {
46+ self . parent = parent
47+ }
48+
49+ // Intercept navigation actions
50+ func webView( _ webView: WKWebView , decidePolicyFor navigationAction: WKNavigationAction ,
51+ decisionHandler: @escaping ( WKNavigationActionPolicy ) -> Void ) {
52+
53+ guard let reqURL = navigationAction. request. url else {
54+ decisionHandler ( . allow)
55+ return
56+ }
57+
58+ let scheme = reqURL. scheme? . lowercased ( ) ?? " "
59+
60+ // 1) Handle itms-services (install manifest) by opening in system
61+ if scheme == " itms-services " {
62+ if UIApplication . shared. canOpenURL ( reqURL) {
63+ UIApplication . shared. open ( reqURL, options: [ : ] , completionHandler: nil )
64+ }
65+ decisionHandler ( . cancel)
66+ return
67+ }
68+
69+ // 2) If the link tries to open in a new window (target="_blank"), open externally
70+ // (navigationAction.targetFrame is nil for new-window links)
71+ if navigationAction. navigationType == . linkActivated, navigationAction. targetFrame == nil {
72+ // choose: open in Safari (external), or load in same webview:
73+ UIApplication . shared. open ( reqURL, options: [ : ] , completionHandler: nil )
74+ decisionHandler ( . cancel)
75+ return
76+ }
77+
78+ // 3) Allow normal navigation
79+ decisionHandler ( . allow)
80+ }
81+
82+ // Optional: handle window.open() from JS (so target=_blank still works)
83+ func webView( _ webView: WKWebView , createWebViewWith configuration: WKWebViewConfiguration ,
84+ for navigationAction: WKNavigationAction , windowFeatures: WKWindowFeatures ) -> WKWebView ? {
85+ // If the action has a URL, open externally (Safari)
86+ if let url = navigationAction. request. url {
87+ UIApplication . shared. open ( url, options: [ : ] , completionHandler: nil )
88+ }
89+ return nil
90+ }
91+
92+ // Optional: handle JS alert/confirm/prompt if needed
93+ func webView( _ webView: WKWebView , runJavaScriptAlertPanelWithMessage message: String ,
94+ initiatedByFrame frame: WKFrameInfo , completionHandler: @escaping ( ) -> Void ) {
95+ // simple native alert fallback
96+ let alert = UIAlertController ( title: nil , message: message, preferredStyle: . alert)
97+ alert. addAction ( UIAlertAction ( title: " OK " , style: . default) { _ in completionHandler ( ) } )
98+ UIApplication . shared. windows. first? . rootViewController? . present ( alert, animated: true , completion: nil )
99+ }
25100 }
26- }
101+ }
0 commit comments