2012-06-09 20 views
21

So che per interagire da Javascript a Java devi iniettare un oggetto Java usando il metodo addjavascriptInterface in webview.Comprendere la webview di Android addjavascriptinterface

Ecco il problema che sto affrontando.

  1. registro un oggetto Java utilizzando addJavascriptInterface metodo per essere disponibile nel mio JS.

  2. ho iniettare qualche JS in WebView utilizzando webview.loadURL("javascript:XXX");

  3. mando un evento JS quando mi sono fatto con l'iniezione di JS.

Il problema è che se subito dopo il passo 1, se eseguo il seguente JavaScript:

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

ottengo "myobject non trovato" in una registrazione di mia console.

Voglio sapere se c'è un po 'di tempo prima che possa accedere al mio oggetto e, in tal caso, come faccio a sapere quanto tempo devo aspettare per chiamare il mio oggetto?

risposta

44

voglio sapere che se c'è un po 'di tempo prima che posso accedere al mio oggetto

Sì, penso che ci sia un ritardo, a causa WebView.addJavascriptInterface verrà eseguito nel thread di lavoro interno del WebView. Forse ci hai pensato, e hai realizzato che WebView deve mantenere almeno un thread di lavoro per fare l'IO della rete asincrona. Forse hai notato questi thread anche in DDMS mentre usi una WebView.

Si scopre che utilizza anche una discussione per eseguire il lavoro per una serie di altri metodi pubblici. Mi piacerebbe davvero che i documenti di Google rendessero questo più chiaro! Ma spero di poterti aiutare e mostrarti come ho provato a confermarlo da solo.

Seguimi mentre guardo il sorgente di WebView. È ragionevolmente leggibile, anche se non è possibile seguire esattamente quello che sta succedendo, è possibile risalire attraverso alcune domande riguardo ai thread.

È possibile scaricare la fonte framework Android tramite lo strumento di gestione SDK, ma è anche speculare su Github, quindi è a questo che ho collegato qui. Ho indovinato e ho scelto un tag vicino ad alcune versioni di ICS. Non è difficile trovare . Ho solo cercato su Google "Sito WebView.java: github.com/android".

Il metodo WebView.addJavascriptInterface invia un messaggio a un'istanza di WebViewCore:

mWebViewCore.sendMessage(EventHub.ADD_JS_INTERFACE, arg); 

In WebViewCore.java ci sono un sacco di metodi di overload chiamati sendMessage, ma non abbiamo davvero bisogno di sapere che esattamente viene chiamato, dal momento che fanno praticamente la stessa cosa C'è anche un bel commento per darci un suggerimento sul fatto che siamo nel posto giusto! Tutti loro delegano a un'istanza di EventHub che è una classe interna. This method risulta essere sincronizzato e sta inviando un messaggio a un'istanza di Handler, che è una buona indicazione che probabilmente è in esecuzione in un'altra discussione, ma per completezza, scopriamolo!

Questo Handler viene creata un'istanza in EventHub.transferMessages che viene chiamato da WebViewCore.initialize. Ci sono alcuni più luppolo qui, ma alla fine ho scoperto che questo è chiamato da run in WebCoreThread (sottoclasse di Runnable), che viene istanziato insieme a un nuovo Thread a destra here.

Che avventura! Quindi, anche se non posso davvero dire con certezza cosa sta succedendo con tutte queste parti mobili, sono abbastanza sicuro di dire che questo metodo non è sincrono e invia un messaggio al thread di lavoro di WebView. Spero che abbia un senso!

se sì, come faccio a sapere quanto tempo devo aspettare per chiamare il mio oggetto?

Purtroppo, non conosco la risposta a questo. Stavo cercando questo esatto problema e ho trovato questa domanda su StackOverflow nel corso del mio googling. Penso che tu abbia le seguenti opzioni, alcune delle quali sono più belle o più semplici di altre:

1) Solo Thread.sleep per 100 ms o qualcosa tra addJavascriptInterface e loadUrl("javascript:..."). Blech, non mi piace, ma è potenzialmente il più facile.

2) Un'altra possibilità è che è possibile chiamare WebView.loadUrl con uno snippet di JavaScript che verifica specificamente se l'interfaccia è impostata e rileva l'Eccezione di riferimento che viene generata se non è stata ancora impostata. Tuttavia, come avrai intuito, questo tipo comporta l'aggiunta di un'interfaccia JavaScript alla WebView!

3) Chiama invece il numero WebView.setWebChromeClient e recupera JavaScript alert() o console.log. Dai miei esperimenti, questo metodo è sincrono, quindi non c'è alcun ritardo. (L'ho confermato alla fonte, ma lascerò i dettagli come esercizio per il lettore) Probabilmente dovresti inventare una stringa speciale per chiamare lo alert e controllarlo all'interno di onJsAlert, quindi non stai solo prendendo tutto il alert() S.

Ci scusiamo per la lunghezza di questa risposta, spero che aiuti. In bocca al lupo!

+0

Buona risposta elaborato con riferimenti appropriati. –

+0

cool. bella risposta Ma controllare gli avvisi e i messaggi della console sono altrettanto brutti di Thread.sleep() :) – Akshat

+0

Ehi, ma ho avvertito che le opzioni non sono ottimali: P – spacemanaki

1

Verificare che gli oggetti Javascript dichiarati nel codice HTML/Javascript che è necessario accedere da Java siano dichiarati globali, altrimenti verranno raccolti molto probabilmente. Ho codice che fa questo (dove Android è la mia interfaccia aggiunto con addJavascriptInterface):

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

Il getLocation invoca LocationManager.requestSingleUpdate di Android che poi richiama il callback quando i fuochi LocationListener.

Senza la "var" trovo che nel momento in cui la ricerca della posizione richiama il callback la funzione di callback è stata garbage collection.

0

(copiato da mia risposta su a similar question)

ho preso implementazione del signor S come il blocco di costruzione per il mio fix e migliorato grandemente di Jason Shah e.

C'è solo troppo codice da inserire in questo commento. Mi collegherò solo ad esso.

I punti chiave sono:

  • Si applica a tutte le versioni di Gingerbread (2.3.x)
  • chiamate da JS per Android sono ora sincroni
  • Non hanno più t o tracciare metodi di interfaccia manualmente
  • fisso possibilità di separatori di stringa che si infrangono il codice
  • molto più facile cambiare la firma JS e denominazioni delle interfacce
Problemi correlati