Виклик функції Java із JavaScript через Android WebView


75

Я хочу здійснити синхронний дзвінок на якийсь код Java у своєму додатку Android.

Я використовую це рішення: https://stackoverflow.com/a/3338656

Мій код 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;
        }
    }

Мій код 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>

Коли я натискаю на java_callкнопку, кнопка переходить у натиснутий стан. Я бачу 'test'в журналі консолі. До тут все нормально.

Проблема в тому, що кнопка ніколи не повертається до свого нормального стану. Він залишається в пресованому стані. Можливо, виконання JavaScript порушено чи щось інше?

Чому кнопка ніколи не повертається до свого нормального стану?

Відповіді:


108

Я не думаю, що це найкраще рішення, щоб змусити javascript виконувати код Java. Дивіться тут:

Якщо ви хочете виставити власний код у HTML, щоб його можна було викликати через javascript, виконайте наступне навколо декларації веб-перегляду:

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

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

Я заявляю про одну функцію для відтворення відео, але ви можете робити все, що завгодно.

Нарешті, ви викликаєте це у WebViewвмісті за допомогою простого виклику 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>

Приклад взятий з іншої моєї відповіді щодо відтворення відео, але він повинен бути достатньо поясненим.

EDIT Відповідно до коментаря @ CedricSoubrie: якщо для цільової версії програми встановлено значення 17 або вище, вам потрібно додати анотацію @JavascriptInterfaceнад кожним методом, який ви хочете експортувати до веб-перегляду.


1
дякую за інформацію, я побачив це рішення. оскільки у 2.3.X є помилка для цього рішення, я не хочу його використовувати. обхідний шлях був дуже приголомшливим.
ozkolonur

@ozkolonur Я використовував це з усіма версіями Android 2.2+, ніколи не бачив помилок. Чи можете ви поділитися, що це таке. Посилання також дуже вітається.
Борис Странджев

Я вважаю, що "playVideo" та "startVideo" повинні бути однаковими?
Маартен

2
@Maarten: насправді це була не єдина помилка у моїй відповіді. Зараз я це виправив.
Борис Странджев

2
@BorisStrandjev Надзвичайно чітка відповідь! Зауважте, що ви повинні додати анотацію "@JavascriptInterface" до будь-якого методу, який ви хочете отримати у своєму JavaScript для версії 17 або новішої. Джерело: developer.android.com/guide/webapps/webview.html
CedricSoubrie

2

Ваша функція повертає значення "true". Це робить властивість "onclick" вашого HTML-коду рівною true, отже кнопка залишається "натиснутою".


2

Методи, визначені в класі " YourJavaScriptInterface ", не забувайте коментувати кожен метод, який ви хочете виставити, за допомогою "@JavascriptInterface", інакше метод не буде спрацьовано.

Наприклад, наведений нижче код з інтерфейсу JavaScript Google Cloud Print для дзвінків зі сторінки веб-перегляду:

        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();
            }
        }
    }
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.