From 2232bc009d856c6d3f35f6c51370e1ef8e20eb67 Mon Sep 17 00:00:00 2001 From: Origuchi Date: Thu, 16 Apr 2026 18:05:25 +0800 Subject: [PATCH] use linux_webview_window to support linux geetest (#1889) * use webview_all to support linux geetest * use desktop_webview_window to support linux geetest * remove previous change in my_application.cc * update --------- Co-authored-by: dom --- lib/pages/login/controller.dart | 5 +- .../login/geetest/geetest_webview_dialog.dart | 146 +++++++++++++++++- lib/pages/login/view.dart | 14 +- lib/utils/request_utils.dart | 4 - linux/runner/my_application.cc | 6 +- pubspec.lock | 9 ++ pubspec.yaml | 4 + 7 files changed, 163 insertions(+), 25 deletions(-) diff --git a/lib/pages/login/controller.dart b/lib/pages/login/controller.dart index a33be8703..d9bf12348 100644 --- a/lib/pages/login/controller.dart +++ b/lib/pages/login/controller.dart @@ -313,9 +313,6 @@ class LoginPageController extends GetxController } if (data['status'] == 2) { SmartDialog.showToast(data['message']); - if (Platform.isLinux) { - return; - } // return; //{"code":0,"message":"0","ttl":1,"data":{"status":2,"message":"本次登录环境存在风险, 需使用手机号进行验证或绑定","url":"https://passport.bilibili.com/h5-app/passport/risk/verify?tmp_token=9e785433940891dfa78f033fb7928181&request_id=e5a6d6480df04097870be56c6e60f7ef&source=risk","token_info":null,"cookie_info":null,"sso":null,"is_new":false,"is_tourist":false}} String url = data['url']!; @@ -520,7 +517,7 @@ class LoginPageController extends GetxController case 0: // login success break; - case -105 when (!Platform.isLinux): + case -105: String captureUrl = res['data']['url']; Uri captureUri = Uri.parse(captureUrl); captchaData.token = captureUri.queryParameters['recaptcha_token']!; diff --git a/lib/pages/login/geetest/geetest_webview_dialog.dart b/lib/pages/login/geetest/geetest_webview_dialog.dart index 2ce9966d6..b78ad963e 100644 --- a/lib/pages/login/geetest/geetest_webview_dialog.dart +++ b/lib/pages/login/geetest/geetest_webview_dialog.dart @@ -1,24 +1,44 @@ -import 'dart:convert'; +import 'dart:convert' show jsonDecode, jsonEncode; +import 'dart:io' show Platform, Directory, File; import 'package:PiliPlus/http/browser_ua.dart'; import 'package:PiliPlus/http/init.dart'; import 'package:PiliPlus/http/loading_state.dart'; import 'package:PiliPlus/main.dart'; import 'package:PiliPlus/utils/accounts/account.dart'; +import 'package:desktop_webview_window/desktop_webview_window.dart'; import 'package:dio/dio.dart'; import 'package:flutter/material.dart'; import 'package:flutter_inappwebview/flutter_inappwebview.dart'; import 'package:get/get.dart'; -class GeetestWebviewDialog extends StatelessWidget { +class GeetestWebviewDialog extends StatefulWidget { const GeetestWebviewDialog(this.gt, this.challenge, {super.key}); final String gt; final String challenge; + @override + State createState() => _GeetestWebviewDialogState(); +} + +class _GeetestWebviewDialogState extends State { static const _geetestJsUri = 'https://static.geetest.com/static/js/fullpage.0.0.0.js'; + late final Future> _future; + Webview? _linuxWebview; + late bool _linuxWebviewLoading = true; + + @override + void initState() { + super.initState(); + _future = _getConfig(widget.gt, widget.challenge); + if (Platform.isLinux) { + _initLinuxWebview(); + } + } + static Future> _getConfig( String gt, String challenge, @@ -62,9 +82,126 @@ class GeetestWebviewDialog extends StatelessWidget { return Error(res.data['message']); } + Future _initLinuxWebview() async { + final config = await _future; + + if (!mounted) { + return; + } + + if (config is Error) { + config.toast(); + Get.back(); + return; + } + + final response = (config as Success).response; + + _linuxWebview = await WebviewWindow.create( + configuration: const CreateConfiguration( + windowWidth: 300, + windowHeight: 400, + title: "验证码", + ), + ); + + if (!mounted) { + _closeLinuxWebview(); + return; + } + + _linuxWebview!.addOnWebMessageReceivedCallback((msg) { + final msgStr = msg.toString(); + if (msgStr.startsWith("success:")) { + final dataStr = msgStr.substring("success:".length); + try { + final data = jsonDecode(dataStr); + Get.back(result: data); + } catch (e) { + debugPrint('geetest decode error: $e'); + } + } else if (msgStr.startsWith("error:")) { + debugPrint('geetest error: $msgStr'); + } + }); + + _linuxWebview!.onClose.whenComplete(() { + if (mounted) { + Get.back(); + } + }); + + final html = + ''' + + + + +'''; + + final tempDir = Directory.systemTemp; + final file = File( + '${tempDir.path}/geetest_${DateTime.now().millisecondsSinceEpoch}.html', + ); + await file.writeAsString(html); + + if (!mounted) { + _closeLinuxWebview(); + return; + } + + _linuxWebview!.launch('file://${file.path}'); + + if (mounted) { + setState(() { + _linuxWebviewLoading = false; + }); + } + } + + void _closeLinuxWebview() { + _linuxWebview?.close(); + _linuxWebview = null; + } + + @override + void dispose() { + _closeLinuxWebview(); + super.dispose(); + } + @override Widget build(BuildContext context) { - final future = _getConfig(gt, challenge); + if (Platform.isLinux) { + return AlertDialog( + title: const Text('验证码'), + content: SizedBox( + width: 300, + height: 400, + child: Center( + child: _linuxWebviewLoading + ? const CircularProgressIndicator() + : const Text('请在弹出的新窗口中完成验证'), + ), + ), + actions: [ + TextButton( + onPressed: Get.back, + child: Text( + '取消', + style: TextStyle(color: ColorScheme.of(context).outline), + ), + ), + ], + ); + } + return AlertDialog( title: const Text('验证码'), content: SizedBox( @@ -108,7 +245,8 @@ class GeetestWebviewDialog extends StatelessWidget { ); }, onLoadStop: (ctr, _) async { - final config = await future; + final config = await _future; + if (!mounted) return; if (config case Success(:final response)) { ctr.evaluateJavascript( source: diff --git a/lib/pages/login/view.dart b/lib/pages/login/view.dart index df62625c5..c8ed426b0 100644 --- a/lib/pages/login/view.dart +++ b/lib/pages/login/view.dart @@ -1,4 +1,3 @@ -import 'dart:io'; import 'dart:ui'; import 'package:PiliPlus/common/constants.dart'; @@ -380,7 +379,6 @@ class _LoginPageState extends State { Builder( builder: (context) { return PopupMenuButton( - enabled: !Platform.isLinux, padding: EdgeInsets.zero, tooltip: '选择国际冠码,' @@ -428,7 +426,6 @@ class _LoginPageState extends State { const SizedBox(width: 6), Expanded( child: TextField( - enabled: !Platform.isLinux, controller: _loginPageCtr.telTextController, keyboardType: TextInputType.number, inputFormatters: [ @@ -460,7 +457,6 @@ class _LoginPageState extends State { children: [ Expanded( child: TextField( - enabled: !Platform.isLinux, controller: _loginPageCtr.smsCodeTextController, decoration: const InputDecoration( prefixIcon: Icon(Icons.sms_outlined), @@ -475,11 +471,9 @@ class _LoginPageState extends State { ), Obx( () => TextButton.icon( - onPressed: !Platform.isLinux - ? _loginPageCtr.smsSendCooldown > 0 - ? null - : _loginPageCtr.sendSmsCode - : null, + onPressed: _loginPageCtr.smsSendCooldown > 0 + ? null + : _loginPageCtr.sendSmsCode, icon: const Icon(Icons.send), label: Text( _loginPageCtr.smsSendCooldown > 0 @@ -494,7 +488,7 @@ class _LoginPageState extends State { ), const SizedBox(height: 20), OutlinedButton.icon( - onPressed: !Platform.isLinux ? _loginPageCtr.loginBySmsCode : null, + onPressed: _loginPageCtr.loginBySmsCode, icon: const Icon(Icons.login), label: const Text('登录'), ), diff --git a/lib/utils/request_utils.dart b/lib/utils/request_utils.dart index 214c011e6..9d68cf03d 100644 --- a/lib/utils/request_utils.dart +++ b/lib/utils/request_utils.dart @@ -493,10 +493,6 @@ abstract final class RequestUtils { String vVoucher, ValueChanged onSuccess, ) async { - if (Platform.isLinux) { - return; - } - final res = await ValidateHttp.gaiaVgateRegister(vVoucher); if (!res.isSuccess) { res.toast(); diff --git a/linux/runner/my_application.cc b/linux/runner/my_application.cc index 29438bd5f..40dcec086 100644 --- a/linux/runner/my_application.cc +++ b/linux/runner/my_application.cc @@ -46,9 +46,9 @@ static void my_application_activate(GApplication *application) { // if future cases occur). const gboolean use_header_bar = [window]() -> gboolean { - if (g_file_test( - g_build_filename(g_get_user_data_dir(), "com.example.piliplus", "use_ssd", NULL), - G_FILE_TEST_EXISTS)) + if (g_file_test(g_build_filename(g_get_user_data_dir(), + "com.example.piliplus", "use_ssd", NULL), + G_FILE_TEST_EXISTS)) return FALSE; #ifdef GDK_WINDOWING_X11 diff --git a/pubspec.lock b/pubspec.lock index 0f01e2f0e..3a83f8be8 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -387,6 +387,15 @@ packages: url: "https://pub.dev" source: hosted version: "0.7.12" + desktop_webview_window: + dependency: "direct main" + description: + path: "." + ref: main + resolved-ref: b429f8ba6b8a99cd0f7eb5fe8d1621f325635c3d + url: "https://github.com/Predidit/linux_webview_window" + source: git + version: "0.2.4" device_info_plus: dependency: "direct main" description: diff --git a/pubspec.yaml b/pubspec.yaml index c9d034d43..bff51b710 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -79,6 +79,10 @@ dependencies: # 浏览器 # webview_flutter: ^4.10.0 flutter_inappwebview: ^6.1.5 + desktop_webview_window: + git: + url: https://github.com/Predidit/linux_webview_window + ref: main # 解决sliver滑动不同步 # extended_nested_scroll_view: ^6.2.1 extended_nested_scroll_view: