Fungsi JavaScript Memanggil Android di WebView

249

Saya mencoba memanggil beberapa javascriptfungsi yang duduk di htmlhalaman yang berjalan di dalam sebuah android webview. Cukup sederhana apa yang coba dilakukan oleh kode di bawah ini - dari aplikasi android, panggil javascriptfungsi dengan pesan tes, yang intinya memanggil fungsi java kembali di aplikasi android yang menampilkan pesan pengujian melalui roti panggang.

The javascriptFungsi terlihat seperti:

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

Dari WebView, saya telah mencoba memanggil javascriptcara-cara berikut tanpa hasil:

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

Saya mengaktifkan javascriptdiWebView

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

Dan inilah JavaKelas

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

Saya telah menghabiskan banyak waktu untuk melihat-lihat kesalahan saya. Semua contoh yang saya temukan menggunakan pendekatan ini. Adakah yang melihat sesuatu yang salah di sini?

Sunting: Ada beberapa javascriptfile eksternal lain yang direferensikan & digunakan dalam html, mungkinkah itu masalahnya?

pengguna163757
sumber
13
Kode yang Anda coba gunakan salahkan kutipan di sisi javascript.
Paul de Vrieze
2
Harap dicatat bahwa sejak Android 4.2 Anda harus menggunakan @JavascriptInterfacedekorator pada metode Java yang ingin Anda buat tersedia untuk WebView melalui Antarmuka JavaScript.
Fred
1
Dari kode myWebView.loadUrl("javascript:testEcho('Hello World!')");saya mengerti bahwa Anda telah melampirkan file html ke tampilan web itu. Bisakah Anda memberi tahu saya bagaimana Anda melakukannya?
Tony_craft

Jawaban:

195

Saya menemukan apa masalahnya: tidak ada tanda kutip di parameter testEcho (). Beginilah cara saya mendapat panggilan untuk bekerja:

myWebView.loadUrl("javascript:testEcho('Hello World!')");
pengguna163757
sumber
silakan lihat di tautan ini stackoverflow.com/questions/9079374/…
kamal_tech_view
Ini bagus, tetapi bagaimana Anda meneruskan objek Java ke fungsi JavaScript sebagai argumen?
Kovács Imre
1
@ KovácsImre String.Format ("javascript: testEcho ('% d', '% d', '% d')", 1, 2, 3); Saya kira
user457015
Terima kasih, saya juga sudah tahu.
Kovács Imre
1
Dimulai dengan KitKat terdapat metode evaluJavascript, periksa stackoverflow.com/a/32163655/3063226
Heitor
117

Dari kitkat dan seterusnya, gunakan metode evaluasiJavascript, bukan loadUrl untuk memanggil fungsi javascript seperti di bawah ini

    if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT) {
        webView.evaluateJavascript("enable();", null);
    } else {
        webView.loadUrl("javascript:enable();");
    }
Prasad
sumber
2
mengapa menggunakan evaluJavascript () alih-alih loadUrl ()?
Kamran Bigdely
2
@kami loadUrl () akan memuat ulang halaman dan memanggil onPageFinished () lagi
Zach
1
@ Zak, masih masalah pra-KitKat, kan?
Vsevolod Ganin
2
@kami Menambah jawaban Zach, evaluJavascript (), akan menjalankan JavaScript secara tidak sinkron. Jadi kita dapat menghindari memblokir utas UI menggunakan evaluJavascript ().
Prasad
loadUrljuga menyebabkan keyboard perangkat lunak muncul ketika saya mencoba mengisi nilai di bidang input.
Yosua
34
public void run(final String scriptSrc) { 
        webView.post(new Runnable() {
            @Override
            public void run() { 
                webView.loadUrl("javascript:" + scriptSrc); 
            }
        }); 
    }
pengguna340994
sumber
dan jika ini tidak berhasil, lakukan Thread baru (Runnaable baru () {.. <seperti di atas> ..}). start ()
Radu Simionescu
26

Saya membuat pembungkus yang bagus untuk memanggil metode JavaScript; itu juga menunjukkan kesalahan JavaScript di log:

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

Anda perlu menambahkan ini juga:

private class WebViewInterface{

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

Dan tambahkan antarmuka ini ke tampilan web Anda:

webView.getSettings().setJavaScriptEnabled(true);
webView.addJavascriptInterface(new WebViewInterface(), "AndroidErrorReporter");
Ilya Gazman
sumber
Fungsi ini, betapapun bagusnya sebuah ide, memiliki implementasi yang salah. Panggilan ini: final Object a = new Object(); callJavaScript(mBrowser, "alert", 1, true, "abc", a);akan menyerah SyntaxErrordengan Unexpected tokenyang tidak mengejutkan ketika Anda akan melihat js dihasilkan hubungi:javascript:try{alert(,,'abc',,)}catch(error){console.error(error.message);}
Lukasz 'Severiaan' Grela
Bahkan panggilan sederhana callJavaScript(mBrowser, "alert", "abc", "def");menghasilkan kesalahan karena selalu ada koma nakal di akhir. -1 dari saya.
Lukasz 'Severiaan' Grela
1
@ Lukasz'Severiaan'Grela tnx, saya memperbaikinya. PS Lain kali jangan malas kamu bisa memperbaikinya sendiri ...;)
Ilya Gazman
16
Untuk referensi di masa mendatang: Mari tetap positif. Menunjukkan kesalahan dalam kode tidak malas. Itu masih umpan balik yang bermanfaat.
DW
Saya kira ini tidak akan berfungsi jika salah satu parameter memiliki 'karakter di dalamnya? Contoh:callJavascript(mBrowser, "can't do it");
Kostanos
18

Ya, Anda memiliki kesalahan sintaksis. Jika Anda ingin mendapatkan kesalahan Javascript dan pernyataan pencetakan di logcat Anda, Anda harus menerapkan onConsoleMessage(ConsoleMessage cm)metode ini di WebChromeClient Anda. Ini memberikan jejak tumpukan lengkap seperti konsol Web (elemen Inspect). Inilah metodenya.

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

Setelah implementasi, Anda akan mendapatkan kesalahan Javascript dan pernyataan cetak ( console.log) di logcat Anda.

Dinesh
sumber
2
Saya percaya ada di WebChromeClient dan bukan WebViewClient.
Michael Levy
Ya, Anda benar @MichaelLevy. Terima kasih telah menunjuk saya untuk kesalahan itu. Sekarang saya sudah mengedit jawaban saya.
Dinesh
1
Terima kasih, jawaban Anda adalah apa yang saya butuhkan. Saya juga menyarankan orang untuk menimpaJsAlert () di WebChromeClient. Kombinasi pencatatan dan peringatan javascript dapat sangat membantu saat men-debug Javascript yang dihosting di tampilan web.
Michael Levy
13

Modifikasi jawaban @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);
    }

akan dengan benar membuat panggilan JS misalnya

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

Perhatikan bahwa objek tidak akan diteruskan dengan benar - tetapi Anda dapat membuat cerita bersambung sebelum diteruskan sebagai argumen.

Saya juga telah mengubah arah kesalahan, saya mengalihkannya ke log konsol yang dapat didengarkan oleh:

    webView.setWebChromeClient(new CustomWebChromeClient());

dan klien

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;
    }
}
Lukasz 'Severiaan' Grela
sumber
Terima kasih. Apakah metode ini akan keluar 'karakter dalam variabel apa pun? Dengan kata lain, apakah akan bekerja dengan callJavascript(mBrowser, "can't do it");:?
Kostanos
1
Baru saja mengedit jawaban dan menambahkan jalan keluar ke 'karakter
Kostanos
2

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <WebView
        android:id="@+id/webView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

</RelativeLayout>

MainActivity.java


import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.webkit.WebView;
import android.webkit.WebViewClient;

import com.bluapp.androidview.R;

public class WebViewActivity3 extends AppCompatActivity {
    private WebView webView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_web_view3);
        webView = (WebView) findViewById(R.id.webView);
        webView.setWebViewClient(new WebViewClient());
        webView.getSettings().setJavaScriptEnabled(true);
        webView.loadUrl("file:///android_asset/webview1.html");


        webView.setWebViewClient(new WebViewClient(){
            public void onPageFinished(WebView view, String weburl){
                webView.loadUrl("javascript:testEcho('Javascript function in webview')");
            }
        });
    }
}

file aset

<!DOCTYPE html PUBLIC "-//WAPFORUM//DTD XHTML Mobile 1.0//EN" "http://www.wapforum.org/DTD/xhtml-mobile10.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><title>WebView1</title>
<meta forua="true" http-equiv="Cache-Control" content="max-age=0"/>
</head>

<body style="background-color:#212121">
<script type="text/javascript">
function testEcho(p1){
document.write(p1);
}
</script>
</body>

</html>
dariush
sumber