Функции JCEF работают только со второго вызова (Java Chromium Embedded Framework)

Недавно я интегрировал Java Chromium Embedded Framework (https://github.com/chromiumembedded/java-cef) в проекте приложения Netbeans (RCP) (Java: JDK11).

Окно браузера отображается в Netbeans TopComponent и в целом работает нормально.

Однако у меня есть несколько довольно небольших, но неприятных ошибок, которые я заметил, которые всегда следуют одному и тому же шаблону: какой бы код я ни выполнял, относящийся к браузеру jcef, всегда работает только тогда, когда я запускаю его во второй раз, и практически игнорируется в первый раз. Однако нет сообщений об ошибках, журналов или чего-то подобного, и код, кажется, выполняется, когда я просматриваю его с помощью инструмента отладки.

Три примера:

  1. Реализация кнопки возврата:
    Это просто проверяет, возвращает ли экземпляр CefBrowser true вместо browser.canGoBack(). Если он возвращает true, кнопка активирована.
    Значение начинается правильно с false, но возвращает true сразу после второго изменения URL. (Очевидно, что это должно произойти после первого)
    С этого момента все работает нормально ....Если только вы не вернетесь (кнопкой возврата) на главную страницу. Затем он, очевидно, должен снова вернуть false, чего не происходит.
    Повторный вызов другого URL возвращает false вместо canGoBack() (который, очевидно, должен быть true) и возвращает true только после второго изменения URL.
    Таким образом, return from canGoBack всегда показывает доход, который он должен был показать от своего предыдущего выполнения, как если бы он отставал на один раз.
  2. Реализация функции перехода
    Эта функция просто перенаправляет вас на указанный веб-сайт, отличный от домашней страницы. Опять же, со второго раза работает нормально, но в первый раз код просто игнорируется. (хотя через отладчик я подтвердил, что код выполняется без ошибок даже с первого раза)
  3. Реализация диалогового окна входа в систему.
    Если браузер замечает, что требуется аутентификация, открывается диалоговое окно, в котором пользователь может ввести БАЗОВЫЕ учетные данные.
    И снова открывается диалоговое окно, учетные данные возвращаются правильно (подтверждено через журнал), передаются соответствующей функции, и она работает со второй попытки, но не с первой. (учетные данные были идентичны)
    Действительно, я подтвердил через Wireshark, что при первом выполнении callback.Continue(ad.getUsername(), ad.getPassword()); на сервер вообще ничего не отправляется...

Код для третьего примера:

cefClient_.addRequestHandler(new CefRequestHandlerAdapter() {
            @Override
            public boolean getAuthCredentials(CefBrowser browser, String origin_url, boolean isProxy, String host,
                    int port, String realm, String scheme, CefAuthCallback callback) {
               
                AuthenticationDialog ad = new AuthenticationDialog();                
                ad.authenticate(); // Shows Login Dialog
                LOGGER.log(Level.INFO, String.format("--->%s:%s", ad.getUsername(), ad.getPassword())); //This confirms that the variables are indeed correct even the first time around
                callback.Continue(ad.getUsername(), ad.getPassword());
                return true;
            }
        });

К сожалению, я больше не знаю, что может вызвать эти проблемы.

Если у кого-то из вас были такие же проблемы или есть какие-либо идеи о том, как их исправить или даже где начать искать исправление, я был бы очень признателен за ваши комментарии.

Заранее спасибо!


person Daki    schedule 01.10.2020    source источник
comment
Вы пробовали форум JCEF?   -  person Abra    schedule 01.10.2020
comment
Спасибо за совет. Пробовал искать на этом форуме, но похожих проблем не нашел. (те, которые звучали похоже, тоже не сработали) Я, вероятно, также должен опубликовать этот вопрос там.   -  person Daki    schedule 01.10.2020
comment
Поскольку я не нашел ни одной темы на форуме jcef, посвященной этой конкретной теме, вполне может быть, что эта проблема на самом деле возникает из-за того, что jcef работает в Netbeans RCP. Конечно, это не первый раз, когда Netbeans RCP мешает чему-то еще...   -  person Daki    schedule 01.10.2020


Ответы (1)


Я нашел ответы на вышеупомянутые вопросы. На случай, если кто-то еще столкнется с подобными проблемами в будущем, я собираюсь кратко суммировать то, что исправило это для меня.

По-видимому, большинство проблем, с которыми я столкнулся, возникли из-за проблем с потоками. Похоже, когда вы выполняете команду в браузере jcef, пока его поток все еще работает над чем-то, ваша команда не будет выполнена, но также не будет никаких сообщений об ошибках или другого нежелательного поведения.

Пример второй проблемы: при выполнении команды go(url) браузер еще не полностью загрузил начальную домашнюю страницу. Поэтому команда была проигнорирована. Чтобы исправить это, я добавил простую переменную String, которая будет сохранять URL-адрес, который кто-то хочет загрузить, пока браузер не завершит загрузку предыдущей страницы. Только тогда этот URL-адрес будет загружен в браузер и, следовательно, удален из переменной. Конечно, это можно было бы сделать и с чем-то вроде списка, но я не могу придумать сценарий, в котором это было бы полезно. Проверка того, завершена ли загрузка браузера, должна выполняться в переопределенном методе onLoadingStateChange файла CefLoadHandlerAdapter.

client_.addLoadHandler(new CefLoadHandlerAdapter() {
        @Override
        public void onLoadingStateChange(CefBrowser browser, boolean isLoading,
                boolean canGoBack, boolean canGoForward) {
            if (!isLoading) {
                browser_ready = true;
                if (goOnReady != null) {
                    goURL(goOnReady);
                }
            }
        }
    });

Аналогичная проблема присутствовала в первом примере из исходного вопроса. Активация кнопки «Назад» в вышеупомянутом onLoadingStateChange через переменную canGoBack в конце концов помогла мне.

Теперь третий пример (диалоговое окно входа отображается дважды) оказался проблемой, которая также присутствовала в официальном подробном коде примера со страницы jcef github. Эта проблема кажется, что это может быть проблема с потоками, но на этот раз я не уверен. В качестве обходного пути я реализовал следующее решение:

  • добавить переменные класса для имени пользователя и пароля
  • если эти переменные пусты, запустите диалог входа в систему в методе getAuthCredentials (см. исходный вопрос) и сохраните заданное имя пользователя и пароль в этих переменных класса.
  • затем выполните browser.reload();
  • затем браузер снова пройдет аутентификацию, но на этот раз переменные не будут пустыми, и вы можете передать их callback.Continue(username, password);, таким образом показывая пользователю только один диалог входа в систему.

Этот процесс также очень быстрый, поэтому пользователь хочет иметь возможность заметить перезагрузку.

person Daki    schedule 12.10.2020