web-dev-qa-db-de.com

Android Aufruf von JavaScript-Funktionen in WebView

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?

226
user163757

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!')");
182
user163757

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();");
    }
105
Prasad
public void run(final String scriptSrc) { 
        webView.post(new Runnable() {
            @Override
            public void run() { 
                webView.loadUrl("javascript:" + scriptSrc); 
            }
        }); 
    }
33
user340994

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");
22
Ilya Gazman

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.

18
Dinesh

Ä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;
    }
}