1、Cordova 核心java類說明javascript
CordovaActivity:Cordova Activity入口,已實現PluginManager、WebView的相關初始化工做, 只需繼承CordovaActivity實現本身的業務需求。java
PluginManager: 插件管理器android
ExposedJsApi :javascript調用Native, 經過插件管理器PluginManager 根據service找到具體實現類。web
NativeToJsMessageQueue:Native調用javascript,主要包括三種方式:loadUrl 、 輪詢、反射WebViewCore執行jsapp
2、 Cordova框架類圖框架
3、Cordova框架啓動異步
當實現了DroidGap或者CordovaInterface接口的Activity的onCreate方法中調用DroidGap的loadUrl方法即啓動了Cordova框架。ide
Cordova提供了一個Class(DroidGap extends CordovaActivity)和一個interface(CordovaInterface)來讓Android開發者開發Cordova。函數
通常狀況下實現DroidGap便可,由於DroidGap類已經作了不少準備工做,能夠說DroidGap類是Cordova框架的一個重要部分;若是在必要的狀況下實現CordovaInterface接口,那麼這個類中不少DroidGap的功能須要本身去實現。繼承了DroidGap或者CordovaInterface的Activity就是一個獨立的Cordova模塊,獨立的Cordova模塊指的是每一個實現了DroidGap或者CordovaInterface接口的Activity都對應一套獨立的WebView,Plugin,PluginManager,沒有共享的。ui
在初始化完CordovaWebView後調用CordovaWebView.loadUrl()。此時完成Cordova的啓動。
1.Cordova關聯對象初始化
在實例化CordovaWebView的時候, CordovaWebView對象會去建立一個屬於當前CordovaWebView對象的插件管理器PluginManager對象,一個消息隊列NativeToJsMessageQueue對象,一個JavascriptInterface對象ExposedJsApi,並將ExposedJsApi對象添加到CordovaWebView中,JavascriptInterface名字爲:_cordovaNative。
2. Cordova的JavascriptInterface
在建立ExposedJsApi時須要CordovaWebView的PluginManager對象和NativeToJsMessageQueue對象。由於全部的JS端與Android native代碼交互都是經過ExposedJsApi對象的exec方法。在exec方法中執行PluginManager的exec方法,PluginManager去查找具體的Plugin並實例化而後再執行Plugin的execute方法,並根據同步標識判斷是同步返回給JS消息仍是異步。由NativeToJsMessageQueue統一管理返回給JS的消息。
3. 什麼時候加載Plugin,如何加載
Cordova在啓動每一個Activity的時候都會將配置文件中的全部plugin加載到PluginManager。那麼是何時將這些plugin加載到PluginManager的呢?在b中說了最後會調用CordovaWebView.loadUrl(),對,就在這個時候會去初始化PluginManager並加載plugin。PluginManager在加載plugin的時候並非立刻實例化plugin對象,而是隻是將plugin的Class名字保存到一個hashmap中,用service名字做爲key值。
當JS端經過JavascriptInterface接口的ExposedJsApi對象請求Android時,PluginManager會從hashmap中查找到plugin,若是該plugin還未實例化,利用java反射機制實例化該plugin,並執行plugin的execute方法。
4.Cordova的數據返回
Cordova中經過exec()函數請求android插件,數據的返回可同步也能夠異步於exec()函數的請求。在開發android插件的時候能夠重寫public boolean isSynch(String action)方法來決定是同步仍是異步。Cordova在android端使用了一個隊列(NativeToJsMessageQueue)來專門管理返回給JS的數據。
1)同步
Cordova在執行完exec()後,android會立刻返回數據,但不必定就是該次請求的數據,多是前面某次請求的數據;由於當exec()請求的插件是容許同步返回數據的狀況下,Cordova也是從NativeToJsMessageQueue隊列頭pop頭數據並返回。而後再根據callbackID反向查找某個JS請求,並將數據返回給該請求的success函數。
2)異步
Cordova在執行完exec()後並不會同步獲得一個返回數據。Cordova在執行exec()的同時啓動了一個XMLHttpRequest對象方式或者prompt()函數方式的循環函數來不停的去獲取NativeToJsMessageQueue隊列中的數據,並根據callbackID反向查找到相對應的JS請求,並將該數據交給success函數。
注:Cordova對本地的HTML文件(file:// 開頭的URL)或者手機設置有代理的狀況下使用XMLHttpRequest方式獲取返回數據,其餘則使用prompt()函數方式獲取返回數據。
五、webView.sendJavascript 發送到js隊列,onNativeToJsMessageAvailable 負責執行js.
Native 調用 JS 執行方式有三種實現 LoadUrlBridgeMode、 OnlineEventsBridgeMode、PrivateApiBridgeMode
一、webView.sendJavascript 發送js方法到JS隊列
二、onJsPrompt 方法攔截,獲取調用方式
》》若是是gap_bridge_mode,則執行 appView.exposedJsApi.setNativeToJsBridgeMode(Integer.parseInt(message));
》》若是是gap_poll, 則執行 appView.exposedJsApi.retrieveJsMessages("1".equals(message));
三、調用setBridgeMode 方法調用onNativeToJsMessageAvailable 執行javascript調用
4、Native調用javascript 方式:NativeToJsMessageQueue
一、loadUrl javascript 調用方式
private class LoadUrlBridgeMode extends BridgeMode if (url.startsWith("file://") || url.startsWith("javascript:") || Config.isUrlWhiteListed(url)) { }
二、Navitive事件通知javascript輪詢獲取Navitive數據
private class OnlineEventsBridgeMode extends BridgeMode
三、經過Java反射獲取webview 的sendMessage 方法執行js, 支持 Android 3.2.4之上(包含)
---能夠解決loadUrl 隱藏鍵盤的問題:當你的焦點在輸入,若是這經過loadUrl調用js,會致使鍵盤隱藏
private class PrivateApiBridgeMode extends BridgeMode Field f = webViewClass.getDeclaredField("mProvider"); f.setAccessible(true); webViewObject = f.get(webView); webViewClass = webViewObject.getClass(); Field f = webViewClass.getDeclaredField("mWebViewCore"); f.setAccessible(true); webViewCore = f.get(webViewObject); if (webViewCore != null) { sendMessageMethod = webViewCore.getClass().getDeclaredMethod("sendMessage", Message.class); sendMessageMethod.setAccessible(true); } Message execJsMessage = Message.obtain(null, EXECUTE_JS, url); sendMessageMethod.invoke(webViewCore, execJsMessage);
四、Native註冊javascript接口 _cordovaNative
boolean isHoneycomb = (SDK_INT >= Build.VERSION_CODES.HONEYCOMB && SDK_INT <= Build.VERSION_CODES.HONEYCOMB_MR2); // Bug being that Java Strings do not get converted to JS strings automatically.This isn't hard to work-around on the JS side, but it's easier to just use the prompt bridge instead. if (isHoneycomb || (SDK_INT < Build.VERSION_CODES.GINGERBREAD)) { Log.i(TAG, "Disabled addJavascriptInterface() bridge since Android version is old."); return; } else if (SDK_INT < Build.VERSION_CODES.HONEYCOMB && Build.MANUFACTURER.equals("unknown")) { // addJavascriptInterface crashes on the 2.3 emulator. Log.i(TAG, "Disabled addJavascriptInterface() bridge callback due to a bug on the 2.3 emulator"); return; } this.addJavascriptInterface(exposedJsApi, "_cordovaNative");