上一講將主體流程和架構都已經介紹完了,
再次查看整個代碼的時候,發現我還是有一些細節並沒有列舉出來,
例如之前只是介紹了addJavaScript一種方式實現通訊,實際上還有另一種通訊方式就是prompt方式,本講再次介紹一下。
prompt有幾個優勢:
1.可以避免掉android 4.2以下,js安全問題
2.可以實現同步調用,直接傳回值
下面開始分析代碼邏輯:
重複的位置,不再累述。直接來到cordova.js中
define("cordova/android/nativeapiprovider", function(require, exports, module) {var nativeApi = this._cordovaNative || require('cordova/android/promptbasednativeapi');//這裡其實如果沒有定義_cordovaNative就會走promptvar currentApi = nativeApi;module.exports = { get: function() { return currentApi; }, setPreferPrompt: function(value) { currentApi = value ? require('cordova/android/promptbasednativeapi') : nativeApi; }, // Used only by tests. set: function(value) { currentApi = value; }};});
而在使用prompt方式的時候,方法都是一樣的。
define("cordova/android/promptbasednativeapi", function(require, exports, module) {module.exports = { exec: function(bridgeSecret, service, action, callbackId, argsJson) { return prompt(argsJson, 'gap:'+JSON.stringify([bridgeSecret, service, action, callbackId]));//直接進入java端,程式碼片段1 }, setNativeToJsBridgeMode: function(bridgeSecret, value) { prompt(value, 'gap_bridge_mode:' + bridgeSecret); }, retrieveJsMessages: function(bridgeSecret, fromOnlineEvent) { return prompt(+fromOnlineEvent, 'gap_poll:' + bridgeSecret); }};});
程式碼片段1:SystemWebChromeClient.java
@Override public boolean onJsPrompt(WebView view, String origin, String message, String defaultValue, final JsPromptResult result) { // Unlike the @JavascriptInterface bridge, this method is always called on the UI thread. String handledRet = parentEngine.bridge.promptOnJsPrompt(origin, message, defaultValue);//程式碼片段2 if (handledRet != null) { result.confirm(handledRet); } else { dialogsHelper.showPrompt(message, defaultValue, new CordovaDialogsHelper.Result() { @Override public void gotResult(boolean success, String value) { if (success) { result.confirm(value); } else { result.cancel(); } } }); } return true; }
程式碼片段2:CordovaBridge.java
public String promptOnJsPrompt(String origin, String message, String defaultValue) { if (defaultValue != null && defaultValue.length() > 3 && defaultValue.startsWith("gap:")) { JSONArray array; try { array = new JSONArray(defaultValue.substring(4)); int bridgeSecret = array.getInt(0); String service = array.getString(1); String action = array.getString(2); String callbackId = array.getString(3); String r = jsExec(bridgeSecret, service, action, callbackId, message);//執行與之前介紹的邏輯一樣的流程中了 return r == null ? "" : r; } catch (JSONException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } return ""; } // Sets the native->JS bridge mode. else if (defaultValue != null && defaultValue.startsWith("gap_bridge_mode:")) { try { int bridgeSecret = Integer.parseInt(defaultValue.substring(16)); jsSetNativeToJsBridgeMode(bridgeSecret, Integer.parseInt(message)); } catch (NumberFormatException e){ e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } return ""; } // Polling for JavaScript messages else if (defaultValue != null && defaultValue.startsWith("gap_poll:")) { int bridgeSecret = Integer.parseInt(defaultValue.substring(9)); try { String r = jsRetrieveJsMessages(bridgeSecret, "1".equals(message)); return r == null ? "" : r; } catch (IllegalAccessException e) { e.printStackTrace(); } return ""; } else if (defaultValue != null && defaultValue.startsWith("gap_init:")) { // Protect against random iframes being able to talk through the bridge. // Trust only pages which the app would have been allowed to navigate to anyway. if (pluginManager.shouldAllowBridgeAccess(origin)) { // Enable the bridge int bridgeMode = Integer.parseInt(defaultValue.substring(9)); jsMessageQueue.setBridgeMode(bridgeMode); // Tell JS the bridge secret. int secret = generateBridgeSecret(); return ""+secret; } else { LOG.e(LOG_TAG, "gap_init called from restricted origin: " + origin); } return ""; } return null; }
到這裡整個流程又銜接上了,就不在廢話了