Rufen Sie die Java-Funktion von JavaScript über Android WebView auf

74

Ich möchte einen Java-Code in meiner Android-App synchron aufrufen.

Ich verwende diese Lösung: https://stackoverflow.com/a/3338656

Mein Java-Code:

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

Mein JavaScript-Code:

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

Wenn ich auf die java_callSchaltfläche tippe, wechselt die Schaltfläche in den gedrückten Zustand. Ich kann 'test'im Konsolenprotokoll sehen. Bis hier ist alles normal.

Das Problem ist, dass die Taste nie wieder in ihren normalen Zustand zurückkehrt. Es bleibt im gedrückten Zustand. Vielleicht ist die JavaScript-Ausführung kaputt oder so?

Warum kehrt die Schaltfläche nie in ihren normalen Zustand zurück?

Ozkolonur
quelle

Antworten:

107

Ich denke nicht, dass dies die beste Lösung ist, um das Javascript dazu zu bringen, Java-Code auszuführen. Siehe hier:

Wenn Sie nativen Code für HTML verfügbar machen möchten, damit er über Javascript aufgerufen werden kann, gehen Sie im Zusammenhang mit Ihrer Webansichtsdeklaration wie folgt vor:

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

Deklarieren Sie die Klasse 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);
    }
}

Ich erkläre eine einzelne Funktion zum Abspielen eines Videos, aber Sie können tun, was Sie wollen.

Schließlich rufen Sie dies im WebViewInhalt über einen einfachen Javascript-Aufruf auf:

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

Das Beispiel stammt aus einer anderen Antwort von mir, über das Abspielen von Videos, sollte aber genug erklären.

EDIT Wie pro @ CedricSoubrie Kommentar: wenn die Zielversion der Anwendung auf 17 oder höher eingestellt Sie müssen Anmerkung hinzuzufügen @JavascriptInterfaceüber jede Methode , die Sie den Export in der Web - Ansicht mögen.

Boris Strandjev
quelle
1
danke für info, ich habe diese lösung gesehen. Da es in 2.3.X einen Fehler für diese Lösung gibt, möchte ich ihn nicht verwenden. Problemumgehung war sehr großartig.
Ozkolonur
@ozkolonur Ich habe dies mit allen Versionen von Android 2.2+ verwendet, habe nie einen Fehler gesehen. Können Sie uns mitteilen, was es ist? Ein Link ist auch sehr willkommen.
Boris Strandjev
Ich nehme an, 'playVideo' und 'startVideo' sollten gleich sein?
Maarten
2
@ Maarten: Eigentlich war dies nicht der einzige Fehler in meiner Antwort. Ich habe es jetzt korrigiert.
Boris Strandjev
2
@ BorisStrandjev Extrem klare Antwort! Beachten Sie, dass Sie die Annotation "@JavascriptInterface" zu jeder Methode hinzufügen müssen, die in Ihrem JavaScript für Version 17 oder höher verfügbar sein soll. Quelle: developer.android.com/guide/webapps/webview.html
CedricSoubrie
2

Ihre Funktion gibt 'true' zurück. Dadurch ist die Eigenschaft "onclick" Ihres HTML-Codes gleich "true", sodass die Schaltfläche "angeklickt" bleibt.

R. Maynard
quelle
2

Bei den in der Klasse " YourJavaScriptInterface " definierten Methoden vergessen Sie nicht, jede Methode, die Sie verfügbar machen möchten, mit "@JavascriptInterface" zu versehen, da sonst die Methode nicht ausgelöst wird.

Der folgende Code stammt beispielsweise aus der Google Cloud Print JavaScript-Oberfläche für Anrufe von einer Webview-Seite:

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