web-dev-qa-db-ja.com

evaluateJavascriptはどのように機能しますか?

新しい evaluateJavascript メソッドをAndroid 4.4で使用しようとしていますが、返されるのはnullの結果だけです:

_webView1.evaluateJavascript("return \"test\";", new ValueCallback<String>() {
    @Override
    public void onReceiveValue(String s) {
        Log.d("LogName", s); // Log is written, but s is always null
    }
});
_

このメソッドに結果を返すにはどうすればよいですか?

更新:もう少し情報:

  1. インターネット権限が設定されています
  2. 私はsetJavascriptEnabled(true);を持っています
  3. アポストロフィ文字列を試しました:_return 'test';_、
  4. JSオブジェクトを試しました:_return { test: 'this' }_
  5. console.log('test');は正常に実行されています。
  6. targetSdkVersionを次のように19に設定します。 アプリでWebView を使用する場合

デバイス:Nexus 7とNexus 5の両方(ストック)

44
CodingIntrigue

このサンプルで使用されているevaluateJavascriptメソッドの例があります。

https://github.com/GoogleChrome/chromium-webview-samples/tree/master/jsinterface-example

基本的に、WebViewで実行するJavaScriptが値を返す場合、コールバックで渡されます。

主な注意点は、OnReceiveValueで返される文字列は、返される内容に応じてJSON値、JSONオブジェクト、またはJSON配列のいずれかであるということです。

これについて注意すべきことは、単一の値を返す場合、JSONリーダーでsetLenient(true)を使用して動作させる必要があるということです。

     if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.KitKat) {
        // In KitKat+ you should use the evaluateJavascript method
        mWebView.evaluateJavascript(javascript, new ValueCallback<String>() {
            @TargetApi(Build.VERSION_CODES.HONEYCOMB)
            @Override
            public void onReceiveValue(String s) {
                JsonReader reader = new JsonReader(new StringReader(s));

                // Must set lenient to parse single values
                reader.setLenient(true);

                try {
                    if(reader.peek() != JsonToken.NULL) {
                        if(reader.peek() == JsonToken.STRING) {
                            String msg = reader.nextString();
                            if(msg != null) {
                                Toast.makeText(getApplicationContext(), msg, Toast.LENGTH_LONG).show();
                            }
                        }
                    }
                } catch (IOException e) {
                    Log.e("TAG", "MainActivity: IOException", e);
                } finally {
                    try {
                        reader.close();
                    } catch (IOException e) {
                        // NOOP
                    }
                }
            }
        });
    }

文字列応答にパーサーを引き続き使用する理由は、引用符でラップされることを意味するJSON値に変換されるためです。

たとえば、行った場合:

mWebView.evaluateJavascript("(function() { return 'this'; })();", new ValueCallback<String>() {
    @Override
    public void onReceiveValue(String s) {
        Log.d("LogName", s); // Prints: "this"
    }
});

二重引用符で囲まれた文字列thisを出力します: "this"。

注目に値する他の例:

mWebView.evaluateJavascript("(function() { return null; })();", new ValueCallback<String>() {
    @Override
    public void onReceiveValue(String s) {
        Log.d("LogName", s); // Prints the string 'null' NOT Java null
    }
});

mWebView.evaluateJavascript("(function() { })();", new ValueCallback<String>() {
    @Override
    public void onReceiveValue(String s) {
        Log.d("LogName", s); //s is Java null
    }
});

mWebView.evaluateJavascript("(function() { return ''; })();", new ValueCallback<String>() {
    @Override
    public void onReceiveValue(String s) {
        Log.d("LogName", s); // Prints "" (Two double quotes)
    }
});
62
Matt Gaunt

わかりました。したがって、ここでresultJavascript呼び出しの結果-Javascriptコンソールにコマンドを入力しているかのようになります。

したがって、結果を取得するには、関数でラップする必要があります。

webView1.evaluateJavascript("(function() { return \"this\"; })();", new ValueCallback<String>() {
    @Override
    public void onReceiveValue(String s) {
        Log.d("LogName", s); // Prints 'this'
    }
});

これも機能します:

webView1.evaluateJavascript("window.variable = \"asd\";", new ValueCallback<String>() {
    @Override
    public void onReceiveValue(String s) {
        Log.d("LogName", s); // Prints asd
    }
});

メソッドはJavascriptオブジェクトも処理します。

webView1.evaluateJavascript("(function() { return { var1: \"variable1\", var2: \"variable2\" }; })();", new ValueCallback<String>() {
    @Override
    public void onReceiveValue(String s) {
        Log.d("LogName", s); // Prints: {"var1":"variable1","var2":"variable2"}
    }
});
11
CodingIntrigue

AndroidJSCore は、WebViewを使用しないJavaScriptを評価するための優れた代替手段です。

WebViewを使い続け、以前のバージョンのAndroid(4+)でJavaScriptを評価する必要がある場合、ここに小さなライブラリがあります。

https://github.com/evgenyneu/js-evaluator-for-Android

jsEvaluator.evaluate("put your JavaScript code", new JsCallback() {
  @Override
  public void onResult(final String result) {
    // get result here (optional)
  }
});
7
Evgenii

@GauntFaceの答えを要約し、JSONパーサーを使用せずに代替ソリューションを提供するには:

JS関数がStringのみを返し、Javaで文字列がマングルされている理由がわからない場合は、JSONエスケープされているためです。

mWebView.evaluateJavascript("(function() { return 'Earvin \"Magic\" Johnson'; })();", new ValueCallback<String>() {
    @Override
    public void onReceiveValue(String s) {
        Log.d("LogName", s);
        // expected: s == Earvin "Magic" Johnson
        // actual:   s == "Earvin \"Magic\" Johnson"
    }
});

onReceiveValueは常にStringを提供しますが、JS関数はnull、Numberリテラルなどを返す場合があります。)

JSと同じ文字列値を取得するには、適切なStringが返されることを100%確信している場合、次のようにJSONエスケープを解除する必要があります。

String unescaped = s.substring(1, s.length() - 1)  // remove wrapping quotes
                     .replace("\\\\", "\\")        // unescape \\ -> \
                     .replace("\\\"", "\"");       // unescape \" -> "

ただし、sは文字列"null" JSが適切なnullを返す場合、明らかに最初のステップとしてそれを確認する必要があります。

if ("null".equals(s)) {
   ...
} else {
   // unescape JSON
}
3
jakub.g

みんなの答えは素晴らしいです。もう1つだけポイントを追加します。この方法のように@JavascripInterfaceアノテーションを持つメソッド内にevaluateJavascriptを配置しないでください

    @JavascripInterface
    public void onData(){ 
            mWebView.evaluateJavascript("javascript:executeNext()",null);
    }  

JavaBridgeスレッドをブロックするためです。 evaluateJavascriptを内部に配置する場合。このようにしてください

    @JavascripInterface
    public void onData(){
        mWebView.post(new Runnable() {
            @Override
            public void run() {
                mWebView.evaluateJavascript("javascript:executeNext()",null);
            }
        });

    }
2
littlebear333