2012-06-09 1 views
21

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

Вот проблема, с которой я столкнулся.

  1. зарегистрировать объект Java, используя addJavascriptInterface метод будет доступен в моих JS.

  2. Я впрыснуть несколько JS в WebView с использованием webview.loadURL("javascript:XXX");

  3. Я посылаю событие JS, когда я сделал с инъекции JS.

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

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

я получаю «MyObject не найден» в журнале моей консоли.

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

ответ

44

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

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

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

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

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

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

mWebViewCore.sendMessage(EventHub.ADD_JS_INTERFACE, arg); 

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

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

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

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

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

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

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

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

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

+0

Хороший сложный ответ с соответствующими ссылками. –

+0

классный. хороший ответ. Но проверка предупреждений и консольных сообщений так же плоха, как и Thread.sleep() :) – Akshat

+0

Эй, я все предупреждал, что варианты субоптимальны: P – spacemanaki

1

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

метода
<script> 
    var cb = function(location) { 
    alert('location is ' + location); 
    } 
    Android.getLocation('cb'); 
</script> 

getLocation вызывающим LocationManager.requestSingleUpdate Android, который затем вызывает функцию обратного вызова когда в LocationListener пожары.

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

0

(копируется из моего ответа на a similar question)

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

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

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

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