web-dev-qa-db-fra.com

Android Appel de fonctions JavaScript dans WebView

J'essaie d'appeler certaines fonctions javascript situées dans une page html à l'intérieur d'un Android webview. Ce que le code essaie de faire ci-dessous est très simple: à partir de l'application Android, appelez une fonction javascript avec un message de test, qui appelle à son tour une fonction Java dans la _.Android application qui affiche le message de test via un toast.

La fonction javascript ressemble à ceci:

function testEcho(message){
     window.JSInterface.doEchoTest(message);
}

Depuis la WebView, j'ai essayé d'appeler la javascript de la manière suivante, sans succès:

myWebView.loadUrl("javascript:testEcho(Hello World!)");
mWebView.loadUrl("javascript:(function () { " + "testEcho(Hello World!);" + "})()");

J'ai activé javascript sur le WebView

myWebView.getSettings().setJavaScriptEnabled(true);
// register class containing methods to be exposed to JavaScript
myWebView.addJavascriptInterface(myJSInterface, "JSInterface"); 

Et voici la Java Class

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();
    }
}

J'ai passé beaucoup de temps à faire des recherches sur Google pour voir ce que je faisais mal. Tous les exemples que j'ai trouvés utilisent cette approche. Est-ce que quelqu'un voit quelque chose de mal ici?

Edit: Il y a plusieurs autres fichiers javascript externes référencés et utilisés dans le fichier html, pourraient-ils être le problème?

226
user163757

J'ai compris quel était le problème: les guillemets manquants dans le paramètre testEcho (). Voici comment j'ai eu l'appel au travail:

myWebView.loadUrl("javascript:testEcho('Hello World!')");
182
user163757

À partir de KitKat, utilisez la méthode assessmentJavascript à la place de loadUrl pour appeler les fonctions javascript décrites ci-dessous.

    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

J'ai créé un wrapper Nice pour appeler des méthodes JavaScript. il affiche également des erreurs JavaScript dans le journal:

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());
}

Vous devez aussi ajouter ceci:

private class WebViewInterface{

    @JavascriptInterface
    public void onError(String error){
        throw new Error(error);
    }
}

Et ajoutez cette interface à votre webview:

webView.getSettings().setJavaScriptEnabled(true);
webView.addJavascriptInterface(new WebViewInterface(), "AndroidErrorReporter");
22
Ilya Gazman

Oui, vous avez l'erreur de syntaxe. Si vous souhaitez obtenir vos erreurs Javascript et vos instructions d'impression dans votre logcat, vous devez implémenter la méthode onConsoleMessage(ConsoleMessage cm) dans votre WebChromeClient. Il donne les traces complètes de la pile comme la console Web (élément Inspect). Voici la méthode.

public boolean onConsoleMessage(ConsoleMessage cm) 
    {
        Log.d("Message", cm.message() + " -- From line "
                             + cm.lineNumber() + " of "
                             + cm.sourceId() );
        return true;
    }

Après la mise en œuvre, vos erreurs Javascript et vos déclarations d’impression (console.log) seront consignées sur votre logcat.

18
Dinesh

Modification de la réponse de @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);
    }

créera correctement les appels JS, par exemple.

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

Notez que les objets ne seront pas passés correctement, mais vous pouvez les sérialiser avant de les passer en argument.

De plus, j’ai modifié l’emplacement de l’erreur, je l’ai redirigé vers le journal de la console qui peut être écouté par:

    webView.setWebChromeClient(new CustomWebChromeClient());

et 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;
    }
}
13