web-dev-qa-db-fra.com

Appelez Java la fonction de JavaScript sur Android WebView

Je souhaite passer un appel synchrone à un Java dans mon Android app.

J'utilise cette solution: https://stackoverflow.com/a/3338656

Mon Java:

final class MyWebChromeClient extends WebChromeClient {
        public boolean onJsAlert(WebView view, String url, String message, JsResult result) {
            Log.d("LogTag", message);
            result.confirm();
            return true;
        }
    }

Mon code JavaScript:

<html>
<script>
function Java_request(){
    alert('test');
}
</script>
<body>
<h2>Welcome</h2>
<div id="area"></div>
<form>
<input type="button" value="Java_call" onclick="Java_request()">
</form>
</body>
</html>

Quand je tape sur le Java_call, le bouton passe à l'état enfoncé. Je vois 'test' dans le journal de la console. Tout est normal jusqu'à ici.

Le problème est que le bouton ne revient jamais à son état normal. Il reste à l'état pressé. Peut-être que l'exécution de JavaScript est cassée ou quelque chose?

Pourquoi le bouton ne revient jamais à son état normal?

70
ozkolonur

Je ne pense pas que ce soit la meilleure solution pour que le javascript soit exécuté Java. Voir ici:

Si vous souhaitez exposer le code natif au code HTML pour qu'il soit appelable via javascript, procédez comme suit pour votre déclaration d'affichage Web:

JavaScriptInterface jsInterface = new JavaScriptInterface(this);
webView.getSettings().setJavaScriptEnabled(true);
webView.addJavascriptInterface(jsInterface, "JSInterface");

Déclarez la classe JavaScriptInterface:

public class JavaScriptInterface {
    private Activity activity;

    public JavaScriptInterface(Activity activity) {
        this.activity = activity;
    }

    @JavascriptInterface
    public void startVideo(String videoAddress){
        Intent intent = new Intent(Intent.ACTION_VIEW);
        intent.setDataAndType(Uri.parse(videoAddress), "video/3gpp"); 
        activity.startActivity(intent);
    }
}

Je déclare une fonction unique pour la lecture d'une vidéo, mais vous pouvez faire ce que vous voulez.

Enfin, vous appelez ceci dans le contenu WebView via un simple appel javascript:

<video width="320" height="240" controls="controls" poster='poster.gif'
       onclick="window.JSInterface.startVideo('file:///sdcard/test.3gp');" >
   Your browser does not support the video tag.
</video>

L'exemple est tiré d'une autre de mes réponses, à propos de la lecture de vidéos, mais devrait en expliquer suffisamment.

EDIT D'après le commentaire de @ CedricSoubrie: si la version cible de l'application est définie sur 17 ou supérieure, vous devez ajouter une annotation @JavascriptInterface au-dessus de chaque méthode que vous souhaitez exporter vers la vue Web.

98
Boris Strandjev

Les méthodes définies dans la classe "YourJavaScriptInterface", n'oubliez pas d'annoter chaque méthode que vous souhaitez exposer avec "@JavascriptInterface", sinon la méthode ne sera pas déclenchée.

Par exemple, le code ci-dessous provient de l'interface JavaScript de Google Cloud Print pour les appels provenant d'une page d'affichage Web:

        final class PrintDialogJavaScriptInterface {
        @JavascriptInterface
        public String toString() { return JS_INTERFACE; }

        @JavascriptInterface
        public String getType() {
            return cloudPrintIntent.getType();
        }

        @JavascriptInterface
        public String getTitle() {
            return cloudPrintIntent.getExtras().getString("title");
        }

        @JavascriptInterface
        public String getContent() {
            try {
                ContentResolver contentResolver = getActivity().getContentResolver();
                InputStream is = contentResolver.openInputStream(cloudPrintIntent.getData());
                ByteArrayOutputStream baos = new ByteArrayOutputStream();

                byte[] buffer = new byte[4096];
                int n = is.read(buffer);
                while (n >= 0) {
                    baos.write(buffer, 0, n);
                    n = is.read(buffer);
                }
                is.close();
                baos.flush();

                return Base64.encodeToString(baos.toByteArray(), Base64.DEFAULT);
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
            return "";
        }

        @JavascriptInterface
        public String getEncoding() {
            return CONTENT_TRANSFER_ENCODING;
        }

        @JavascriptInterface
        public void onPostMessage(String message) {
            if (message.startsWith(CLOSE_POST_MESSAGE_NAME)) {
                finish();
            }
        }
    }
1
tyolab

Votre fonction retourne 'true'. Cela rend la propriété 'onclick' de votre code HTML égale à true, donc le bouton reste 'cliqué'.

1
R. Maynard