AndroidはWebViewでJavaScript関数を呼び出す


249

内で実行さjavascriptれているhtmlページにあるいくつかの関数を呼び出そうとしていますandroid webview。コードが以下で実行しようとすることはかなり簡単ですjavascript。Android アプリから、テストメッセージで関数を呼び出します。これにより、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!);" + "})()");

私は有効にしjavascriptましたWebView

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、それらが問題になる可能性はありますか?


13
使用しようとするコードは、JavaScript側で引用符をミスします。
Paul de Vrieze、2011年

2
Android 4.2以降で@JavascriptInterfaceは、JavaScriptインターフェースを介してWebViewで使用できるようにするJavaメソッドでデコレーターを使用する必要があることに注意してください。
フレッド

1
コードから、myWebView.loadUrl("javascript:testEcho('Hello World!')");HTMLファイルをそのWebビューに既に添付していることがわかります。どうやってそれをやったの?
Tony_craft 2014年

回答:


195

私は問題が何であるかを理解しました:testEcho()パラメータに引用符がありません。これは私が仕事をする方法を得た方法です:

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

これらのリンクでご覧下さいstackoverflow.com/questions/9079374/...
kamal_tech_view

すばらしいですが、Javaオブジェクトを引数としてJavaScript関数に渡すにはどうすればよいでしょうか。
コバチイムレ

1
@KovácsImreString.Format( "javascript:testEcho( '%d'、 '%d'、 '%d')"、1、2、3); 私は推測
user457015

おかげで、私もその間に知りました。
コバチイムレ

1
KitKatから、evaluateJavascriptメソッドがあります。stackoverflow.com
a / 32163655/3063226を

117

キットカット以降、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();");
    }

2
loadUrl()の代わりにevaluateJavascript()を使用する理由
Kamran Bigdely

2
@kami loadUrl()はページをリロードし、再びonPageFinished()を呼び出します
Zach

1
@Zachそれでもpre-KitKatの問題ですよね。
Vsevolod Ganin 16

2
@kami Zachの回答、evaluateJavascript()に追加すると、JavaScriptが非同期で実行されます。したがって、evaluateJavascript()を使用してUIスレッドをブロックすることを回避できます。
Prasad

loadUrlまた、入力フィールドに値を入力しようとすると、ソフトウェアキーボードが表示されました。
ジョシュア

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

これが機能しない場合は、新しいThread(new Runnaable(){.. <like above> ..})。start()を実行してください
Radu Simionescu

26

JavaScriptメソッドを呼び出すための素晴らしいラッパーを作成しました。また、ログに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);
    }
}

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

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

この関数は、アイデアとしては優れていますが、実装が間違っています。このコール:final Object a = new Object(); callJavaScript(mBrowser, "alert", 1, true, "abc", a);に生じるであろうSyntaxErrorUnexpected tokenされますが、生成されたjsファイルを見てみましょうするときは驚くべきことではないの呼び出し:javascript:try{alert(,,'abc',,)}catch(error){console.error(error.message);}
ルカシュ「Severiaan」Grela

callJavaScript(mBrowser, "alert", "abc", "def");末尾に常に不正なコンマがあるため、単純な呼び出しでもエラーが発生します。私から-1。
Lukasz 'Severiaan' Grela

1
@ Lukasz'Severiaan'Grela tnx、私はそれを修正しました。PS次回は怠惰にしないでください、自分で修正できます...;)
Ilya Gazman

16
将来の参考のために:ポジティブでいよう。コードのエラーを指摘するのは面倒ではありません。それはまだ有用なフィードバックです。
DW

パラメータのいずれかに '文字が含まれている場合、これは機能しないと思いますか?例:callJavascript(mBrowser, "can't do it");
コスタノス

18

はい、構文エラーがあります。logcatでJavascriptエラーと印刷ステートメントを取得する場合は、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;
    }

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


2
これはWebViewClientではなくWebChromeClientにあると思います。
マイケルレビー

はい、あなたは正しい@MichaelLevyです。その間違いを指摘してくれてありがとう。今、私は私の答えを編集しました。
ディネッシュ2013

1
ありがとう、あなたの答えは私が必要としていたものでした。WebChromeClientでonJsAlert()をオーバーライドすることもお勧めします。JavaScriptロギングとアラートの組み合わせは、WebビューでホストされているJavaScriptをデバッグするときに非常に役立ちます。
マイケルレビー

13

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

ありがとう。このメソッドは、変数内の '文字をエスケープしますか?言い換えれば、次のように動作しますcallJavascript(mBrowser, "can't do it");か?
コスタノス

1
ちょうど答えを編集して、エスケープを '文字に追加しました
コスタノス

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

資産ファイル

<!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>
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.