WebView скрывает мягкую клавиатуру во время loadUrl(), что означает, что клавиатура не может оставаться открытой при вызове javascript

Так как вы вызываете javascript в WebView через loadUrl ( "javascript:..." ); Клавиатура не может оставаться открытой.

Метод loadUrl() вызывает loadUrlImpl(), который вызывает метод под названием clearHelpers(), который затем вызывает clearTextEntry(), который затем вызывает hideSoftKeyboard(), а затем мы становимся настолько одинокими, что клавиатура уходит.

Насколько я вижу, все они являются частными и не могут быть переопределены.

Кто-нибудь нашел обходное решение для этого? Есть ли способ заставить клавиатуру оставаться открытой или напрямую вызвать javascript, не перейдя через loadUrl()?

Можно ли переопределить WebView, чтобы предотвратить вызов (private method) clearTextEntry()?

Ответы

Ответ 1

Обновление

KitKat добавил публичный метод для непосредственного вызова javascript: оценитьJavascript()

Для более старой версии apis вы можете попробовать решение, как показано ниже, но если бы мне пришлось это сделать снова, я бы посмотрел только на создание метода совместимости, который в KitKat использует вышеуказанный метод и на более старых устройствах, использует отражение для детализации для внутреннего частного метода: BrowserFrame.stringByEvaluatingJavaScriptFromString()

Затем вы можете напрямую вызвать javascript, не имея дело с loadUrl и добавив "javascript: " в script.

Старый ответ

В соответствии с просьбой Алока Кулкарни, я дам краткий обзор возможного обходного пути, о котором я думал об этом. Я на самом деле не пробовал, но теоретически он должен работать. Этот код будет грубым и просто служит примером.

Вместо того, чтобы отправлять вызовы через loadUrl(), вы ставите в очередь свои javascript-вызовы, а затем javascript вытаскивает их. Что-то вроде:

private final Object LOCK = new Object();
private StringBuilder mPendingJS;

public void execJS(String js) {
    synchronized(LOCK) {
        if (mPendingJS == null) {
            mPendingJS = new StringBuilder();
            mPendingJS.append("javascript: ");
        }
        mPendingJS
            .append(js)
            .append("; ");
    }
}

Вместо вызова метода loadUrl() этот метод. (Для этого просто я использовал синхронизированный блок, но это может быть лучше подходит для другого маршрута. Поскольку javascript работает в своем потоке, это должно быть потокобезопасным в той или иной форме).

Тогда ваш WebView будет иметь такой интерфейс:

public class JSInterface {

    public String getPendingJS() {
        synchronized(LOCK) {
            String pendingCommands = mPendingJS.toString();
            mPendingJS.setLength(0);
            mPendingJS.append("javascript: ");
            return pendingCommands;
        }
    }

}

Это возвращает строку с ожидающими командами и очищает их, чтобы они не возвращались снова.

Вы бы добавили его в WebView следующим образом:

mWebView.addJavascriptInterface(new JSInterface(), "JSInterface");

Тогда в вашем javascript вы установили бы некоторый интервал, в который нужно сбросить отложенные команды. На каждом интервале он вызывал бы JSInterface.getPendingJS(), который возвращал бы строку всех ожидающих команд, а затем вы могли бы их выполнить.

Вы можете улучшить это, добавив проверку метода execJS, чтобы узнать, существует ли в WebView поле EditText и находится в фокусе. Если он есть, то вы будете использовать этот метод очередности, но если его не было в фокусе, вы можете просто вызвать loadUrl(), как обычно. Таким образом, он использует это обходное решение, когда ему действительно нужно.

Ответ 2

Что касается более старых API (до 19), я использовал аналогичный метод для ответа, но немного отличается.

Во-первых, я отслеживаю, отображается ли клавиатура с помощью javascript в веб-представлении примерно так:

document.addEventListener( "focus", function(e){        
    var el = e.target;
    reportKeyboardDisplayedToJava( isInputElement( el ) );
}, true);

document.addEventListener( "blur", function(e){        
    reportKeyboardDisplayedToJava( false );
}, true);

Если клавиатура отображается, а js-инъекция выполняется с помощью уровня Java Java - я "откладываю" эту инъекцию. Я добавляю его в список строк, позволяю пользователю закончить ввод данных, а затем при исчезновении клавиатуры я обнаруживаю это и выполняю отставание от инъекций.