原文地址:http://rensanning.iteye.com/blog/2043049



为什么手机浏览器或者WebView中不能执行JavaScript调用本地API,而在HTML5混合式应用中却能执行? 


JavaScript调用本地API大概有4种方法: 

(1)addJavascriptInterface/@JavascriptInterface  
Android的WebView类的标准接口。 
Java代码  
  1. webView.addJavascriptInterface(new JSHandler(this), "Bridge");  
  2.   
  3. class JSHandler {  
  4.     public Context context;  
  5.       
  6.     public JSHandler(Context c) {  
  7.         this.context = c;  
  8.     }  
  9.   
  10.     public void doSomething() {  
  11.         Log.d("JSHandler""doSomething@JSHandler");  
  12.         Toast.makeText(this.context, "doSomething@JSHandler", Toast.LENGTH_LONG).show();  
  13.     }  
  14. }  

addJavascriptInterface()方法的第一个参数就是要暴露给JavaScript的Class对象,第二个参数是可以调动该Class方法的JavaScript的全局变量。 

Js代码  
  1. $(function() {  
  2.     Bridge.doSomething();  
  3. });  


但是addJavascriptInterface()方法存在安全隐患,在JavaScript中可以反射调用到Class的任意属性,比如以下代码能够取到Activity的package名。 
Js代码  
  1. $(function() {    
  2.     var klass = Bridge.getClass();  
  3.     var field = klass.getDeclaredField('context');  
  4.     field.setAccessible(true);  
  5.     var context = field.get(Bridge);  
  6.     document.getElementById('res').innerHTML = context.getPackageName();  
  7. });  

 

Android 4.2 Jelly Bean以后版本,只有标示了@JavascriptInterface的方法JavaScript才能调到。 
Java代码  
  1. webView.addJavascriptInterface(new MyCustomHander(this), "Bridge");  
  2.   
  3. class MyCustomHander {  
  4.     public Context context;  
  5.       
  6.     public MyCustomHander(Context c) {  
  7.         this.context = c;  
  8.     }  
  9.       
  10.     @JavascriptInterface  
  11.     public void doSomething() {  
  12.         Log.d("MyCustomHander""doSomething@MyCustomHander");  
  13.         Toast.makeText(this.context, "doSomething@MyCustomHander", Toast.LENGTH_LONG).show();  
  14.     }  
  15.       
  16.     public void doSomething2() {  
  17.         Log.d("MyCustomHander""doSomething2@MyCustomHander");  
  18.         Toast.makeText(this.context, "doSomething2@MyCustomHander", Toast.LENGTH_LONG).show();  
  19.     }  
  20. }  


Android 4.2以前版本看到的是:"doSomething2@MyCustomHander",而Android 4.2以后版本看到的是:"doSomething@MyCustomHander"。 
比如Android 4.1: 
 

(2)自定义URL  

Java代码  
  1. webView.setWebViewClient(new WebViewClient() {  
  2.     @Override  
  3.     public boolean shouldOverrideUrlLoading(WebView view, String url) {  
  4.         if (url.startsWith("apicall://")) {  
  5.             Log.d("MyWebViewClient""doSomething@WebViewClient: " + url);  
  6.             Toast.makeText(getBaseContext(), "doSomething@WebViewClient: " + url, Toast.LENGTH_LONG).show();  
  7.             return true;  
  8.         }  
  9.         return false;  
  10.     }  
  11. });  


Js代码  
  1. $(function() {  
  2.   window.location = 'apicall:////some_api_name/exec?a=1&b=2';  
  3. });  

 

(3)JsAlert  

Java代码  
  1. webView.setWebChromeClient(new WebChromeClient() {  
  2.     @Override  
  3.     public boolean onJsAlert(WebView view, String url,  
  4.             String message, JsResult result) {  
  5.         Log.d("MyWebChromeClient""doSomething@WebChromeClient: " + message);  
  6.         Toast.makeText(getBaseContext(), "doSomething@WebChromeClient: " + message, Toast.LENGTH_LONG).show();  
  7.         // return super.onJsAlert(view, url, message, result);  
  8.         return true;  
  9.     }  
  10. });  


Js代码  
  1. $(function() {  
  2.   alert("123");  
  3. });  

 

(4)搭建本地HTTP服务器  

NanoHttpd  是一个轻量级的可嵌入的HTTP服务器。 
Java代码  
  1. public class APIHttpServer extends NanoHTTPD {  
  2.   
  3.     public APIHttpServer() {  
  4.         super(4000);  
  5.     }  
  6.   
  7.     @Override  
  8.     public Response serve(String uri, Method method,  
  9.             Map headers, Map params,  
  10.             Map files) {  
  11.   
  12.         String data = "uri=" + uri + ", params=" + params;  
  13.         Log.d("APIHttpServer""doSomething@APIHttpServer: " + data);  
  14.   
  15.         return new NanoHTTPD.Response(Status.OK, "application/json""{msg:'nano'}");  
  16.     }  
  17. }  
  18.   
  19. APIHttpServer server = new APIHttpServer();  
  20. server.start();  


Js代码  
  1. $(function() {  
  2.   $.getJSON("http://localhost:4000/some_api_name?a=1&b=2&c=3");  
  3. });  


AndroidManifest.xml 
Xml代码  
  1. <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>  
  2. <uses-permission android:name="android.permission.INTERNET"/>  


 


还有一种方法,通过URL的变更也能够实现,但是存在安全问题,基本不使用!  
Js代码  
  1. window.location = 'http://cdv_exec/' + service + '#' + action + '#' + callbackId + '#' + argsJson;  

Java代码  
  1. public class MyWebViewClient extends WebViewClient {  
  2.   public boolean shouldOverrideUrlLoading(WebView view, String url) {  
  3.     if (url.startsWith("http://cdv_exec/")) {  
  4.       handleExecUrl(url); // 截取参数处理  
  5.     }  
  6.   }  
  7. }  


参考: 
http://www.buildinsider.net/mobile/bookhtml5hybrid

更多相关文章

  1. Android的jni的调用C,C++的几个应用(基本类型,数组,类(结构体))
  2. android 实现分享功能两种方法
  3. 再也不信网上流传的方法了!!android创建组件的真正写法!
  4. android 官网处理图片 代码
  5. 转:Parcle
  6. android ListView上拉加载更多 下拉刷新功能实现(采用pull-to-ref
  7. Android(安卓)ApiDemo 笔记(二)Graphics和View
  8. android手机震动代码
  9. Android随笔之标题栏的去除以及自定义

随机推荐

  1. Android之Handler的用法
  2. Android触摸滑动全解(三)——View坐标体系
  3. android集成科大讯飞语音听写和语音合成
  4. Android省市区滚轮默认显示已选择的项
  5. 你如何评价Android系统?优缺点。
  6. 基础总结篇之二:Activity的四种launchMode
  7. Android(安卓)内存优化代码篇总结
  8. Android(安卓)Socket 发送与接收数据问题
  9. Hbuilder集成个推时Android和ISO中推送的
  10. Android实现无线调试自己的应用