fit-webview-bridge 0.2.0a2__tar.gz → 0.2.0a4__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of fit-webview-bridge might be problematic. Click here for more details.

@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: fit-webview-bridge
3
- Version: 0.2.0a2
3
+ Version: 0.2.0a4
4
4
  Summary: Qt native WebView bridge with PySide6 bindings
5
5
  Author: FIT Project
6
6
  License: LGPL-3.0-or-later
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "fit-webview-bridge"
3
- version = "0.2.0a2"
3
+ version = "0.2.0a4"
4
4
  description = "Qt native WebView bridge with PySide6 bindings"
5
5
  requires-python = ">=3.11,<3.14"
6
6
  dependencies = ["PySide6==6.9.0", "shiboken6==6.9.0", "shiboken6-generator==6.9.0"]
@@ -8,10 +8,13 @@
8
8
  #include <QUrl>
9
9
 
10
10
  @class WKNavDelegate;
11
+ @class FitUrlMsgHandler;
11
12
 
12
13
  struct WKWebViewWidget::Impl {
13
- WKWebView* wk = nil;
14
- WKNavDelegate* delegate = nil;
14
+ WKWebView* wk = nil;
15
+ WKNavDelegate* delegate = nil;
16
+ WKUserContentController* ucc = nil;
17
+ FitUrlMsgHandler* msg = nil;
15
18
  };
16
19
 
17
20
  @interface WKNavDelegate : NSObject <WKNavigationDelegate>
@@ -19,11 +22,34 @@ struct WKWebViewWidget::Impl {
19
22
  @end
20
23
 
21
24
  @implementation WKNavDelegate
25
+ - (void)webView:(WKWebView *)webView didStartProvisionalNavigation:(WKNavigation *)navigation {
26
+ if (!self.owner) return;
27
+ if (webView.URL)
28
+ emit self.owner->urlChanged(QUrl::fromEncoded(QByteArray(webView.URL.absoluteString.UTF8String)));
29
+ emit self.owner->loadProgress(5);
30
+ emit self.owner->canGoBackChanged(webView.canGoBack);
31
+ emit self.owner->canGoForwardChanged(webView.canGoForward);
32
+ }
33
+ - (void)webView:(WKWebView *)webView didCommitNavigation:(WKNavigation *)navigation {
34
+ if (!self.owner) return;
35
+ if (webView.URL)
36
+ emit self.owner->urlChanged(QUrl::fromEncoded(QByteArray(webView.URL.absoluteString.UTF8String)));
37
+ emit self.owner->loadProgress(50);
38
+ emit self.owner->canGoBackChanged(webView.canGoBack);
39
+ emit self.owner->canGoForwardChanged(webView.canGoForward);
40
+ }
41
+ - (void)webView:(WKWebView *)webView didReceiveServerRedirectForProvisionalNavigation:(WKNavigation *)navigation {
42
+ if (!self.owner) return;
43
+ if (webView.URL)
44
+ emit self.owner->urlChanged(QUrl::fromEncoded(QByteArray(webView.URL.absoluteString.UTF8String)));
45
+ }
22
46
  - (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation {
23
47
  if (!self.owner) return;
24
48
  emit self.owner->loadFinished(true);
25
- if (webView.URL) emit self.owner->urlChanged(QUrl::fromEncoded(QByteArray(webView.URL.absoluteString.UTF8String)));
26
- if (webView.title) emit self.owner->titleChanged(QString::fromUtf8(webView.title.UTF8String));
49
+ if (webView.URL)
50
+ emit self.owner->urlChanged(QUrl::fromEncoded(QByteArray(webView.URL.absoluteString.UTF8String)));
51
+ if (webView.title)
52
+ emit self.owner->titleChanged(QString::fromUtf8(webView.title.UTF8String));
27
53
  emit self.owner->loadProgress(100);
28
54
  emit self.owner->canGoBackChanged(webView.canGoBack);
29
55
  emit self.owner->canGoForwardChanged(webView.canGoForward);
@@ -35,20 +61,32 @@ struct WKWebViewWidget::Impl {
35
61
  emit self.owner->canGoBackChanged(webView.canGoBack);
36
62
  emit self.owner->canGoForwardChanged(webView.canGoForward);
37
63
  }
38
- - (void)webView:(WKWebView *)webView didStartProvisionalNavigation:(WKNavigation *)navigation {
39
- if (self.owner) emit self.owner->loadProgress(5);
40
- }
41
- - (void)webView:(WKWebView *)webView didCommitNavigation:(WKNavigation *)navigation {
42
- if (self.owner) emit self.owner->loadProgress(50);
64
+ @end
65
+
66
+ // Handler per messaggi JS (SPA: pushState/replaceState/popstate/click)
67
+ @interface FitUrlMsgHandler : NSObject <WKScriptMessageHandler>
68
+ @property(nonatomic, assign) WKWebViewWidget* owner;
69
+ @end
70
+
71
+ @implementation FitUrlMsgHandler
72
+ - (void)userContentController:(WKUserContentController *)userContentController
73
+ didReceiveScriptMessage:(WKScriptMessage *)message {
74
+ if (!self.owner) return;
75
+ if (![message.name isEqualToString:@"fitUrlChanged"]) return;
76
+ if (![message.body isKindOfClass:[NSString class]]) return;
77
+ QString s = QString::fromUtf8([(NSString*)message.body UTF8String]);
78
+ emit self.owner->urlChanged(QUrl::fromEncoded(s.toUtf8()));
43
79
  }
44
80
  @end
45
81
 
82
+ // Conversione QUrl -> NSURL con forzatura http->https e normalizzazione user-input
46
83
  static NSURL* toNSURL(QUrl u) {
47
84
  if (!u.isValid()) return nil;
48
85
 
49
86
  if (u.scheme().isEmpty())
50
87
  u = QUrl::fromUserInput(u.toString());
51
88
 
89
+ // Forza sempre http -> https (nessuna eccezione)
52
90
  if (u.scheme() == "http")
53
91
  u.setScheme("https");
54
92
 
@@ -59,7 +97,6 @@ static NSURL* toNSURL(QUrl u) {
59
97
  return [NSURL URLWithString:[NSString stringWithUTF8String:enc.constData()]];
60
98
  }
61
99
 
62
-
63
100
  WKWebViewWidget::WKWebViewWidget(QWidget* parent)
64
101
  : QWidget(parent), d(new Impl) {
65
102
  setAttribute(Qt::WA_NativeWindow, true);
@@ -70,6 +107,39 @@ WKWebViewWidget::WKWebViewWidget(QWidget* parent)
70
107
  if ([cfg respondsToSelector:@selector(defaultWebpagePreferences)]) {
71
108
  cfg.defaultWebpagePreferences.allowsContentJavaScript = YES;
72
109
  }
110
+
111
+ // UserContentController + script per intercettare navigazioni SPA
112
+ d->ucc = [WKUserContentController new];
113
+ d->msg = [FitUrlMsgHandler new];
114
+ d->msg.owner = this;
115
+ [d->ucc addScriptMessageHandler:d->msg name:@"fitUrlChanged"];
116
+
117
+ NSString* js =
118
+ @"(function(){"
119
+ @" function emit(){"
120
+ @" try{ window.webkit.messageHandlers.fitUrlChanged.postMessage(location.href); }catch(e){}"
121
+ @" }"
122
+ @" var _ps = history.pushState;"
123
+ @" history.pushState = function(){ _ps.apply(this, arguments); emit(); };"
124
+ @" var _rs = history.replaceState;"
125
+ @" history.replaceState = function(){ _rs.apply(this, arguments); emit(); };"
126
+ @" window.addEventListener('popstate', emit, true);"
127
+ @" document.addEventListener('click', function(ev){"
128
+ @" var a = ev.target && ev.target.closest ? ev.target.closest('a[href]') : null;"
129
+ @" if (!a) return;"
130
+ @" if (a.target === '_blank' || a.hasAttribute('download')) return;"
131
+ @" setTimeout(emit, 0);" // lascia tempo alla SPA di aggiornare l’URL
132
+ @" }, true);"
133
+ @"})();";
134
+
135
+ WKUserScript* us = [[WKUserScript alloc]
136
+ initWithSource:js
137
+ injectionTime:WKUserScriptInjectionTimeAtDocumentStart
138
+ forMainFrameOnly:YES];
139
+
140
+ [d->ucc addUserScript:us];
141
+ cfg.userContentController = d->ucc;
142
+
73
143
  d->wk = [[WKWebView alloc] initWithFrame:nsParent.bounds configuration:cfg];
74
144
  d->wk.autoresizingMask = NSViewWidthSizable | NSViewHeightSizable;
75
145
  [nsParent addSubview:d->wk];
@@ -81,8 +151,15 @@ WKWebViewWidget::WKWebViewWidget(QWidget* parent)
81
151
 
82
152
  WKWebViewWidget::~WKWebViewWidget() {
83
153
  if (!d) return;
154
+ if (d->ucc && d->msg) {
155
+ @try { [d->ucc removeScriptMessageHandlerForName:@"fitUrlChanged"]; } @catch (...) {}
156
+ }
157
+ d->msg = nil;
158
+
84
159
  if (d->wk) { [d->wk removeFromSuperview]; d->wk = nil; }
85
160
  d->delegate = nil;
161
+ d->ucc = nil;
162
+
86
163
  delete d; d = nullptr;
87
164
  }
88
165