Wywołanie funkcji Java z JavaScript przez Android WebView

Chcę wykonać synchroniczne połączenie z kodem Javy w mojej aplikacji na Androida.

Używam tego rozwiązania: https://stackoverflow.com/a/3338656

Mój kod Javy:

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

Mój kod 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>

Kiedy dotknę java_call przycisk przechodzi do stanu wciśniętego. Widzę 'test' w dzienniku konsoli. Do tej pory wszystko jest normalne.

Problem w tym, że przycisk nigdy nie wraca do normalnego stanu. Pozostaje w stanie wciśniętym. Maybe the Wykonanie JavaScript jest zepsute czy coś?

Dlaczego przycisk nigdy nie wraca do normalnego stanu?

Author: Community, 2012-04-30

3 answers

Myślę, że nie jest to najlepsze rozwiązanie, aby zmusić javascript do wykonania kodu java. Zobacz tutaj:

Jeśli chcesz udostępnić kod macierzysty HTML do wywołania za pomocą javascript, wykonaj następujące czynności wokół deklaracji widoku sieci:

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

{JavaScriptInterface}

public class JavaScriptInterface {
    private Activity activity;

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

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

Deklaruję jedną funkcję do odtwarzania wideo, ale możesz robić, co chcesz.

W końcu wywołujesz to w treści WebView za pomocą prostego wywołania 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>

The przykład pochodzi z innej mojej odpowiedzi na temat odtwarzania filmów, ale powinien być wystarczająco wyjaśniony.

Edytuj zgodnie z komentarzem @ CedricSoubrie: jeśli docelowa wersja aplikacji jest ustawiona na 17 lub wyższą, musisz dodać adnotację @JavascriptInterface nad każdą metodą, którą chcesz wyeksportować do widoku sieci web.

 84
Author: Boris Strandjev,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-03-19 13:54:58

Funkcja zwraca 'true'. To sprawia, że właściwość "onclick" Twojego kodu HTML jest równa true, stąd przycisk pozostaje "kliknięty".'

 1
Author: R. Maynard,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-06-30 16:12:54

Metody zdefiniowane w klasie " YourJavaScriptInterface", nie zapomnij dodać adnotacji do każdej metody, którą chcesz udostępnić za pomocą "@ JavascriptInterface", w przeciwnym razie metoda nie zostanie uruchomiona.

Na przykład poniższy kod pochodzi z interfejsu JavaScript Google Cloud Print dla połączeń ze strony webview:

        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();
            }
        }
    }
 0
Author: tyolab,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-03-12 06:11:01