Cordova android框架詳解

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");

 
相關文章
相關標籤/搜索