Merge main into codex/tempdir-media-spooling

This commit is contained in:
Levi committed 2026-09-16 23:20:29 +08:00
commit 5342be16d9
32 files changed
+1709 -46

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';
@@ -73,7 +74,6 @@ class WebViewRpcService {
final Map<String, WebViewRpcPageSession> _pagesById = {};
final Completer<void> _overlayReady = Completer<void>();
late final CookieManager _cookieManager = CookieManager.instance();
RpcServerHandle? _server;
int _pageSeq = 0;
@@ -129,6 +129,9 @@ class WebViewRpcService {
switch (method) {
case 'webview.isAvailable':
return {'available': true};
case 'profile.remove':
await _removeProfile(_string(params, 'profileId'));
return {};
case 'page.open':
return _openPage(params);
case 'page.addInitScript':
@@ -162,10 +165,12 @@ class WebViewRpcService {
}
Future<Map<String, dynamic>> _openPage(Map<String, dynamic> params) async {
final profile = WebViewProfile(_string(params, 'profileId'));
await profile.prepare(proxyUrl: Uri.parse(_string(params, 'proxyUrl')));
final pageId = 'page-${++_pageSeq}';
final session = WebViewRpcPageSession(
pageId: pageId,
cookieManager: _cookieManager,
profile: profile,
headless: params['headless'] as bool? ?? false,
debug: params['debug'] as bool? ?? false,
title: params['title'] as String? ?? '',
@@ -185,6 +190,15 @@ class WebViewRpcService {
return {'pageId': pageId};
}
Future<void> _removeProfile(String id) async {
for (final page in _pagesById.values.where((page) => page.profile.id == id).toList()) {
await _closePage(page.pageId);
}
// Let visible platform views unmount before releasing their native store.
await WidgetsBinding.instance.endOfFrame;
await WebViewProfile(id).remove();
}
WebViewRpcPageSession _page(Map<String, dynamic> params) {
final page = _pagesById[_pageId(params)];
if (page == null) {
@@ -271,6 +285,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',
@@ -283,7 +300,7 @@ class WebViewRpcService {
class WebViewRpcPageSession {
WebViewRpcPageSession({
required this.pageId,
required this.cookieManager,
required this.profile,
required this.headless,
required this.debug,
required this.title,
@@ -293,7 +310,8 @@ class WebViewRpcPageSession {
});
final String pageId;
final CookieManager cookieManager;
final WebViewProfile profile;
late final CookieManager cookieManager = profile.cookieManager;
final bool headless;
final bool debug;
final String title;
@@ -449,6 +467,8 @@ class WebViewRpcPageSession {
'path': cookie.path ?? '/',
'secure': cookie.isSecure,
'httpOnly': cookie.isHttpOnly,
if (cookie.expiresDate != null)
'expires': DateTime.fromMillisecondsSinceEpoch(cookie.expiresDate!, isUtc: true).toIso8601String(),
};
})
.toList(growable: false);
@@ -524,6 +544,7 @@ class WebViewRpcPageSession {
}
InAppWebViewSettings get _settings => InAppWebViewSettings(
profileId: profile.id,
javaScriptEnabled: true,
transparentBackground: true,
isInspectable: debug,