web-dev-qa-db-ja.com

WebViewでのAndroid呼び出しJavaScript関数

私はAndroid webview内で実行されているjavascriptページに座っているいくつかのhtml関数を呼び出そうとしています。コードが次に試みることは非常に簡単です - Androidアプリから、テストメッセージでjavascript関数を呼び出します。この関数はinturnを使ってトースト経由でテストメッセージを表示するAndroidアプリにJava関数を呼び出します。

javascript関数は次のようになります。

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

WebViewから、私はjavascriptを以下の方法でうまく動かないように呼び出そうとしました。

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

javascriptWebViewを有効にしました

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

そしてJavaクラス

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

私は自分が間違っているかもしれないことを見るためにグーグルを回って多くの時間を費やしました。私が見つけたすべての例はこのアプローチを使います。誰かがここで何か悪いことを見ますか?

編集:javascriptで参照され使用されている他の外部htmlファイルがいくつかありますが、それらが問題になる可能性はありますか?

220
user163757

私は問題が何であるかを把握しました:testEcho()パラメータに引用符がありません。これは私が働くように電話をかけた方法です:

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

KitKat以降では、loadUrlではなくevaluateJavascriptメソッドを使用して、以下のようなJavaScript関数を呼び出します。

    if (Android.os.Build.VERSION.SDK_INT >= Android.os.Build.VERSION_CODES.KitKat) {
        webView.evaluateJavascript("enable();", null);
    } else {
        webView.loadUrl("javascript:enable();");
    }
99
Prasad
public void run(final String scriptSrc) { 
        webView.post(new Runnable() {
            @Override
            public void run() { 
                webView.loadUrl("javascript:" + scriptSrc); 
            }
        }); 
    }
32
user340994

JavaScriptメソッドを呼び出すためのNiceラッパーを作成しました。また、ログにJavaScriptエラーが表示されます。

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

これも追加する必要があります。

private class WebViewInterface{

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

そしてこのインターフェースをあなたのWebビューに追加してください。

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

はい、構文エラーがあります。あなたのJavascriptエラーとあなたのlogcatの印刷ステートメントを取得したい場合は、あなたのWebChromeClientでonConsoleMessage(ConsoleMessage cm)メソッドを実装する必要があります。 Webコンソール(Inspect要素)のような完全なスタックトレースを表示します。これがその方法です。

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

実装後、Javascriptエラーとprintステートメント(console.log)がlogcatに表示されます。

17
Dinesh

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

正しくJS呼び出しを作成します。

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

オブジェクトは正しく渡されないことに注意してください - しかし、引数として渡す前にそれらを直列化することができます。

また、エラーが発生する場所を変更し、コンソールログに転送しました。

    webView.setWebChromeClient(new CustomWebChromeClient());

とクライアント

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