Preserve existing profile connections when opening more pages

This commit is contained in:
Levi committed 2026-09-14 00:43:50 +08:00
1 parent ca98806dcc
commit c47b735fc4
8 files changed
+46 -11

No files matched your search

@@ -3,6 +3,7 @@ import 'dart:collection';
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_inappwebview/flutter_inappwebview.dart';
import '../../core/common/start_config.dart';
@@ -273,6 +274,9 @@ class WebViewRpcService {
if (error is WebViewRpcException) {
return {'code': error.code, 'message': error.message};
}
if (error is PlatformException && error.code == 'UNAVAILABLE') {
return {'code': error.code, 'message': error.message ?? 'WebView is unavailable'};
}
final code = switch (method) {
'page.goto' => 'NAVIGATION_FAILED',
'page.execute' => 'EVALUATION_FAILED',
@@ -10,6 +10,9 @@ import io.flutter.plugin.common.MethodChannel;
// Internal host bridge: profile creation and proxy completion precede navigation.
final class GopeedProfiles {
private static String appliedProxy;
private static String pendingProxy;
private static final java.util.List<MethodChannel.Result> pending = new java.util.ArrayList<>();
static void prepare(MethodCall call, MethodChannel.Result result) {
if (!WebViewFeature.isFeatureSupported(WebViewFeature.MULTI_PROFILE) ||
!WebViewFeature.isFeatureSupported(WebViewFeature.PROXY_OVERRIDE)) {
@@ -24,10 +27,29 @@ final class GopeedProfiles {
if (!"http".equals(uri.getScheme()) || !"127.0.0.1".equals(uri.getHost()) || uri.getPort() <= 0)
throw new IllegalArgumentException("Invalid host proxy configuration");
ProfileStore.getInstance().getOrCreateProfile(id);
if (proxy.equals(appliedProxy)) { result.success(true); return; }
if (pendingProxy != null) {
if (proxy.equals(pendingProxy)) pending.add(result);
else result.error("UNAVAILABLE", "A different WebView proxy is being configured", null);
return;
}
pendingProxy = proxy;
pending.add(result);
ProxyConfig config = new ProxyConfig.Builder().addProxyRule(proxy).removeImplicitRules().build();
ProxyController.getInstance().setProxyOverride(config, Runnable::run, () -> result.success(true));
ProxyController.getInstance().setProxyOverride(config, task -> new android.os.Handler(android.os.Looper.getMainLooper()).post(task), () -> {
appliedProxy = proxy;
pendingProxy = null;
java.util.List<MethodChannel.Result> completed = new java.util.ArrayList<>(pending);
pending.clear();
for (MethodChannel.Result callback : completed) callback.success(true);
});
} catch (RuntimeException e) {
result.error("UNAVAILABLE", "Unable to configure WebView profile and proxy", null);
if (pendingProxy != null && pending.contains(result)) {
pendingProxy = null;
java.util.List<MethodChannel.Result> failed = new java.util.ArrayList<>(pending);
pending.clear();
for (MethodChannel.Result callback : failed) callback.error("UNAVAILABLE", "Unable to configure WebView profile and proxy", null);
} else result.error("UNAVAILABLE", "Unable to configure WebView profile and proxy", null);
}
}
}
@@ -5,6 +5,7 @@ import Network
import Flutter
final class GopeedProfiles {
private static var proxyURLs: [String: String] = [:]
private static var stores: [String: WKWebsiteDataStore] = [:]
static func store(_ identifier: String) -> WKWebsiteDataStore? { stores[identifier] }
@@ -19,11 +20,16 @@ final class GopeedProfiles {
result(FlutterError(code: "UNAVAILABLE", message: "Isolated WebView profiles and proxy require macOS 14 / iOS 17 or newer and valid host configuration", details: nil))
return
}
if stores[identifier] != nil && proxyURLs[identifier] == proxyURL {
result(true)
return
}
let store = stores[identifier] ?? WKWebsiteDataStore(forIdentifier: uuid)
let endpoint = nw_endpoint_create_host(host, String(port))
let proxy = nw_proxy_config_create_socksv5(endpoint)
store.__proxyConfigurations = [proxy]
stores[identifier] = store
proxyURLs[identifier] = proxyURL
result(true)
}
}
@@ -5,6 +5,7 @@ import Network
import FlutterMacOS
final class GopeedProfiles {
private static var proxyURLs: [String: String] = [:]
private static var stores: [String: WKWebsiteDataStore] = [:]
static func store(_ identifier: String) -> WKWebsiteDataStore? { stores[identifier] }
@@ -19,11 +20,16 @@ final class GopeedProfiles {
result(FlutterError(code: "UNAVAILABLE", message: "Isolated WebView profiles and proxy require macOS 14 / iOS 17 or newer and valid host configuration", details: nil))
return
}
if stores[identifier] != nil && proxyURLs[identifier] == proxyURL {
result(true)
return
}
let store = stores[identifier] ?? WKWebsiteDataStore(forIdentifier: uuid)
let endpoint = nw_endpoint_create_host(host, String(port))
let proxy = nw_proxy_config_create_socksv5(endpoint)
store.__proxyConfigurations = [proxy]
stores[identifier] = store
proxyURLs[identifier] = proxyURL
result(true)
}
}
@@ -97,6 +97,7 @@ Future<void> checkProfiles() async {
final target = WebUri('https://profiles.invalid/');
final pages = <HeadlessInAppWebView>[];
Future<InAppWebViewController> open(WebViewProfile profile) async {
await profile.prepare(proxyUrl);
final ready = Completer<InAppWebViewController>();
final page = HeadlessInAppWebView(
onReceivedServerTrustAuthRequest: (_, _) async =>