我可以在Android(v2.2及以上版本)上从Java同步运行javascript吗?

gg58donl  于 2023-04-28  发布在  Android
关注(0)|答案(4)|浏览(90)

我试图从我的Java android应用程序中运行一些javascript,但我需要它同步运行。WebView无法实现这一点,因为loadUrl和loadData没有返回类型。真的,我正在寻找的是iOS的UIWebView上类似于此的东西:

- (NSString)stringByEvaluatingJavaScriptFromString:(NSString)script

我试过使用Rhino,但它对我来说太慢了。
谢谢!

6xfqseft

6xfqseft1#

是的,但是你必须使用WebView.addJavaScriptInterface()。

igetnqfo

igetnqfo2#

我相信它是同步的,但是,就像你正确地注意到的那样,没有办法从调用中返回一个值。
首先,创建一个简单的类(假设你的返回类型是String):

public class MyCallback {

    private String returnValue;

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

    public String getReturnValue() {
        return returnValue;
    }

}

保持这个类的简单和封装是很重要的,因为如果你从潜在的不可信的源加载HTML,它可能会给你的应用程序带来一个安全漏洞。也就是说,不要简单地传入你的Activity,让Javascript直接调用它的方法。
然后执行你想要的JavaScript,给它一个回调的示例来存储结果:

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

uujelgoq3#

这是一个老问题,但我看没有答案。下面是我如何做到这一点(但要小心阻止UI线程在这里(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")
  }
}

然后运行如下代码:

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

jv4diomz4#

webView.evaluateJavascript()异步运行,但您可以使用一个简单的信号量来等待执行。
步骤:
1.创建一个javascript接口(基本上是一个类,带有一个方法,将从我们想要评估的javascript中调用。

public class MyInterface 
 {
     private String value;
     private Semaphore semaphore;

     public MyInterface(Semaphore semaphore) {
         this.semaphore = semaphore;
     }

     public String getValue() {
         return value;
     }

     @JavascriptInterface
     public void setValue(String value) {
         this.value = value;
         //important release the semaphore after the execution
         semaphore.release();
     }
 }

1.将javascript界面添加到Android Web视图

Semaphore mySemaphore = new Semaphore(0);
 MyInterface myJsInterface = new MyInterface(mySemaphore);
 webView.addJavascriptInterface(myJsInterface, "jsInterface");

1.执行JavaScript并等待执行

webView.evaluateJavascript("var myValue='this works';jsInterface.setValue(myValue);", null);
 //await the execution
 mySemaphore.acquire();
 //the interface now have the value after the execution
 myJsInterface.getValue();

相关问题