Подтвердить что ты не робот

Понимание веб-интерфейса Android addjavascriptinterface

Я знаю, что для взаимодействия с Javascript на Java вам нужно вставить объект Java с помощью метода addjavascriptInterface в webview.

Вот проблема, с которой я сталкиваюсь.

  • Я зарегистрирую объект java с использованием метода addJavascriptInterface, который будет доступен в моем JS.

  • Я добавляю несколько JS в веб-просмотр, используя webview.loadURL("javascript:XXX");

  • Я отправляю событие JS, когда я закончил с инъекцией JS.

Проблема заключается в том, что если сразу после шага 1, если я выполняю следующий Javascript:

mWebView.loadUrl("javascript:if(window.myobject) console.log('myobject found---------'); else {console.log('myobject not found----');}");

Я получаю "myobject not found" в моем журнале консоли.

Я хочу знать, что если есть время, прежде чем я получу доступ к моему объекту, и если да, то как мне узнать, сколько времени ждать, чтобы вызвать мой объект?

4b9b3361

Ответ 1

Я хочу знать, что если есть время, прежде чем я могу получить доступ к моему объекту

Да, я думаю, что есть задержка, потому что WebView.addJavascriptInterface будет запущен в внутреннем рабочем потоке WebView. Возможно, вы об этом подумали и поняли, что WebView должен поддерживать по крайней мере один рабочий поток для выполнения асинхронной сетевой операции ввода-вывода. Возможно, вы также заметили эти потоки в DDMS при использовании WebView.

Оказывается, он также использует поток для работы для ряда других общедоступных методов. Я очень хочу, чтобы документы Google сделали это яснее! Но я надеюсь, что смогу помочь и показать вам, как я пытался подтвердить это для себя.

Следуйте за мной, когда я взгляну на источник для WebView. Это разумно читаемо, даже если вы не можете точно следить за тем, что происходит, можно проследить ответы на некоторые вопросы относительно потоков.

Вы можете загрузить исходный код Android с помощью инструмента менеджера SDK, но он также отразился на Github, так что я связался здесь. Я догадался и выбрал тег, близкий к некоторой версии ICS. Нетрудно найти WebView.addJavascriptInterface. Я просто Googled "WebView.java сайт: github.com/android".

Метод WebView.addJavascriptInterface отправляет сообщение экземпляру WebViewCore:

mWebViewCore.sendMessage(EventHub.ADD_JS_INTERFACE, arg);

В WebViewCore.java есть множество перегруженных методов, называемых sendMessage, но нам не нужно знать, что именно вызывается, поскольку они делаю почти то же самое. Там даже хороший комментарий, чтобы дать нам намек, что мы в нужном месте! Все они делегируют экземпляр EventHub, который является некоторым внутренним классом. Этот метод оказывается синхронизированным и отправляет сообщение в экземпляр Handler, что является хорошим показателем того, что это, вероятно, работает в другом потоке, но для полноты, давайте узнаем!

Этот Handler создается в EventHub.transferMessages, который вызывается из WebViewCore.initialize. Здесь есть еще несколько прыжков, но в конце концов я узнал, что это вызвано из run в WebCoreThread (подкласс Runnable), который создается вместе с новым Thread правом .

Какое приключение! Поэтому, хотя я действительно не могу точно сказать, что происходит со всеми этими движущимися частями, я уверен, что этот метод не является синхронным и отправляет сообщение в рабочий поток WebView. Надеюсь это имеет смысл!

Если да, как узнать, сколько времени мне нужно подождать, чтобы вызвать мой объект?

К сожалению, я не знаю ответа на этот вопрос. Я изучал этот точный вопрос и нашел этот вопрос в StackOverflow в ходе моего Googling. Я думаю, у вас есть следующие варианты, некоторые из которых лучше или проще других:

1) Просто Thread.sleep за 100 мс или что-то среднее между addJavascriptInterface и loadUrl("javascript:..."). Блех, мне это не нравится, но это, возможно, самый простой.

2) Еще одна возможность состоит в том, что вы могли бы вызвать WebView.loadUrl со фрагментом JavaScript, который специально проверяет, установлен ли интерфейс, и улавливает возвращаемое ReferenceError, если оно еще не установлено. Однако, как вы, возможно, догадались, это связано с добавлением интерфейса JavaScript в WebView!

3) Вместо этого вызовите WebView.setWebChromeClient и перехватите JavaScript alert() или console.log. Из моих экспериментов этот метод синхронный, поэтому нет задержки. (Я подтвердил это в источнике, но я оставлю детали как упражнение для читателя). Вероятно, вы должны найти специальную строку для вызова alert с и проверить ее внутри onJsAlert, так что вы не просто ловите все alert() s.

Извините за длину этого ответа, надеюсь, это поможет. Удачи!

Ответ 2

Убедитесь, что ваши объекты Javascript, объявленные в вашем HTML/Javascript, которые вам нужны для доступа с Java, объявляются глобальными, иначе они, скорее всего, будут собраны. У меня есть код, который делает это (где Android - это мой интерфейс, добавленный с addJavascriptInterface):

<script>
  var cb = function(location) {
     alert('location is ' + location);
  }
  Android.getLocation('cb');
</script>

Метод getLocation вызывает Android LocationManager.requestSingleUpdate, который затем вызывает обратный вызов при срабатывании LocationListener.

Без "var" я обнаружил, что к тому моменту, когда поиск местоположения вызывает обратный вызов, функция обратного вызова была собрана мусором.

Ответ 3

(скопирован из моего ответа на аналогичный вопрос)

Я применил реализацию Джейсона Шаха и г-на S в качестве строительного блока для моего исправления и значительно улучшил его.

В этот комментарий есть слишком много кода, который я просто свяжу с ним.

Ключевые моменты:

  • Относится ко всем версиям Gingerbread (2.3.x)
  • Звонки с JS на Android теперь синхронны
  • Больше не нужно вручную отображать методы интерфейса.
  • Исправлена ​​возможность разбиения разделителей строк
  • Намного легче изменить JS-подпись и имена интерфейсов