Native Bridge
// CordovaWebView.java
pluginManager = new PluginManager(this, this.cordova);
jsMessageQueue = new NativeToJsMessageQueue(this, cordova);
exposedJsApi = new ExposedJsApi(pluginManager, jsMessageQueue);
resourceApi = new CordovaResourceApi(this.getContext(), pluginManager);
exposeJsInterface();
// exposeJsInterface()
this.addJavascriptInterface(exposedJsApi, "_cordovaNative");
// similar in ActionScript
ExternalInterface.addCallback("say", this._say);
Prompt (2.3 simulator, 3.2-)
'cordova/android/promptbasednativeapi'
JS Object (addJavascriptInterface)
get NativeApi
nativeApiProvider = require('cordova/android/nativeapiprovider');
nativeApiProvider.get()
NativeApi Provider
var nativeApi = this._cordovaNative
|| require('cordova/android/promptbasednativeapi');
Location Change (CordovaWebViewClient)
This mode is currently for benchmarking purposes only
// NativeToJsMessageQueue.java
ENABLE_LOCATION_CHANGE_EXEC_MODE = true;
window.location = 'http://cdv_exec/'
+ service + '#' + action + '#'
+ callbackId + '#' + argsJson;
onJsPrompt
boolean reqOk = false;
if (url.startsWith("file://") || Config.isUrlWhiteListed(url)) {
reqOk = true;
}
// Synchronous: 'gap:*', 'gap_poll:', 'gap_init:'
String r = this.appView.exposedJsApi.exec(..); // -> PluginManager.exec()
result.confirm(r == null ? "" : r); // JsPromptResult
// Asynchronous: 'gap_bridge_mode:'
result.confirm(''); // JsPromptResult
// PluginManager.java
exec(..) -> app.sendPluginResult(..) -> CordovaWebView
// CordovaWebView.java
this.jsMessageQueue.addPluginResult(..) -> NativeToJsMessageQueue
// NativeToJsMessageQueue.java
[?BridgeMode].onNativeToJsMessageAvailable(..)
// make encoded JS
sb.append("window.setTimeout(function(){cordova.require('cordova/plugin/android/polling').pollOnce();},0);");
// OnlineEventsBridgeMode
webView.setNetworkAvailable(online);
// LoadUrlBridgeMode
webView.loadUrlNow("javascript:" + js);
// PrivateApiBridgeMode (Android 3.2.4+)
sendMessageMethod = webViewCore.getClass().getDeclaredMethod("sendMessage", Message.class);
sendMessageMethod.invoke(webViewCore, execJsMessage);
// This is called from the NativeToJsMessageQueue.java.
androidExec.processMessages = function(messages) {..};
OnlineEventsBridge - 'cordova/exec'
window.addEventListener('online', pollOnceFromOnlineEvent, false);
window.addEventListener('offline', pollOnceFromOnlineEvent, false);
function pollOnceFromOnlineEvent() {
pollOnce(true);
}
function pollOnce(opt_fromOnlineEvent) {
var msg = nativeApiProvider.get().retrieveJsMessages(!!opt_fromOnlineEvent);
androidExec.processMessages(msg);
}
function pollingTimerFunc() {
if (pollEnabled) {
pollOnce();
setTimeout(pollingTimerFunc, 50);
}
}
iFrame
nav (fastest)
var command = [callbackId, service, action, actionArgs];
commandQueue.push(JSON.stringify(command));
execIframe.src = "gap://ready";
hash
execHashIframe.contentWindow.location.hash = hashValue;
XMLHttpRequest (5.x)
execXhr.open('HEAD', "/!gap_exec?" + (+new Date()), true);
execXhr.setRequestHeader('cmds', iOSExec.nativeFetchMessages());
ViewController
// shouldStartLoadWithRequest:navigationType:
if ([[url scheme] isEqualToString:@"gap"]) {
[_commandQueue fetchCommandsFromJs];
[_commandQueue executePending];
return NO;
}
CommandQueue
- (void)fetchCommandsFromJs
{
NSString* queuedCommandsJSON = [_viewController.webView
stringByEvaluatingJavaScriptFromString:
@"cordova.require('cordova/exec').nativeFetchMessages()"];
}
Plugin
- (NSString*)writeJavascript:(NSString*)javascript
{
return [self.webView stringByEvaluatingJavaScriptFromString:javascript];
}
external.Notify()
var command = service + "/" + action + "/" + callbackId
+ "/" + JSON.stringify(args);
window.external.Notify(command);
ScriptNotify
void CordovaBrowser_ScriptNotify(object sender, NotifyEventArgs e)
{
..
}
NativeExecution
// NativeExecution.cs
private void InvokeScriptCallback(ScriptCallback script)
{
this.webBrowser.InvokeScript(script.ScriptName, script.Args);
}
WebBrowser
// WebBrowser.cs
public Object InvokeScript(String scriptName, params Object[] args)
{
..
}
XMLHttpRequest
Sync / Async
function RemoteFunctionCall(functionUri) {
..
function composeUri() {
return "http://localhost:8472/" + functionUri;
}
..
}
function createXhrRequest(uri, isAsync) {
..
request.open("POST", uri, isAsync);
request.setRequestHeader("Content-Type", "application/json");
..
}
response = JSON.parse(decodeURIComponent(request.responseText) || "null");
Native
webview.js
var requestObj = networkResourceRequested.createHandler(_webviewObj);
_webviewObj.onNetworkResourceRequested = requestObj.networkResourceRequestedHandler;
networkResourceRequested.js
module.exports = {
createHandler: function (webview) {
return new NetworkResourceRequestHandler(webview);
}
};
executeJavaScript
this.webview.executeJavaScript('');
PluginResult
var executeString = "cordova.callbackFromNative('" + callbackId + "', " +
!!success + ", " + status + ", [" + data + "], " + !!keepCallback + ");";
env.webview.executeJavaScript(executeString);
no Cordova API
Chrome / Safari / Firefox
open -a "Google Chrome.app" --args --disable-web-security --allow-file-access-from-files
F12 / Alt + Command + J
Apache Ripple™
npm install -g ripple-emulator
ripple emulate --path path/to/app
ripple emulate --remote http://mytest.com
adb logcat
adb logcat -s CordovaWebViewClient
DDMS (Dalvik Debug Monitor Service)
{Andriod SDK Home}/tools/monitor
Debug Target(phone) <=> Debug Server <=> Debug Client(PC)
WEb INspector REmote ['waɪnəri]
sudo npm -g install weinre
weinre --boundHost 192.168.1.2 --httpPort 8888
//192.168.1.2:8888/target/target-script-min.js
http://192.168.1.2:8888
http://debug.phonegap.com
bd
http://debug.phonegap.com/client/#bd
just for iOS 5.0 && 5.1
[NSClassFromString(@"WebView") _enableRemoteInspector];
Web debugging tool for iOS Simuator
基于新浪移动云的移动应用
PhoneGap 1.8-
支持版本不详
Preview & inspect web designs on devices
via `index.html` from local server
cordova run *** (platform)
but, doen't work (only iOS emulator)...