1. 程式人生 > >Android中JavaScript和Native之間的Bridge

Android中JavaScript和Native之間的Bridge

原文地址: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. class JSHandler {  
  3.     public
     Context context;  
  4.     public JSHandler(Context c) {  
  5.         this.context = c;  
  6.     }  
  7.     public void doSomething() {  
  8.         Log.d("JSHandler""[email protected]");  
  9.         Toast.makeText(this.context, "[email protected]", Toast.LENGTH_LONG).show();  
  10.     }  
  11. }  

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. class MyCustomHander {  
  3.     public Context context;  
  4.     public MyCustomHander(Context c) {  
  5.         this.context = c;  
  6.     }  
  7.     @JavascriptInterface  
  8.     public void doSomething() {  
  9.         Log.d("MyCustomHander""[email protected]");  
  10.         Toast.makeText(this.context, "[email protected]", Toast.LENGTH_LONG).show();  
  11.     }  
  12.     public void doSomething2() {  
  13.         Log.d("MyCustomHander""[email protected]");  
  14.         Toast.makeText(this.context, "[email protected]", Toast.LENGTH_LONG).show();  
  15.     }  
  16. }  


Android 4.2以前版本看到的是:"[email protected]",而Android 4.2以後版本看到的是:"[email protected]"。 
比如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""[email protected]: " + url);  
  6.             Toast.makeText(getBaseContext(), "[email protected]: " + 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""[email protected]: " + message);  
  6.         Toast.makeText(getBaseContext(), "[email protected]: " + 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.     public APIHttpServer() {  
  3.         super(4000);  
  4.     }  
  5.     @Override  
  6.     public Response serve(String uri, Method method,  
  7.             Map<String, String> headers, Map<String, String> params,  
  8.             Map<String, String> files) {  
  9.         String data = "uri=" + uri + ", params=" + params;  
  10.         Log.d("APIHttpServer""[email protected]: " + data);  
  11.         return new NanoHTTPD.Response(Status.OK, "application/json""{msg:'nano'}");  
  12.     }  
  13. }  
  14. APIHttpServer server = new APIHttpServer();  
  15. 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

相關推薦

AndroidJavaScriptNative之間Bridge

原文地址:http://rensanning.iteye.com/blog/2043049 為什麼手機瀏覽器或者WebView中不能執行JavaScript呼叫本地API,而在HTML5混合式應用中卻能執行?  JavaScript呼叫本地API大概有4種方法: (1)

Androiddppx之間進行轉換

在xml佈局檔案中,我們既可以設定px,也可以設定dp(或者dip)。一般情況下,我們都會選擇使用dp,這樣可以保證不同螢幕解析度的機器上佈局一致。但是在程式碼中,如何處理呢?很多控制元件的方法中都只提供了設定px的方法,例如setPadding,並沒有提供設定dp的方法。

Android Service Activity之間傳值。(涉及BroadCast的基本用法)

首先先建立一個Android工程(名字自定義)這裡我命名為MyActivity 包名為:package org.hm.myactivity; 再最後給自己的activity命名(名字自定義)此處我命名為MyTestActivity public class MyTestA

AndroidJavaJavaScript互動 Android原生html互動

1.WebView開啟JavaScript指令碼執行 WebSettings settings = webView.getSettings(); settings.setJavaScriptEnabled(true); 2.WebView設定

AndroidgetDrawablegetColor過時的替代方法

this logs con 知識 log launcher 16px ase spa 版權聲明:本文為博主原創文章,未經博主允許不得轉載。 前言 Android SDK 升級到 23 之後,getDrawable和getColor方法提示過時。 解決方案 getRe

Android 單位dppx之間相互轉換

style pan static float logs ati col return roi public class DensityUtil { /** * 根據手機的分辨率從 dp 的單位 轉成為 px(像素) */

Android BitmapDrawable相互轉換的方法

canvas board null height .com factory oar tool pla 1、Drawable --> Bitmap [java] view plain copy Bitmap drawable2Bitmap(Drawabl

關於ToolbarnavigationIcontitle之間距離及展開

boolean ionic code sin block max change nav 希望 關於Toolbar中navigationIcon和title之間距離及展開 問題緣起 在進行Coolcode項目的MyclassActivity中,我發現navigationI

Android兩個Activity之間簡單通信

idg tin test ide button ima 接收 9.png set 在Android中,一個界面被稱為一個activity,在兩個界面之間通信,采用的是使用一個中間傳話者(即Intent類)的模式,而不是直接通信。 下面演示如何實現兩個activity之間的通

AndroidGalleryImageSwitcher同步自動(滾動)播放圖片庫

目標 art trac repl otto fin instance img com 本文主要內容是如何讓Gallery和ImageSwitcher控件能夠同步自動播放圖片集 ,看起來較難,然而,實現的方法非常簡單, 請跟我慢慢來。總的來說,本文要實現的效果如下圖:(截

【spring Boot】Spring@Controller@RestController之間的區別

處理 public 不同 esp 舉例 rest control tro adding spring Boot入手的第一天,看到例子中的@RestController ............. 相同點:都是用來表示Spring某個類的是否可以接收HTTP請求 不同點:@C

AndroidRelativeLayoutLinearLayout性能分析

ant 顯示 二次 iou other comm 排列 vertica 簡單的 先看一些現象吧:用eclipse或者Android studio,新建一個Activity自動生成的布局文件都是RelativeLayout,或許你會認為這是IDE的默認設置問題,其實不然,

AndroidServiceIntentService的差別

前言: ServiceTimeout(20 seconds)小概率型別Service在特定的時間內無法處理完成,會造成ANR — 應用程式無響應(ANR:Application Not Responding)的情況 ▲ 分析 : 避免ANR最核心的一點就是在主執行緒減少耗時操作。這時我們

30-python3 bytes string 之間的互相轉換

轉自:http://www.jb51.net/article/105064.htm   password = b'123456' 等價於: pw = '123456' password = pw.encode(encoding='utf-8')      前言

SpringMVC@PathVariable@RequestParam之間的區別

@PathVariable繫結URI模板變數值 @PathVariable是用來獲得請求url中的動態引數的 @PathVariable用於將請求URL中的模板變數對映到功能處理方法的引數上。//通俗來講配置url和方法的一個關係 @RequestMapping("/item/{item

AndroidSerializableParcelable序列化物件詳解

學習內容: 1.序列化的目的 2.Android中序列化的兩種方式 3.Parcelable與Serializable的效能比較 4.Android中如何使用Parcelable進行序列化操作 5.Parcelable的工作原理 6.相關例項   1.序列化

javaStringdate之間的互轉

1 Java時間格式轉換大全 2 3 import java.text.*; 4 import java.util.Calendar; 5 public class VeDate { 6 /** 7 * 獲取現在時間 8 * 9 * @ret

UnitySpriteTexture2D之間的關係。

Texture2D中包含多種型別的貼圖,比如normol map,default,sprite 等等。 當我們去切割精靈產生一張或多張資源的時候,就會產生sprite,如圖上面這個object的型別就是Texture2D,下面這個object就是sprite了,我們可以看 Selectio

Android srcbackground的區別

XML屬性中src和background的區別: src會存放原圖的大小,background會根據view的大小拉伸整張圖片。src是前景而background是背景。 可以使用scaleType屬性設定src(只對src起作用)的縮放方式。 詳細的scaleType說明: CEN

對於QtQStringchar*之間的互相轉換問題(系列二)

對於Qt,雖說對C++全部相容,但是一旦涉及到和介面的資料的互動操作,難免涉及到char*和QString的轉換問題,轉換的過程很簡單,這裡總結了一下網上提供的最簡單的一個方法: 從char*轉成QString型別: 使用fromLocal8Bit方法進行轉換: char * te