web-dev-qa-db-ja.com

webView.evaluateJavascriptコールバックから値を返す方法は?

したがって、私はJavascriptBridgeという名前のクラスを持っています。これは、JavaとJavascriptの間の通信に使用します。

コマンドをJavaScriptに送信するには、次のようにします。

public void sendDataToJs(String command) {
    webView.loadUrl("javascript:(function() { " + command + "})()");
}

私の問題は、Javascriptからの応答を返す関数も必要になることです。 webView.evaluateJavascriptを使用してみますが、evaluateJavascriptは別のスレッドで実行されるため、コールバックはスキップされます。

public String getDataFromJs(String command, WebView webView) {
    String data = null;

    webView.evaluateJavascript("(function() { return " + command + "; })();", new ValueCallback<String>() {
        @Override
        public void onReceiveValue(String s) {
            Log.d("LogName", s); // Print "test"
            // data = s; // The value that I would like to return
        }
    });

    return data; // Return null, not "test"
}

メソッドの呼び出し:

String result = getDataFromJs("test", webView); // Should return "test" from the webView

@ JavascriptInterfaceも試してみましたが、同じ結果が得られます。

12
endlessCoffee

Android(つまり、現在のスレッド)でJavascriptを同期的に評価する方法はないため、evaluateJavascriptを使用してコールバックを待つのが最善策です。

public void getDataFromJs(String command, WebView webView) {
    webView.evaluateJavascript("(function() { return " + command + "; })();", new ValueCallback<String>() {
        @Override
        public void onReceiveValue(String s) {
            returnDataFromJs(s);
        }
    });
}

public returnDataFromJs(String data) {
    // Do something with the result.
}

現在のスレッドでJavaScriptを評価する方法はありません。JavaScriptの操作には時間がかかり(JSエンジンが起動するまでに時間がかかる)、現在のスレッドをブロックする可能性があるためです。

8
Colin White

私はあなたを助けることができる小さなコードスニペットをコトリンで書きました。これはRxKotlinを使用して作成しましたが、Javaを使用する場合、RxJava2は同じなので使用できます。

fun getDataFromJsSync(command: String, webView: WebView): String {
    return getDataFromJs(command, webView).blockingGet()
}

fun getDataFromJs(command: String, webView: WebView): Single<String> {
    return Single.create { emitter: SingleEmitter<String> ->
        try {
            webView.evaluateJavascript(
                    "(function() { return $command; })();",
                    { result -> emitter.onSuccess(result) }
            )
        } catch (e: Exception) {
            emitter.onError(e)
        }
    }
}

追伸私は関数をテストしていませんし、それらが機能することを保証できませんが、時間がないので、テストして、Javaに書き換えます。時間があるときは、おそらく最大5時間です。

1
TheKarlo95