WebView'da Android Calling JavaScript işlevleri


249

İçinde çalışan javascriptbir htmlsayfada oturan bazı işlevleri çağırmaya çalışıyorum android webview. Kodun aşağıda yapmaya çalıştığı oldukça basit - android uygulamasından, javascripttest mesajıyla bir fonksiyonu çağırın , bu da tost yoluyla test mesajını gösteren android uygulamasında bir java fonksiyonunu geri çağırır.

javascriptFonksiyon görünüyor gibi:

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

WebView, ben javascriptşanssız aşağıdaki yolları aramayı denedim :

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

Ben etkinleştirmek did javascriptüzerindeWebView

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

Ve JavaSınıfı Heres

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

Neler yanlış yaptığımı görmek için çok zaman harcadım. Bulduğum tüm örnekler bu yaklaşımı kullanır. Burada yanlış bir şey gören var mı?

Düzenleme:javascript başvurulan ve kullanılan birkaç dış dosyalar vardır, htmlonlar sorun olabilir mi?


13
Kullanmaya çalıştığınız kod, javascript tarafında tırnak işaretleri eksik.
Paul de Vrieze

2
Android 4.2'den bu yana, @JavascriptInterfacedekoratörü JavaScript Arayüzü aracılığıyla WebView için kullanılabilir hale getirmek istediğiniz Java yöntemlerinde kullanmanız gerektiğini lütfen unutmayın .
Fred

1
Kodundan myWebView.loadUrl("javascript:testEcho('Hello World!')");sizin zaten bunu Web görünümündeki html dosyasına ekledikten anlıyoruz. Bana bunu nasıl yaptığını söyler misin?
Tony_craft

Yanıtlar:


195

Sorunun ne olduğunu anladım: testEcho () parametresinde tırnak işaretleri eksik. İşte bu şekilde çalışmak için çağrı aldım:

myWebView.loadUrl("javascript:testEcho('Hello World!')");

lütfen bu bağlantıya bir göz atın stackoverflow.com/questions/9079374/…
kamal_tech_view

Güzel, ama bir Java nesnesini argüman olarak bir JavaScript işlevine nasıl iletirsiniz?
Kovács Imre

1
@ KovácsImre String.Format ("javascript: testEcho ('% d', '% d', '% d')", 1, 2, 3); Sanırım
user457015

Teşekkürler, bu arada da öğrendim.
Kovács Imre

1
KitKat ile başlayarak evaluJavascript yöntemi vardır, stackoverflow.com/a/32163655/3063226
Heitor

117

Kitkat'tan itibaren javascript işlevlerini aşağıdaki gibi çağırmak için loadUrl yerine evaluJavascript yöntemini kullanın

    if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT) {
        webView.evaluateJavascript("enable();", null);
    } else {
        webView.loadUrl("javascript:enable();");
    }

2
loadUrl () yerine evaluJavascript () nasıl kullanılır?
Kamran Bigdely

2
@kami loadUrl () sayfayı yeniden yükleyecek ve onPageFinished () öğesini tekrar arayacak
Zach

1
@Zach Hala KitKat öncesi bir sorun, değil mi?
Vsevolod Ganin

2
@kami Zach yanıtına ekleme, evaluJavascript (), JavaScript'i eşzamansız olarak çalıştırır. Bu nedenle evaluJavascript () kullanarak UI iş parçacığını engellemekten kaçınabiliriz.
Prasad

loadUrlAyrıca, bir giriş alanındaki değeri doldurmaya çalıştığımda yazılım klavyesinin görünmesine neden oldu.
Joshua

34
public void run(final String scriptSrc) { 
        webView.post(new Runnable() {
            @Override
            public void run() { 
                webView.loadUrl("javascript:" + scriptSrc); 
            }
        }); 
    }

ve bu işe yaramazsa, yeni Konu (yeni Runnaable () {.. <yukarıdaki gibi> ..}). start ()
Radu Simionescu

26

JavaScript yöntemlerini çağırmak için güzel bir sarmalayıcı oluşturdum; ayrıca günlükte JavaScript hataları gösterir:

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

Bunu da eklemeniz gerekir:

private class WebViewInterface{

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

Ve bu arayüzü web görünümünüze ekleyin:

webView.getSettings().setJavaScriptEnabled(true);
webView.addJavascriptInterface(new WebViewInterface(), "AndroidErrorReporter");

Bu işlev, ne kadar iyi bir fikir olsa da, yanlış uygulamalara sahiptir. Bu çağrı: final Object a = new Object(); callJavaScript(mBrowser, "alert", 1, true, "abc", a);boyun eğer SyntaxErrorile Unexpected tokenhangi oluşturulan js bakacağız zaman şaşırtıcı değildir diyoruz:javascript:try{alert(,,'abc',,)}catch(error){console.error(error.message);}
Lukasz 'Severiaan' Grela'da

callJavaScript(mBrowser, "alert", "abc", "def");Sonunda her zaman hileli virgül olduğu için basit çağrı bile hata üretir. Benden -1.
Lukasz 'Severiaan' Grela

1
@ Lukasz'Severiaan'Grela tnx, bunu düzelttim. PS Bir dahaki sefere tembel olmayın; kendiniz düzeltebilirsiniz ...;)
Ilya Gazman

16
İleride başvurmak için: Olumlu kalalım. Kodda bir hata olduğunu belirtmek tembel değildir. Hala yararlı bir geri bildirim.
DW

Herhangi bir parametre 'karakteri varsa bu işe yaramaz sanırım? Örnek:callJavascript(mBrowser, "can't do it");
Kostanos

18

Evet sözdizimi hatası var. Javascript hatalarınızı ve baskı ifadelerinizi onConsoleMessage(ConsoleMessage cm)logcat'inize almak istiyorsanız, yöntemi WebChromeClient'inize uygulamalısınız. Web konsolu (Inspect öğesi) gibi tüm yığın izlerini verir. İşte yöntem.

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

Uygulamadan sonra Javascript hatalarınızı ve console.loglogcat'ınızda print ifadelerini ( ) alacaksınız .


2
Ben WebChromeClient ve WebViewClient üzerinde olduğuna inanıyorum.
Michael Levy

Evet haklısın @MichaelLevy. Beni bu hata için gösterdiğin için teşekkürler. Şimdi cevabımı düzenledim.
Dinesh

1
Teşekkürler, cevabın tam ihtiyacım olan şeydi. Ayrıca insanların WebChromeClient onJsAlert () geçersiz kılma öneririz. Javascript günlüğü ve uyarılarının kombinasyonu, web görünümünde barındırılan Javascript hata ayıklaması sırasında gerçekten yardımcı olabilir.
Michael Levy

13

@Ilya_Gazman cevabının değiştirilmesi

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

JS çağrılarını doğru bir şekilde oluşturur;

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

Nesnelerin doğru bir şekilde geçirilmeyeceğini unutmayın - ancak bağımsız değişken olarak geçmeden önce bunları serileştirebilirsiniz.

Ayrıca hatanın nereye gittiğini değiştirdim, onu dinleyebileceğiniz konsol günlüğüne yönlendirdim:

    webView.setWebChromeClient(new CustomWebChromeClient());

ve müşteri

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

Teşekkürler. Bu yöntem herhangi bir değişkenin içindeki karakterden kaçacak mı? Başka bir deyişle, çalışır: callJavascript(mBrowser, "can't do it");?
Kostanos

1
Cevabı yeni düzenledim ve kaçış karakterine eklendi
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')");
            }
        });
    }
}

varlık dosyası

<!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>
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.