У меня есть приложение Delphi со встроенным браузером CEF, и оно перестало работать с тех пор, как я обновил CEF 117.1.4 и Chromium 117.0.5938.92 до CEF 123.0.12 и Chromium 123.0.6312.107.
С CEF 117 я могу без проблем запустить два экземпляра приложения, но теперь при запуске второго экземпляра происходит сбой:
begin
GlobalCEFApp := TCefApplication.Create;
InicializaCef;
// Reducir el número de locales a un mínimo
GlobalCEFApp.LocalesRequired := 'ca,de,en-GB,en-US,es-419,es,fr,it,pt-BR,pt-PT';
GlobalCEFApp.SetCurrentDir := True;
GlobalCEFApp.LocalesDirPath := 'locales';
Application.Initialize;
Application.Title := 'QBrowser';
Application.CreateForm(TMainForm, MainForm);
test := GlobalCEFApp.StartMainProcess;
if test then
Application.Run;
GlobalCEFApp.Free;
GlobalCEFApp := nil;
end.
GlobalCEFApp.StartMainProcess теперь возвращает False.
Есть ли какое-то новое значение конфигурации, которое я упускаю из виду?
CEF изменил способ инициализации и теперь проверяет, работает ли другое приложение с той же настройкой RootCache
. Эта функция была добавлена в CEF 120.1.8.
Если GlobalCEFApp.Cache
и GlobalCEFApp.RootCache
пусты, то будет использоваться каталог конкретной платформы по умолчанию. В случае с Windows: %AppData%\Local\CEF\User Data\
.
Использование каталога по умолчанию не рекомендуется в производственных приложениях. Запись нескольких экземпляров приложения в один и тот же каталог GlobalCEFApp.RootCache
может привести к повреждению данных.
Есть два способа избежать этого:
GlobalCEFApp.OnAlreadyRunningAppRelaunch
, чтобы получать уведомления о запуске нового экземпляра приложения и открытии новой вкладки или дочерней формы в веб-браузере.GlobalCEFApp.RootCache
для каждого экземпляра приложения.Прочтите документацию, чтобы узнать все подробности (найдите TCefApplicationCore
по типу) о:
GlobalCEFApp.OnAlreadyRunningAppRelaunch
:
Реализуйте эту функцию, чтобы обеспечить поведение, специфичное для приложения, когда уже запущенное приложение перезапускается с тем же значением
TCefSettings.root_cache_path
. Например, активируйте существующее окно приложения или создайте новое окно приложения.command_line
будет доступен только для чтения. Не оставляйте ссылку наcommand_line
вне этой функции. Вернитеtrue
(1
), если перезапуск обработан, илиfalse
(0
) для поведения перезапуска по умолчанию. Поведение по умолчанию создаст новое окно Chrome в стиле по умолчанию.Чтобы избежать повреждения кэша, для данного значения
TCefSettings.root_cache_path
разрешен запуск только одного экземпляра приложения. При перезапуске приложение проверяет одноэлементную блокировку процесса, а затем пересылает новые аргументы запуска уже запущенному процессу приложения перед досрочным завершением. Поэтому клиентские приложения должны проверить возвращаемое значениеcef_initialize()
для раннего выхода, прежде чем продолжить.Эта функция будет вызываться в потоке пользовательского интерфейса процесса браузера.
GlobalCEFApp.RootCache
:
Корневой каталог для данных, относящихся к установке, и родительский каталог для данных, относящихся к профилю. Все значения
TCefSettings.cache_path
иICefRequestContextSettings.cache_path
должны иметь общий родительский каталог. Если это значение пусто иTCefSettings.cache_path
не пусто, то по умолчанию будет установлено значениеTCefSettings.cache_path
. Любое непустое значение должно быть абсолютным путем. Если оба значения пусты, то будет использоваться каталог по умолчанию, специфичный для платформы (каталог~/.config/cef_user_data
в Linux, каталог~/Library/Application Support/CEF/User Data
в MacOS, каталогAppData\Local\CEF\User Data
в каталоге профиля пользователя в Windows). Использование каталога по умолчанию не рекомендуется в производственных приложениях (см. ниже).Запись нескольких экземпляров приложения в один и тот же каталог
root_cache_path
может привести к повреждению данных. Поэтому для защиты от этого используется одноэлементная блокировка процесса на основе значенияroot_cache_path
. Такое одноэлементное поведение применяется ко всем приложениям на основе CEF, использующим версию 120 или новее. Вам следует настроитьroot_cache_path
для своего приложения и реализоватьICefBrowserProcessHandler.OnAlreadyRunningAppRelaunch
, который затем будет вызываться при любом перезапуске приложения с тем же значениемroot_cache_path
.Неправильная установка значения
root_cache_path
может привести к сбоям при запуске или другим неожиданным последствиям (например, песочница блокирует доступ для чтения и записи к определенным файлам).
GlobalCEFApp.Cache
:
Каталог, в котором на диске будут храниться данные глобального кэша браузера. Если это значение не пусто, то это должен быть абсолютный путь, равный или дочерний каталог
TCefSettings.root_cache_path
. Если это значение пустое, браузеры будут созданы в «режиме инкогнито», где для хранения используются кэши в памяти, и никакие данные, специфичные для профиля, не сохраняются на диске (данные, специфичные для установки, все равно будут сохраняться в root_cache_path). Базы данных HTML5, такие какlocalStorage
, будут сохраняться между сеансами только в том случае, если указан путь к кэшу. Может быть переопределено для отдельных экземпляровICefRequestContext
с помощью значенияICefRequestContextSettings.cache_path
. При использовании среды выполнения Chrome любое значение дочернего каталога будет игнорироваться и вместо него будет использоваться профиль «по умолчанию» (также дочерний каталог).
В документах написано «функция», но TOnAlreadyRunningAppRelaunchEvent
— это процедура. Доступ к папке Windows AppData
текущего пользователя можно получить с помощью переменной среды %AppData%
(также работает в Проводнике).
@salvador-díaz-fau Я следовал вашим инструкциям и теперь успешно запускаю несколько экземпляров. При запуске я создаю случайное имя для папки, которая будет использоваться в качестве кеша: if CreateDir(UniqueCache) then GlobalCEFApp.RootCache := UniqueCache;
Но, поскольку я тоже использую GlobalCEFApp.SingleProcess := False
, это заканчивается созданием нескольких папок. Есть ли способ создать только один временный кеш? Где мне удалить папку кэша?
Вы можете создавать уникальные каталоги кэша, объединяя идентификатор процесса. Например, «c:\rootcache» + inttostr(MyCurrentProcessID). Затем вы можете периодически удалять неиспользуемые каталоги кэша.
Где мне следует удалить временный кеш? Приложение создает несколько папок, но я могу удалить только одну из них. Я попробовал GlobalCEFApp.OnBrowserDestroyed
, но он не вызывается.
Если все экземпляры вашего приложения создают каталоги корневого кэша с идентификатором процесса, вы можете получить список всех идентификаторов процессов вашего приложения и сравнить эти значения с именами каталогов корневого кэша. Если каталог корневого кэша имеет неиспользуемый идентификатор процесса, вы можете безопасно удалить его в любое время и из любого места.
Почему бы не спросить его автора?