开发者

Can I run javascript synchronously from Java on Android (v2.2 and above)?

I'm trying to run some javascript from within my Java android app but I need it to run synchronously. WebView can't accomplish this since loadUrl and loadData don't have return types. Really, what I'm looking for is something equivalent to this on iOS's UIWebView:

- (NSString)stringByEvaluatingJavaScriptFromString:(NSString)script

I tried using Rhino but it's W开发者_运维知识库AY too slow for my purposes.

Thanks!


Yes but you'll have to use WebView.addJavaScriptInterface().


I believe it is synchronous, however, like you correctly note, there's no way to return a value from the call. Dan alludes to a solution ...

Firstly, create a simple class like this (assuming your return type is a String):

public class MyCallback {

    private String returnValue;

    public void setReturnValue(String s) {
        returnValue = s;
    }

    public String getReturnValue() {
        return returnValue;
    }

}

It's important to keep this class simple and encapsulated because if you're loading HTML from potentially untrustworthy sources it could present a security hole in to your application. That is, don't be tempted to simply pass in your Activity and have the Javascript call methods on it directly.

Then execute the Javascript you want giving it an instance of the callback to store the result:

 WebView webView = // ... get this from somewhere
 MyCallback callback = new MyCallback();
 webView.addJavaScriptInterface(callback, "callback");
 webView.loadURL("javascript:callback.setReturnValue(someFunction())");
 System.out.println("return value is " + callback.getReturnValue());


Old question but I see there's no answer. Here's how I do it (but be careful blocking the UI thread here (Kotlin).

class MyWebView @JvmOverloads constructor(
  context: Context,
  attrs: AttributeSet? = null,
  defStyle: Int = 0
): WebView(context, attrs, defStyle) {

  private val lock = ReentrantLock()
  private val condition = lock.newCondition()

  private inner class MyJsInterface {
    @JavascriptInterface
    fun finished() {
      lock.withLock {
        // Do stuff (Not the UI thread)
        condition.signalAll()
      }
    }
  }

  private val jsInterface = MyJsInterface()

  fun syncJsCall(js: String) {
    lock.withLock {
      loadUrl("javascript:$js")
      condition.await()
    }
  }

  init {
    options.javascriptEnabled = true
    addJavascriptInterface(jsInterface, "MyApp")
  }
}

Then run something like:

webview.syncJsCall(
  """
    (function() {
      console.log("hello world");
      MyApp.finished();
   })()
  """.trimIndent()
)
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜