Voglio ottenere un valore restituito da Javascript in Android. Posso farlo con l'iPhone, ma non posso farlo con Android. Ho usato loadUrl, ma è ritornato vuoto invece di un oggetto. Qualcuno può aiutarmi? Grazie.Come ottenere il valore di ritorno da javascript in webview di Android?
risposta
Utilizzare addJavascriptInterface()
per aggiungere un oggetto Java all'ambiente Javascript. Chiedi al tuo javascript di chiamare un metodo su quell'oggetto Java per fornire il suo "valore di ritorno".
Ecco un hack su come è possibile realizzarlo:
Aggiungi questo Cliente al vostro WebView:
final class MyWebChromeClient extends WebChromeClient {
@Override
public boolean onJsAlert(WebView view, String url, String message, JsResult result) {
Log.d("LogTag", message);
result.confirm();
return true;
}
}
Ora nella chiamata javascript fare:
webView.loadUrl("javascript:alert(functionThatReturnsSomething)");
Ora, nel onJsAlert chiama "messaggio" conterrà il valore restituito.
Questo è un hack estremamente prezioso; specialmente quando stai costruendo un'app in cui non hai il controllo su javascript e devi accontentarti delle funzioni esistenti. Nota che puoi ottenere lo stesso risultato senza intercettare gli avvisi JS usando 'booleano pubblico onConsoleMessage (consoleMessage consoleMessage)' invece di 'onJsAlert' e poi nella chiamata javascript fai' webView.loadUrl ("javascript: console.log (functionThatReturnsSomething) ");' - in questo modo lasci da solo gli avvisi JS. –
La soluzione con 'WebChromeClient.onConsoleMessage' sembra essere più pulita, ma sii consapevole che non funziona con alcuni dispositivi HTC. Vedi [questa domanda] (http://stackoverflow.com/questions/4860021/android-problem-with-debugging-javascript-in-webview) per maggiori informazioni. – Piotr
Qualsiasi motivo che usi addJavascriptInterface non sarebbe preferibile? – Keith
Ecco cosa mi è venuto in mente oggi. È thread-safe, ragionevolmente efficiente e consente l'esecuzione javascript javascript di da Java per una WebView Android.
Funziona su Android 2.2 e versioni successive. (Richiede commons-lang perché ho bisogno dei miei snippet di codice passati a eval() come stringa Javascript. Puoi rimuovere questa dipendenza avvolgendo il codice non tra virgolette, ma in function(){}
)
Innanzitutto, aggiungi questo al tuo Javascript File:
function evalJsForAndroid(evalJs_index, jsString) {
var evalJs_result = "";
try {
evalJs_result = ""+eval(jsString);
} catch (e) {
console.log(e);
}
androidInterface.processReturnValue(evalJs_index, evalJs_result);
}
Quindi, aggiungere questo alla tua attività Android:
private Handler handler = new Handler();
private final AtomicInteger evalJsIndex = new AtomicInteger(0);
private final Map<Integer, String> jsReturnValues = new HashMap<Integer, String>();
private final Object jsReturnValueLock = new Object();
private WebView webView;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
webView = (WebView) findViewById(R.id.webView);
webView.addJavascriptInterface(new MyJavascriptInterface(this), "androidInterface");
}
public String evalJs(final String js) {
final int index = evalJsIndex.incrementAndGet();
handler.post(new Runnable() {
public void run() {
webView.loadUrl("javascript:evalJsForAndroid(" + index + ", " +
"\"" + StringEscapeUtils.escapeEcmaScript(js) + "\")");
}
});
return waitForJsReturnValue(index, 10000);
}
private String waitForJsReturnValue(int index, int waitMs) {
long start = System.currentTimeMillis();
while (true) {
long elapsed = System.currentTimeMillis() - start;
if (elapsed > waitMs)
break;
synchronized (jsReturnValueLock) {
String value = jsReturnValues.remove(index);
if (value != null)
return value;
long toWait = waitMs - (System.currentTimeMillis() - start);
if (toWait > 0)
try {
jsReturnValueLock.wait(toWait);
} catch (InterruptedException e) {
break;
}
else
break;
}
}
Log.e("MyActivity", "Giving up; waited " + (waitMs/1000) + "sec for return value " + index);
return "";
}
private void processJsReturnValue(int index, String value) {
synchronized (jsReturnValueLock) {
jsReturnValues.put(index, value);
jsReturnValueLock.notifyAll();
}
}
private static class MyJavascriptInterface {
private MyActivity activity;
public MyJavascriptInterface(MyActivity activity) {
this.activity = activity;
}
// this annotation is required in Jelly Bean and later:
@JavascriptInterface
public void processReturnValue(int index, String value) {
activity.processJsReturnValue(index, value);
}
}
Grazie per il codice di cui sopra - l'ho adottato nel mio progetto Android. Tuttavia, vi è una trappola in esso, derivante dal cattivo design dell'API Java. La riga: jsReturnValueLock.wait (waitMs - (System.currentTimeMillis() - start)); Il valore dell'argomento della funzione wait() può talvolta accadere per valutare su 0. E questo significa "aspetta all'infinito" - ricevevo occasionalmente errori di "nessuna risposta". L'ho risolto testando per: se break (scaduto> = waitMS); e non chiamare di nuovo System.currentTimeMillis() di seguito, ma utilizzando il valore trascorso. Sarebbe meglio modificare e correggere il codice precedente. – gregko
Wow, grazie mille! Lo vedevo anch'io e non ho mai capito da dove venisse. – Keith
Ma se eseguo evalJS nel listener button.click, ecc. waitForJsReturnValue può causare evalJs() per riagganciare. Quindi webView.loadUrl() all'interno di handler.post() potrebbe non avere possibilità di esecuzione perché il listener button.click non è stato restituito. – victorwoo
Uguale Keith
ma la risposta più breve
webView.addJavascriptInterface(this, "android");
webView.loadUrl("javascript:android.onData(functionThatReturnsSomething)");
E implementare la funzione
@JavascriptInterface
public void onData(String value) {
//.. do something with the data
}
Non dimenticare di rimuovere il onData
da proguard
lista (Proguard se è stato attivato)
puoi approfondire la parte 'proguard'? – eugene
@eugene se non sai cosa sia, probabilmente non lo usi. In ogni caso è qualcosa che abilita il che rende il reverse engineering della tua app più difficile –
Grazie. So che ho proguard-project.txt nella radice del progetto ma non di più. Ti sto chiedendo perché la tua soluzione funziona ma ricevo SIGSEGV. Sto valutando 'document.getElementById (" my-div "). ScrollTop' per ottenere la posizione di scorrimento da' SwipeRefreshLayout :: canChildScrollUp() '. Sospetto che potrebbe essere dovuto al fatto che la chiamata venga chiamata troppe volte nel breve periodo. o "proguard" che sospetto perché non so cosa sia .. – eugene
La soluzione che @Felix Khazin suggerito opere, ma c'è un manca il punto chiave.
La chiamata javascript deve essere effettuata dopo aver caricato la pagina Web nello WebView
. Aggiungi questo WebViewClient
allo WebView
, insieme allo WebChromeClient
.
completa Esempio:
Su API 19+, il modo migliore per farlo è quello di chiamare evaluateJavascript sul WebView:
webView.evaluateJavascript("foo.bar()", new ValueCallback<String>() {
@Override public void onReceiveValue(String value) {
// value is the result returned by the Javascript as JSON
}
});
risposta correlati con maggiori dettagli: https://stackoverflow.com/a/20377857
- 1. come ottenere il valore di ritorno da una chiamata ajax?
- 2. Android WebView Javascript getSelection
- 3. webview android: come cambiare il testo del titolo di avviso javaScript nella webview di Android?
- 4. Ottenere valore restituito da JavaScript UIWebView
- 5. valore di ritorno calcolata da JavaScript FileReader evento onload
- 6. Android: problema con il debug di javascript in webview
- 7. Ottenere il valore di ritorno dalla stored procedure in ADO.NET
- 8. Come ottenere il valore casella di testo in JavaScript
- 9. Valore di ritorno da Thread
- 10. Ottenere un valore di ritorno da un metodoInfo.invoke
- 11. È possibile ottenere un valore di ritorno da multiprocessing.Process?
- 12. Android WebView Javascript abilitato
- 13. Come posso ottenere il valore da EditText in Android?
- 14. Come ottenere il valore di ritorno da matlab in script bash?
- 15. Ottenere il valore da un pulsante di opzione utilizzando javascript
- 16. Ottenere un valore di ritorno utilizzando il sottoprocesso
- 17. Android: Intercetta chiamata AJAX da WebView
- 18. Come ottenere il testo selezionato in WebView Android
- 19. Come ottenere il valore restituito da xcodebuild?
- 20. Ottenere valore di ritorno dopo SetTimeout
- 21. Come ottenere il valore hashtag e il valore di e commerciale di un URL in Javascript?
- 22. WebView Android JavaScript dalle risorse
- 23. Ottieni valore di ritorno da setTimeout
- 24. Valore di ritorno Uispy come "?"
- 25. Come posso ottenere il codice di ritorno da CustomAction?
- 26. Come ottenere il valore di visualizzazione di Select using javascript
- 27. JavaScript non funziona in Android WebView
- 28. Come ottenere il valore da Object, con valore di default
- 29. Ottenere valore restituito da JavaScript in C# controllo Webbrowser WPF
- 30. Come posso ottenere il secondo valore di ritorno da una funzione senza utilizzare variabili temporanee?
come posso farlo in situazioni come http: // StackOverflow.it/questions/5521191/return-a-value-from-javascript-function-in-android – vnshetty
Questo non aiuta se il tuo js non scrive in questo oggetto e non puoi toccare il js. –
@PacMani: utilizzare 'loadUrl (" javascript: ... ")' (livello API 1-18) o 'evaluateJavascript()' (livello API 19+) per valutare il proprio codice JavaScript nel contesto del Web attualmente caricato pagina. – CommonsWare