Android与javascript混合开发

749人浏览 / 0人评论 / 添加收藏

1.在WebView中使用JavaScript

Android提供了一个很强大的WebView控件用来处理Web网页,而在网页中JavaScript又是一个很举足轻重的脚本。因此,使用WebView时经常会涉及到Android代码和JavaScript代码的交互。

实现Java和js交互通常只需要以下几步:

①WebView开启JavaScript脚本执行。

WebView myWebView = (WebView) findViewById(R.id.webview);

WebSettings webSettings = myWebView.getSettings();

webSettings.setJavaScriptEnabled(true);

②WebView设置供JavaScript调用的交互接口。

③客户端和网页端编写调用对方的代码。

 

2.JavaScript调用Android中的方法

比如,可以用JavaScript代码调用Android代码中的方法,来展现一个对话框,而不是使用JS中的alert()方法。

在JS和Android代码间绑定一个新的接口,需要调用addJavascriptInterface()方法。该方法参数传入一个Java对象实例和一个字符串,该字符串是一个名字(interface name,注意此接口不是通常所说的那个用来实现的接口,而是传入的这个对象在JS中的别名),在JS代码中用此名字调用该Java对象的方法。

addJavascriptInterface()方法可以让JS代码控制宿主程序,这是一个非常有力的特性,但是同时也存在一些安全问题,因为进一步JS代码可以通过反射访问到注入对象的公有域。攻击者可能会在HTML和JavaScript中包含了有威胁性的代码。所以Android 4.1,API 17开始,只有被JavascriptInterface注解标识的公有方法可以被JS代码访问。

另外,因为JS代码和Java对象在这个WebView所私有的后台线程交互,所以还需要注意线程安全性问题。

注意,与JS代码绑定的的这个Java对象运行在另一个线程中,与创建它的线程不是一个线程。而且这个Java对象的域是不可访问的。

//自定义的Android代码和JavaScript代码之间的桥梁类

public class WebAppInterface {

   Context mContext;

   WebAppInterface(Context c) {

       mContext = c;

   }

   // 如果target>=API 17,则需要加上如下注解

  @JavascriptInterface

   public void showToast(String toast) {

       Toast.makeText(mContext, toast, Toast.LENGTH_LONG).show();

   }

}

然后将这个类和WebView中的JS代码绑定:

WebView webView = (WebView) findViewById(R.id.webview);

webView.addJavascriptInterface(new WebAppInterface(this), "Android"); //给这个对象起的别名叫“Android”

这样就创立了一个接口名,叫“Android”,运行在WebView中的JS代码可以通过这个名字调用WebAppInterface类中的showToast()方法:

<input type="button" value="Say hello" onClick="showAndroidToast('Hello Android!')" />

<script type="text/javascript">

   function showAndroidToast(toast) {

       Android.showToast(toast);

   }

</script>

 

3.Android调用JavaScript代码

这个还比较简单,需要调用的时候只需要一行代码:

myWebView.loadUrl("javascript:myFunction()");

其中myFunction()是JS函数。

注意:如果JavaScript函数是带参数的,那么调用时要特别注意。

比如下面这个JS函数,在原来内容上加入一行:

function writeLine(string) {

   console.log("Write a new Line");

   document.getElementById("content").inn erHTML += string + "<br />";//在content标签段落加入新行

}

其中content是自定义的标签,html中有一个段落是:<p id="content"></p>

那么在Android代码中调用这个writeLine()函数时,需要传入一个字符串参数,比如想要传入一个叫name的String:

myWebView.loadUrl("javascript:writeLine('"+name+"')");//JS代码要是带参数

注意:双引号中的函数名一定不要写错。

 

4.使用举例

①Android端代码:

public class MainActivity extends Activity {

 @Override

 protected void onCreate(Bundle savedInstanceState) {

     super.onCreate(savedInstanceState);

     setContentView(R.layout.activity_main);

     final WebView myWebView = (WebView) findViewById(R.id.myWebView);

     WebSettings settings = myWebView.getSettings();

     settings.setJavaScriptEnabled(true);

     myWebView.addJavascriptInterface(new JsInteration(), "control");

     myWebView.setWebChromeClient(new WebChromeClient() {});

     myWebView.setWebViewClient(new WebViewClient() {

         @Override

         public void onPageFinished(WebView view, String url) {

             super.onPageFinished(view, url);

             testMethod(myWebView);

         }        

     });

     myWebView.loadUrl( "file:///android_asset/js_java_interaction.html");

 }

 private void testMethod(WebView webView){

     String call = "javascript:sayHello()";      

     call = "javascript:alertMessage(\"" + "content" + "\")";    

     call = "javascript:toastMessage(\"" + "content" + "\")";      

     call = "javascript:sumToJava(1,2)";

     webView.loadUrl(call);      

 }

 public class JsInteration {    

     @JavascriptInterface

    public void toastMessage(String message){

         Toast.makeText(this, message, Toast.LENGTH_LONG).show();

     }      

     @JavascriptInterface

     public void onSumResult(int result) {

         Log.i(LOGTAG, "onSumResult result=" + result);

     }

 }

}

②前端网页代码:

<html>

<script type="text/javascript">

   function sayHello() {

       alert("Hello")

   }

   function alertMessage(message) {

       alert(message)

   }

   function toastMessage(message) {

       window.control.toastMessage(message)

   }

   function sumToJava(number1, number2){

      window.control.onSumResult(number1 + number2)

   }

</script>

Java-Javascript Interaction In Android

</html>

③JS调用Java

调用格式为window.jsInterfaceName.methodName(parameterValues),此例中使用的是control作为注入接口名称。

function toastMessage(message) {

 window.control.toastMessage(message)

}

function sumToJava(number1, number2){

  window.control.onSumResult(number1 + number2)

}

④Java调用JS

webView调用js的基本格式为:webView.loadUrl(“javascript:methodName(parameterValues)”)

1)调用js无参无返回值函数:

String call = "javascript:sayHello()";

webView.loadUrl(call);

2)调用js有参无返回值函数:

String call = "javascript:alertMessage(\"" + "content" + "\")"; //注意对于字符串作为参数值需要进行转义双引号。

webView.loadUrl(call);

3)调用js有参数有返回值的函数

Android在4.4之前并没有提供直接调用js函数并获取值的方法,所以在此之前,常用的思路是 java调用js方法,js方法执行完毕,再次调用java代码将值返回。

第一步:Java调用js代码:

String call = "javascript:sumToJava(1,2)";

webView.loadUrl(call);

第二步:js函数处理,并将结果通过调用java方法返回

function sumToJava(number1, number2){

  window.control.onSumResult(number1 + number2)

}

第三步:Java在回调方法中获取js函数返回值

@JavascriptInterface

public void onSumResult(int result) {

 Log.i(LOGTAG, "onSumResult result=" + result);

}

Android 4.4之后使用evaluateJavascript即可。这里展示一个简单的交互示例。

先提供一个具有返回值的js方法:

function getGreetings() {

     return 1;

}

java代码里用evaluateJavascript方法调用:

private void testEvaluateJavascript(WebView webView) {

 webView.evaluateJavascript("getGreetings()", new ValueCallback<String>() {

     @Override

     public void onReceiveValue(String value) {

         Log.i(LOGTAG, "onReceiveValue value=" + value);

     }

  });

}

输出结果:

I/MainActivity( 1432): onReceiveValue value=1

注意:

①上面限定了结果返回结果为String,对于简单的类型会尝试转换成字符串返回,对于复杂的数据类型,建议以字符串形式的json返回。

②evaluateJavascript方法必须在UI线程(主线程)调用,因此onReceiveValue也执行在主线程。

全部评论