Ich versuche, einige javascript
- Funktionen aufzurufen, die auf einer html
- Seite in einem Android webview
Ausgeführt werden. Ganz einfach, was der Code im Folgenden versucht: Rufen Sie in der App Android eine Funktion javascript
mit einer Testnachricht auf, die wiederum eine Funktion Java in der App aufruft Android App, die eine Testnachricht per Toast anzeigt.
Die Funktion javascript
sieht folgendermaßen aus:
function testEcho(message){
window.JSInterface.doEchoTest(message);
}
In WebView habe ich ohne Erfolg versucht, die javascript
folgendermaßen aufzurufen:
myWebView.loadUrl("javascript:testEcho(Hello World!)");
mWebView.loadUrl("javascript:(function () { " + "testEcho(Hello World!);" + "})()");
Ich habe javascript
für WebView
aktiviert
myWebView.getSettings().setJavaScriptEnabled(true);
// register class containing methods to be exposed to JavaScript
myWebView.addJavascriptInterface(myJSInterface, "JSInterface");
Und hier ist die Klasse Java
public class JSInterface{
private WebView mAppView;
public JSInterface (WebView appView) {
this.mAppView = appView;
}
public void doEchoTest(String echo){
Toast toast = Toast.makeText(mAppView.getContext(), echo, Toast.LENGTH_SHORT);
toast.show();
}
}
Ich habe viel Zeit damit verbracht, herumzugoogeln, um zu sehen, was ich falsch mache. Alle Beispiele, die ich gefunden habe, verwenden diesen Ansatz. Stimmt hier jemand etwas nicht?
Edit: Es werden mehrere andere externe javascript
- Dateien referenziert und in der html
verwendet. Könnten sie das Problem sein?
Ich fand heraus, was das Problem war: fehlende Anführungszeichen im Parameter testEcho (). So bekam ich den Aufruf zur Arbeit:
myWebView.loadUrl("javascript:testEcho('Hello World!')");
Verwenden Sie ab KitKat die Methode evaluationJavascript anstelle von loadUrl, um die unten aufgeführten Javascript-Funktionen aufzurufen
if (Android.os.Build.VERSION.SDK_INT >= Android.os.Build.VERSION_CODES.KitKat) {
webView.evaluateJavascript("enable();", null);
} else {
webView.loadUrl("javascript:enable();");
}
public void run(final String scriptSrc) {
webView.post(new Runnable() {
@Override
public void run() {
webView.loadUrl("javascript:" + scriptSrc);
}
});
}
Ich habe einen Nice-Wrapper zum Aufrufen von JavaScript-Methoden erstellt. Es zeigt auch JavaScript-Fehler im Protokoll:
private void callJavaScript(String methodName, Object...params){
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append("javascript:try{");
stringBuilder.append(methodName);
stringBuilder.append("(");
for (int i = 0; i < params.length; i++) {
Object param = params[i];
if(param instanceof String){
stringBuilder.append("'");
stringBuilder.append(param.toString().replace("'", "\\'"));
stringBuilder.append("'");
}
if(i < params.length - 1){
stringBuilder.append(",");
}
}
stringBuilder.append(")}catch(error){Android.onError(error.message);}");
webView.loadUrl(stringBuilder.toString());
}
Sie müssen dies auch hinzufügen:
private class WebViewInterface{
@JavascriptInterface
public void onError(String error){
throw new Error(error);
}
}
Und fügen Sie diese Schnittstelle zu Ihrer Webansicht hinzu:
webView.getSettings().setJavaScriptEnabled(true);
webView.addJavascriptInterface(new WebViewInterface(), "AndroidErrorReporter");
Ja, Sie haben den Syntaxfehler. Wenn Sie Ihre Javascript-Fehler und Druckanweisungen in Ihrem Logcat erhalten möchten, müssen Sie die Methode onConsoleMessage(ConsoleMessage cm)
in Ihrem WebChromeClient implementieren. Es gibt die kompletten Stack-Traces wie die Webkonsole (Inspect-Element). Hier ist die Methode.
public boolean onConsoleMessage(ConsoleMessage cm)
{
Log.d("Message", cm.message() + " -- From line "
+ cm.lineNumber() + " of "
+ cm.sourceId() );
return true;
}
Nach der Implementierung erhalten Sie Ihre Javascript-Fehler und Druckanweisungen (console.log
) auf Ihrem Logcat.
Änderung der Antwort von @Ilya_Gazman
private void callJavaScript(WebView view, String methodName, Object...params){
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append("javascript:try{");
stringBuilder.append(methodName);
stringBuilder.append("(");
String separator = "";
for (Object param : params) {
stringBuilder.append(separator);
separator = ",";
if(param instanceof String){
stringBuilder.append("'");
}
stringBuilder.append(param.toString().replace("'", "\\'"));
if(param instanceof String){
stringBuilder.append("'");
}
}
stringBuilder.append(")}catch(error){console.error(error.message);}");
final String call = stringBuilder.toString();
Log.i(TAG, "callJavaScript: call="+call);
view.loadUrl(call);
}
jS-Aufrufe werden korrekt erstellt, z.
callJavaScript(mBrowser, "alert", "abc", "def");
//javascript:try{alert('abc','def')}catch(error){console.error(error.message);}
callJavaScript(mBrowser, "alert", 1, true, "abc");
//javascript:try{alert(1,true,'abc')}catch(error){console.error(error.message);}
Beachten Sie, dass Objekte nicht korrekt übergeben werden - Sie können sie jedoch serialisieren, bevor Sie sie als Argument übergeben.
Außerdem habe ich geändert, wohin der Fehler geht. Ich habe ihn in das Konsolenprotokoll umgeleitet, das abgehört werden kann von:
webView.setWebChromeClient(new CustomWebChromeClient());
und Client
class CustomWebChromeClient extends WebChromeClient {
private static final String TAG = "CustomWebChromeClient";
@Override
public boolean onConsoleMessage(ConsoleMessage cm) {
Log.d(TAG, String.format("%s @ %d: %s", cm.message(),
cm.lineNumber(), cm.sourceId()));
return true;
}
}