fit-webview-bridge 0.2.4a1__tar.gz → 0.2.6a1__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.4a1
3
+ Version: 0.2.6a1
4
4
  Summary: Qt native WebView bridge with PySide6 bindings
5
5
  Author: FIT Project
6
6
  License: LGPL-3.0-or-later
@@ -63,6 +63,31 @@ class Main(QMainWindow):
63
63
  # segnali base
64
64
  self.view.titleChanged.connect(self.setWindowTitle)
65
65
  self.view.loadProgress.connect(lambda p: print("progress:", p))
66
+ self.view.setUserAgent(
67
+ "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.4 Safari/605.1.15"
68
+ )
69
+
70
+ def on_load_finished():
71
+ print("on_load_finished")
72
+ tok = self.view.evaluateJavaScriptWithResult(
73
+ "(() => ({ y: window.scrollY,"
74
+ " h: Math.max(document.body.scrollHeight, document.documentElement.scrollHeight),"
75
+ " vh: window.innerHeight }))()"
76
+ )
77
+
78
+ def on_js(result, token, error):
79
+ print(f"result: {result}")
80
+ if token != tok:
81
+ return
82
+ if error:
83
+ print("JS error:", error)
84
+ return
85
+ # result è dict serializzato in JSON (se hai scelto la serializzazione)
86
+ # oppure primitive QVariant: gestiscilo e continua il flow di screenshot
87
+
88
+ self.view.javaScriptResult.connect(on_js)
89
+
90
+ self.view.loadFinished.connect(on_load_finished)
66
91
 
67
92
  # abilita/disabilita i bottoni in base alla navigazione
68
93
  self.btnBack.setEnabled(False)
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "fit-webview-bridge"
3
- version = "0.2.4a1"
3
+ version = "0.2.6a1"
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"]
@@ -23,11 +23,19 @@ public:
23
23
  Q_INVOKABLE void stop();
24
24
  Q_INVOKABLE void reload();
25
25
  Q_INVOKABLE void evaluateJavaScript(const QString& script);
26
+ Q_INVOKABLE quint64 evaluateJavaScriptWithResult(const QString& script);
27
+
26
28
 
27
29
  Q_INVOKABLE void setDownloadDirectory(const QString& dirPath);
28
30
  Q_INVOKABLE QString downloadDirectory() const;
29
31
  void renderErrorPage(const QUrl& url, const QString& reason, int httpStatus);
30
32
 
33
+ // ==== USER AGENT ====
34
+ Q_INVOKABLE void setUserAgent(const QString& ua); // UA completo
35
+ Q_INVOKABLE QString userAgent() const; // restituisce l’override (se presente)
36
+ Q_INVOKABLE void resetUserAgent(); // rimuove l’override
37
+ Q_INVOKABLE void setApplicationNameForUserAgent(const QString& appName); // opzionale
38
+
31
39
  signals:
32
40
  void loadFinished(bool ok);
33
41
  void urlChanged(const QUrl& url);
@@ -43,10 +51,16 @@ signals:
43
51
  void downloadFinished(DownloadInfo* info);
44
52
  void downloadFailed(const QString& filePath, const QString& error);
45
53
 
54
+ void javaScriptResult(const QVariant& result, quint64 token, const QString& error);
55
+
56
+
46
57
  protected:
47
58
  void showEvent(QShowEvent*) override;
48
59
  void resizeEvent(QResizeEvent*) override;
49
60
 
50
61
  private:
51
62
  struct Impl; Impl* d = nullptr;
63
+
64
+ // --- NEW: helper che applica UA
65
+ void applyUserAgent();
52
66
  };
@@ -5,6 +5,11 @@
5
5
  #include "WKWebViewWidget.h"
6
6
  #include "DownloadInfo.h"
7
7
 
8
+ #include <atomic>
9
+
10
+ #include <QPointer>
11
+ static std::atomic<quint64> s_jsToken{0};
12
+
8
13
 
9
14
  static inline void fit_emit_downloadStarted(WKWebViewWidget* owner,
10
15
  const QString& name,
@@ -53,6 +58,10 @@ struct WKWebViewWidget::Impl {
53
58
  WKUserContentController* ucc = nil;
54
59
  FitUrlMsgHandler* msg = nil;
55
60
  QString downloadDir; // es. ~/Downloads
61
+
62
+ // --- UA ---
63
+ QString customUA; // override UA (se non vuoto)
64
+ QString appUA; // suffix via configuration (opzionale)
56
65
  };
57
66
 
58
67
  // =======================
@@ -854,6 +863,8 @@ WKWebViewWidget::WKWebViewWidget(QWidget* parent)
854
863
  d->delegate.webView = d->wk;
855
864
  [d->wk setNavigationDelegate:d->delegate];
856
865
  [d->wk setUIDelegate:d->delegate];
866
+
867
+ applyUserAgent();
857
868
  }
858
869
 
859
870
  WKWebViewWidget::~WKWebViewWidget() {
@@ -904,6 +915,45 @@ void WKWebViewWidget::evaluateJavaScript(const QString& script) {
904
915
  }];
905
916
  }
906
917
 
918
+ quint64 WKWebViewWidget::evaluateJavaScriptWithResult(const QString& script) {
919
+ if (!d || !d->wk) return 0;
920
+ const quint64 token = ++s_jsToken;
921
+
922
+ NSString* s = [NSString stringWithUTF8String:script.toUtf8().constData()];
923
+
924
+ // ✅ usa QPointer invece di __weak
925
+ QPointer<WKWebViewWidget> guard(this);
926
+
927
+ [d->wk evaluateJavaScript:s completionHandler:^(id result, NSError* error) {
928
+ WKWebViewWidget* self = guard.data();
929
+ if (!self) return; // l'oggetto Qt è stato distrutto: esci in sicurezza
930
+
931
+ QVariant out;
932
+ if ([result isKindOfClass:NSString.class]) {
933
+ out = QString::fromUtf8([(NSString*)result UTF8String]);
934
+ } else if ([result isKindOfClass:NSNumber.class]) {
935
+ out = QVariant::fromValue([(NSNumber*)result doubleValue]);
936
+ } else if (!result || result == (id)kCFNull) {
937
+ out = QVariant();
938
+ } else {
939
+ NSData* data = [NSJSONSerialization dataWithJSONObject:result options:0 error:nil];
940
+ if (data) out = QString::fromUtf8((const char*)data.bytes, (int)data.length);
941
+ }
942
+
943
+ const QString err = error
944
+ ? QString::fromUtf8(error.localizedDescription.UTF8String)
945
+ : QString();
946
+
947
+ // rimanda sul main loop Qt; se 'self' muore prima della consegna,
948
+ // Qt scarta la chiamata perché il receiver non esiste più
949
+ QMetaObject::invokeMethod(self, [self, out, token, err]{
950
+ emit self->javaScriptResult(out, token, err);
951
+ }, Qt::QueuedConnection);
952
+ }];
953
+
954
+ return token;
955
+ }
956
+
907
957
  // =======================
908
958
  // Download directory API
909
959
  // =======================
@@ -1001,4 +1051,59 @@ void WKWebViewWidget::renderErrorPage(const QUrl& url,
1001
1051
  // Carica l'HTML direttamente nella webview
1002
1052
  [d->wk loadHTMLString:[NSString stringWithUTF8String:html.toUtf8().constData()]
1003
1053
  baseURL:[NSURL URLWithString:@"about:blank"]];
1004
- }
1054
+ }
1055
+
1056
+ // --- NEW: metodo privato
1057
+ void WKWebViewWidget::applyUserAgent() {
1058
+ if (!(d && d->wk)) return;
1059
+ @autoreleasepool {
1060
+ // Suffix via configuration.applicationNameForUserAgent
1061
+ if (d->appUA.isEmpty()) {
1062
+ @try { [d->wk.configuration setValue:nil forKey:@"applicationNameForUserAgent"]; } @catch(...) {}
1063
+ } else {
1064
+ NSString* s = [NSString stringWithUTF8String:d->appUA.toUtf8().constData()];
1065
+ @try {
1066
+ if ([d->wk.configuration respondsToSelector:@selector(setApplicationNameForUserAgent:)]) {
1067
+ d->wk.configuration.applicationNameForUserAgent = s;
1068
+ } else {
1069
+ [d->wk.configuration setValue:s forKey:@"applicationNameForUserAgent"];
1070
+ }
1071
+ } @catch(...) {}
1072
+ }
1073
+
1074
+ // Override totale via customUserAgent
1075
+ if (d->customUA.isEmpty()) {
1076
+ @try { d->wk.customUserAgent = nil; } @catch(...) {
1077
+ @try { [d->wk setValue:nil forKey:@"customUserAgent"]; } @catch(...) {}
1078
+ }
1079
+ } else {
1080
+ NSString* ua = [NSString stringWithUTF8String:d->customUA.toUtf8().constData()];
1081
+ @try { d->wk.customUserAgent = ua; } @catch(...) {
1082
+ @try { [d->wk setValue:ua forKey:@"customUserAgent"]; } @catch(...) {}
1083
+ }
1084
+ }
1085
+ }
1086
+ }
1087
+
1088
+ // --- API pubblica UA
1089
+ void WKWebViewWidget::setUserAgent(const QString& ua) {
1090
+ if (!d) return;
1091
+ d->customUA = ua.trimmed();
1092
+ applyUserAgent();
1093
+ }
1094
+
1095
+ QString WKWebViewWidget::userAgent() const {
1096
+ return d ? d->customUA : QString();
1097
+ }
1098
+
1099
+ void WKWebViewWidget::resetUserAgent() {
1100
+ if (!d) return;
1101
+ d->customUA.clear();
1102
+ applyUserAgent();
1103
+ }
1104
+
1105
+ void WKWebViewWidget::setApplicationNameForUserAgent(const QString& appName) {
1106
+ if (!d) return;
1107
+ d->appUA = appName.trimmed();
1108
+ applyUserAgent();
1109
+ }