你的位置:首页 > 操作系统

[操作系统]WebView上实现Java与JavaScript交互


      在安卓开发上,考虑到开发效率和界面更新,有时使用WebView结合web页面技术,可以快速迭代地开发移动应用。WebView加载资源的速度并不慢,但是如果资源多了,就很慢。图片、css、js、html这些资源每个大概需要10-200ms,一般都是30ms以内就行了。但是,WebView是等全部资源加载完成才开始渲染的,所以最后用原生js来写,别用太多jQuery之类的框架,以改善用户体验。

  在混合开发中,有时会用到安卓原生SDK,如调用相机、查看相册、录音等,这就需要web页面中的JavaScript能调用到安卓SDK接口。由于Android的WebView是基于webkit内核的,集成了js与java互调的接口函数,可以方便地进行开发使用。

界面布局

 1 <RelativeLayout ="http://schemas.android.com/apk/res/android" 2   ="http://schemas.android.com/tools" 3   android:layout_width="match_parent" 4   android:layout_height="match_parent" > 5  6   <WebView 7     android:id="@+id/webView" 8     android:layout_width="fill_parent" 9     android:layout_height="fill_parent"10     android:layout_above="@+id/linearLayout"11     />12   <LinearLayout 13     android:id="@+id/linearLayout"14     android:layout_width="match_parent"15     android:layout_height="wrap_content"16     android:layout_alignParentBottom="true"17     >18     <Button19       android:id="@+id/btn"20       android:layout_width="wrap_content"21       android:layout_height="wrap_content"22       android:text="Java调用JavaScript接口"23       >24     </Button>25   </LinearLayout>26 </RelativeLayout>

 java代码:

 1 private WebView webView; 2   private Handler handler = new Handler(); 3   private Button button; 4   @SuppressLint("SetJavaScriptEnabled") 5   @Override 6   protected void onCreate(Bundle savedInstanceState) { 7     super.onCreate(savedInstanceState); 8     setContentView(R.layout.activity_main); 9     webView = (WebView) findViewById(R.id.webView);10     11     //自定义webView设置12     WebSettings webSettings = webView.getSettings();13     webSettings.setJavaScriptEnabled(true);14     webView.addJavascriptInterface(new MyJavaScriptInterface(MainActivity.this), "javaInterface");15     //如果注释了,javaScript中的alert弹窗等就会失效,不显示16     webView.setWebChromeClient(new WebChromeClient());17     //webView.setWebChromeClient(new MyWebChromeClient());18     19     //测试webView加载是否正常20     //webView.loadUrl("http://www.baidu.com/");21     webView.setWebViewClient(new HelloWebView());22     webView.loadUrl("file:///android_asset/index.html");23     24     button = (Button) findViewById(R.id.btn);25     button.setOnClickListener(new View.OnClickListener() {26       27       @Override28       public void onClick(View v) {29         String param = "bb";30         webView.loadUrl("javascript:showTitle('"+param+"')");31       }32     });33   }34 35   private class HelloWebView extends WebViewClient{36     @Override37     public boolean shouldOverrideUrlLoading(WebView view, String url) {38       // TODO Auto-generated method stub39       view.loadUrl(url);40       return true;41     }    42   }43   44   /**45    * 在主线程中定义JavaScript可以调用的安卓接口46    * @author CHQ47    * API 17以后,每个被调用java函数都要叫声明 @JavascriptInterface48   */49   public class MyJavaScriptInterface{50     private Context context;51     52     public MyJavaScriptInterface(Context context){53       this.context = context;54     }55     @JavascriptInterface56     public String toString() {57       return "this is interface";58     }59     @JavascriptInterface60     public void clickOnAndroid() {61       Toast.makeText(context, "js调用安卓:....", Toast.LENGTH_SHORT).show();62     }63     /**64      * 安卓调用JS接口,要开启子线程调用65     */66     @JavascriptInterface67     public void call() {68       Toast.makeText(context, "安卓客户端再调用JavaScript接口", Toast.LENGTH_SHORT).show();69       handler.post(new Runnable() {      70         @Override71         public void run() {72           String param = "bb";73           webView.loadUrl("javascript:showTitle('"+param+"')");74         }75       });76       77     }78     79   }

其中:有几点必须注意的,网上早期关于WebView的描述中,有几点变化。1)安卓4.2以上的版本中使用WebView实现Java与Js互调,java接口需要声明@JavascriptInterface ; 2)WebView要调用setWebChromeClient(),以适应Js等弹窗等实现;3)addJavascriptInterface中绑定的接口中调用JavaScript接口,需要开启子线程来调用(报错:Caused by: java.lang.Throwable: A WebView method was called on thread 'JavaBridge'. All WebView methods must be called on the same thread. );

 

HTML代码:

<html>  <script type="text/javascript">    //安卓定义的接口1    function callAndroidInterface() {      window.javaInterface.clickOnAndroid();    }    //    function showTitle(param) {      alert("传参:"+param);      var x = document.getElementById("title");      alert("标题:"+x.innerHTML);    }  </script>  <body>  <h3 id="title">关于安卓与JavaScript的交互</h3>  <input type="button" value="调用接口1" onclick="callAndroidInterface()"></input>    <input type="button" value="测试接口可用性" onclick="showTitle('aa')"></input>    <input type="button" value="调用接口2" onclick="window.javaInterface.call()"></input>    </body></html>

 以上html文件,其中javaInterface就是webView中addJavacriptInterface()方法中注入的接口入口名称,通过该名称就可以直接调用Java中的接口。(该html页面需要保持到项目assets目录中,由webView.loadUrl("file:///android_asset/index.html")来加载);

 

效果图:


 
其中,对话框弹出:网址为"file://"的网页显示:,如果是服务器上的web页面就会显示源IP地址等等,显然不是我们想要的。下一篇,我们可以重写WebChromeClient来修改对话框、确认框等webView的优化。