关闭

Android中JavaScript和Native之间的Bridge

755人阅读 评论(0) 收藏 举报
分类:

原文地址: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<String, String> headers, Map<String, String> params,  
  10.             Map<String, String> 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
0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:841536次
    • 积分:9056
    • 等级:
    • 排名:第2043名
    • 原创:203篇
    • 转载:51篇
    • 译文:0篇
    • 评论:146条
    最新评论