- 浏览: 3545997 次
- 性别:
- 来自: 大连
博客专栏
-
使用Titanium Mo...
浏览量:38096
-
Cordova 3.x入门...
浏览量:607094
-
常用Java开源Libra...
浏览量:682038
-
搭建 CentOS 6 服...
浏览量:89204
-
Spring Boot 入...
浏览量:401676
-
基于Spring Secu...
浏览量:69652
-
MQTT入门
浏览量:91647
文章分类
最新评论
-
afateg:
阿里云的图是怎么画出来的?用什么工具?
各云服务平台的架构图 -
cbn_1992:
博主,采用jdbctoken也就是数据库形式之后,反复点击获取 ...
Spring Security OAuth2 Provider 之 数据库存储 -
ipodao:
写的很是清楚了,我找到一份中文协议:https://mcxia ...
MQTT入门(6)- 主题Topics -
Cavani_cc:
还行
MQTT入门(6)- 主题Topics -
fexiong:
博主,能否提供完整源码用于学习?邮箱:2199611997@q ...
TensorFlow 之 构建人物识别系统
执行cordova.js的入口就以下2行代码:
src/cordova.js 事件的处理和回调,外部访问cordova.js的入口
其中第一步是加载整个模块系统和外部访问cordova.js的入口,基于事件通道提供了整体的事件拦截控制及回调。代码不是很复杂。
源码:
src/common/init.js 初始化处理
第二步是就是执行初始化处理
源码:
src/android/platform.js 平台启动处理
源码:
src/common/pluginloader.js 加载所有cordova_plugins.js中定义的模块,执行完成后会触发onPluginsReady
// 导入cordova window.cordova = require('cordova'); // 启动处理 require('cordova/init');
src/cordova.js 事件的处理和回调,外部访问cordova.js的入口
其中第一步是加载整个模块系统和外部访问cordova.js的入口,基于事件通道提供了整体的事件拦截控制及回调。代码不是很复杂。
源码:
// file: src/cordova.js define("cordova", function(require, exports, module) { // 调用通道和平台模块 var channel = require('cordova/channel'); var platform = require('cordova/platform'); // 备份document和window的事件监听器 var m_document_addEventListener = document.addEventListener; var m_document_removeEventListener = document.removeEventListener; var m_window_addEventListener = window.addEventListener; var m_window_removeEventListener = window.removeEventListener; // 保存自定义的document和window的事件监听器 var documentEventHandlers = {}, windowEventHandlers = {}; // 拦截document和window的事件监听器(addEventListener/removeEventListener) // 存在自定义的事件监听器的话,使用自定义的;不存在的话调用备份document和window的事件监听器 document.addEventListener = function(evt, handler, capture) { var e = evt.toLowerCase(); if (typeof documentEventHandlers[e] != 'undefined') { documentEventHandlers[e].subscribe(handler); } else { m_document_addEventListener.call(document, evt, handler, capture); } }; window.addEventListener = function(evt, handler, capture) { var e = evt.toLowerCase(); if (typeof windowEventHandlers[e] != 'undefined') { windowEventHandlers[e].subscribe(handler); } else { m_window_addEventListener.call(window, evt, handler, capture); } }; document.removeEventListener = function(evt, handler, capture) { var e = evt.toLowerCase(); if (typeof documentEventHandlers[e] != "undefined") { documentEventHandlers[e].unsubscribe(handler); } else { m_document_removeEventListener.call(document, evt, handler, capture); } }; window.removeEventListener = function(evt, handler, capture) { var e = evt.toLowerCase(); if (typeof windowEventHandlers[e] != "undefined") { windowEventHandlers[e].unsubscribe(handler); } else { m_window_removeEventListener.call(window, evt, handler, capture); } }; // 创建一个指定type的事件。 // 参考:https://developer.mozilla.org/en-US/docs/Web/API/document.createEvent#Notes function createEvent(type, data) { var event = document.createEvent('Events'); // 指定事件名、不可冒泡、不可取消 event.initEvent(type, false, false); // 自定义数据 if (data) { for (var i in data) { if (data.hasOwnProperty(i)) { event[i] = data[i]; } } } return event; } // 外部访问cordova.js的入口 var cordova = { // 模块系统 define:define, require:require, // 版本号和平台名 version:CORDOVA_JS_BUILD_LABEL, platformId:platform.id, // 为了拦截document和window的事件监听器,添加或删除自定义的事件监听器 addWindowEventHandler:function(event) { return (windowEventHandlers[event] = channel.create(event)); }, // sticky 是指一旦被调用那么它以后都保持被调用的状态,所定义的监听器会被立即执行。 // 比如: deviceready事件只触发一次,以后的所有监听都是立即执行的。 addStickyDocumentEventHandler:function(event) { return (documentEventHandlers[event] = channel.createSticky(event)); }, addDocumentEventHandler:function(event) { return (documentEventHandlers[event] = channel.create(event)); }, removeWindowEventHandler:function(event) { delete windowEventHandlers[event]; }, removeDocumentEventHandler:function(event) { delete documentEventHandlers[event]; }, // 获取拦截前的document和window的事件监听器 getOriginalHandlers: function() { return {'document': {'addEventListener': m_document_addEventListener, 'removeEventListener': m_document_removeEventListener}, 'window': {'addEventListener': m_window_addEventListener, 'removeEventListener': m_window_removeEventListener}}; }, // 调用document的事件 fireDocumentEvent: function(type, data, bNoDetach) { var evt = createEvent(type, data); if (typeof documentEventHandlers[type] != 'undefined') { // 判断是否需要抛出事件异常 if( bNoDetach ) { // 通过Channel的fire方法来调用事件(apply) documentEventHandlers[type].fire(evt); } else { // setTimeout(callback, 0) 的意思是DOM构成完毕、事件监听器执行完后立即执行 setTimeout(function() { // 调用加载cordova.js之前定义的那些deviceready事件 if (type == 'deviceready') { document.dispatchEvent(evt); } // 通过Channel的fire方法来调用事件(apply) documentEventHandlers[type].fire(evt); }, 0); } } else { // 直接调用事件 document.dispatchEvent(evt); } }, // 调用window的事件 fireWindowEvent: function(type, data) { var evt = createEvent(type,data); if (typeof windowEventHandlers[type] != 'undefined') { setTimeout(function() { windowEventHandlers[type].fire(evt); }, 0); } else { window.dispatchEvent(evt); } }, // 插件回调相关------------------------------------- // 回调ID中间的一个随机数(真正的ID:插件名+随机数) callbackId: Math.floor(Math.random() * 2000000000), // 回调函数对象,比如success,fail callbacks: {}, // 回调状态 callbackStatus: { NO_RESULT: 0, OK: 1, CLASS_NOT_FOUND_EXCEPTION: 2, ILLEGAL_ACCESS_EXCEPTION: 3, INSTANTIATION_EXCEPTION: 4, MALFORMED_URL_EXCEPTION: 5, IO_EXCEPTION: 6, INVALID_ACTION: 7, JSON_EXCEPTION: 8, ERROR: 9 }, // 以后使用callbackFromNative代替callbackSuccess和callbackError callbackSuccess: function(callbackId, args) { try { cordova.callbackFromNative(callbackId, true, args.status, [args.message], args.keepCallback); } catch (e) { console.log("Error in error callback: " + callbackId + " = "+e); } }, callbackError: function(callbackId, args) { try { cordova.callbackFromNative(callbackId, false, args.status, [args.message], args.keepCallback); } catch (e) { console.log("Error in error callback: " + callbackId + " = "+e); } }, // 调用回调函数 callbackFromNative: function(callbackId, success, status, args, keepCallback) { var callback = cordova.callbacks[callbackId]; // 判断是否定义了回调函数 if (callback) { if (success && status == cordova.callbackStatus.OK) { // 调用success函数 callback.success && callback.success.apply(null, args); } else if (!success) { // 调用fail函数 callback.fail && callback.fail.apply(null, args); } // 如果设置成不再保持回调,删除回调函数对象 if (!keepCallback) { delete cordova.callbacks[callbackId]; } } }, // 没有地方用到! // 目的是把你自己的函数在注入到Cordova的生命周期中。 addConstructor: function(func) { channel.onCordovaReady.subscribe(function() { try { func(); } catch(e) { console.log("Failed to run constructor: " + e); } }); } }; module.exports = cordova; });
src/common/init.js 初始化处理
第二步是就是执行初始化处理
源码:
// file: src/common/init.js define("cordova/init", function(require, exports, module) { var channel = require('cordova/channel'); var cordova = require('cordova'); var modulemapper = require('cordova/modulemapper'); var platform = require('cordova/platform'); var pluginloader = require('cordova/pluginloader'); // 定义平台初期化处理必须在onNativeReady和onPluginsReady之后进行 var platformInitChannelsArray = [channel.onNativeReady, channel.onPluginsReady]; // 输出事件通道名到日志 function logUnfiredChannels(arr) { for (var i = 0; i < arr.length; ++i) { if (arr[i].state != 2) { console.log('Channel not fired: ' + arr[i].type); } } } // 5秒之后deviceready事件还没有被调用将输出log提示 // 出现这个错误的情况比较复杂,比如,加载的plugin太多等等 window.setTimeout(function() { if (channel.onDeviceReady.state != 2) { console.log('deviceready has not fired after 5 seconds.'); logUnfiredChannels(platformInitChannelsArray); logUnfiredChannels(channel.deviceReadyChannelsArray); } }, 5000); // 替换window.navigator function replaceNavigator(origNavigator) { // 定义新的navigator,把navigator的原型链赋给新的navigator的原型链 var CordovaNavigator = function() {}; CordovaNavigator.prototype = origNavigator; var newNavigator = new CordovaNavigator(); // 判断是否存在Function.bind函数 if (CordovaNavigator.bind) { for (var key in origNavigator) { if (typeof origNavigator[key] == 'function') { // 通过bind创建一个新的函数(this指向navigator)后赋给新的navigator // 参考:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind newNavigator[key] = origNavigator[key].bind(origNavigator); } } } return newNavigator; } // 替换webview的BOM对象navigator // Cordova提供的接口基本都是:navigator.<plugin_name>.<action_name> if (window.navigator) { window.navigator = replaceNavigator(window.navigator); } // 定义console.log() if (!window.console) { window.console = { log: function(){} }; } // 定义console.warn() if (!window.console.warn) { window.console.warn = function(msg) { this.log("warn: " + msg); }; } // 注册pause,resume,deviceready事件通道,并应用到Cordova自定义的事件拦截 // 这样页面定义的事件监听器就能订阅到相应的通道上了。 channel.onPause = cordova.addDocumentEventHandler('pause'); channel.onResume = cordova.addDocumentEventHandler('resume'); channel.onDeviceReady = cordova.addStickyDocumentEventHandler('deviceready'); // 如果此时DOM加载完成,触发onDOMContentLoaded事件通道中的事件处理 if (document.readyState == 'complete' || document.readyState == 'interactive') { channel.onDOMContentLoaded.fire(); } else { // 如果此时DOM没有加载完成,定义一个监听器在DOM完成后触发事件通道的处理 // 注意这里调用的webview的原生事件监听 document.addEventListener('DOMContentLoaded', function() { channel.onDOMContentLoaded.fire(); }, false); } // 以前版本是在CordovaLib中反向执行js把_nativeReady设置成true后触发事件通道 // 现在已经改成在平台启动处理中立即触发 // 参考:https://issues.apache.org/jira/browse/CB-3066 if (window._nativeReady) { channel.onNativeReady.fire(); } // 给常用的模块起个别名 // 比如:就可以直接使用cordova.exec(...)来代替var exec = require('cordova/exec'); exec(...); // 不过第一行第二个参数应该是“Cordova”,c应该大写!!! modulemapper.clobbers('cordova', 'cordova'); modulemapper.clobbers('cordova/exec', 'cordova.exec'); modulemapper.clobbers('cordova/exec', 'Cordova.exec'); // 调用平台初始化启动处理 platform.bootstrap && platform.bootstrap(); // 所有插件加载完成后,触发onPluginsReady事件通道中的事件处理 pluginloader.load(function() { channel.onPluginsReady.fire(); }); // 一旦本地代码准备就绪,创建cordova所需的所有对象 channel.join(function() { // 把所有模块附加到window对象上 modulemapper.mapModules(window); // 如果平台有特殊的初始化处理,调用它(目前来看都没有) platform.initialize && platform.initialize(); // 触发onCordovaReady事件通道,标示cordova准备完成 channel.onCordovaReady.fire(); // 一切准备就绪后,执行deviceready事件通道上的所有事件。 channel.join(function() { require('cordova').fireDocumentEvent('deviceready'); }, channel.deviceReadyChannelsArray); // onCordovaReady、onDOMContentLoaded }, platformInitChannelsArray); // onNativeReady、onPluginsReady });
src/android/platform.js 平台启动处理
源码:
// file: src/android/platform.js define("cordova/platform", function(require, exports, module) { module.exports = { id: 'android', // 平台启动处理(各个平台处理都不一样,比如ios就只需要触发onNativeReady) bootstrap: function() { var channel = require('cordova/channel'), cordova = require('cordova'), exec = require('cordova/exec'), modulemapper = require('cordova/modulemapper'); // 把exec()的执行从WebCore线程变到UI线程上来 // 后台PluginManager初始化的时候默认添加了一个'PluginManager的插件 exec(null, null, 'PluginManager', 'startup', []); // 触发onNativeReady事件通道,告诉JS本地代码已经完成 channel.onNativeReady.fire(); // app插件。现在没有被单独抽出去,没找到合适的地方。 modulemapper.clobbers('cordova/plugin/android/app', 'navigator.app'); // 给返回按钮注意个监听器 var backButtonChannel = cordova.addDocumentEventHandler('backbutton'); backButtonChannel.onHasSubscribersChange = function() { // 如果只为返回按钮定义了1个事件监听器的话,通知后台覆盖默认行为 exec(null, null, "App", "overrideBackbutton", [this.numHandlers == 1]); }; // 添加菜单和搜素的事件监听 cordova.addDocumentEventHandler('menubutton'); cordova.addDocumentEventHandler('searchbutton'); // 启动完成后,告诉本地代码显示WebView channel.onCordovaReady.subscribe(function() { exec(null, null, "App", "show", []); }); } }; });
src/common/pluginloader.js 加载所有cordova_plugins.js中定义的模块,执行完成后会触发onPluginsReady
// file: src/common/pluginloader.js define("cordova/pluginloader", function(require, exports, module) { var modulemapper = require('cordova/modulemapper'); var urlutil = require('cordova/urlutil'); // 创建<script>tag,把js文件动态添加到head中 function injectScript(url, onload, onerror) { var script = document.createElement("script"); script.onload = onload; script.onerror = onerror || onload; // 出错的时候也执行onload处理 script.src = url; document.head.appendChild(script); } // 加载到head中的插件js脚本定义如下: // cordova.define("org.apache.cordova.xxx", function(require, exports, module) { ... }); // 模块名称是cordova_plugins.js中定义的id,所以要把该id指向定义好的clobbers function onScriptLoadingComplete(moduleList, finishPluginLoading) { for (var i = 0, module; module = moduleList[i]; i++) { if (module) { try { // 把该模块需要clobber的clobber到指定的clobbers里 if (module.clobbers && module.clobbers.length) { for (var j = 0; j < module.clobbers.length; j++) { modulemapper.clobbers(module.id, module.clobbers[j]); } } // 把该模块需要合并的部分合并到指定的模块里 if (module.merges && module.merges.length) { for (var k = 0; k < module.merges.length; k++) { modulemapper.merges(module.id, module.merges[k]); } } // 处理只希望require()的模块 // <js-module src="www/xxx.js" name="Xxx"> // <runs /> // </js-module> if (module.runs && !(module.clobbers && module.clobbers.length) && !(module.merges && module.merges.length)) { modulemapper.runs(module.id); } } catch(err) { } } } // 插件js脚本加载完成后,执行回调!!! finishPluginLoading(); } // 加载所有cordova_plugins.js中定义的js-module function handlePluginsObject(path, moduleList, finishPluginLoading) { var scriptCounter = moduleList.length; // 没有插件,直接执行回调后返回 if (!scriptCounter) { finishPluginLoading(); return; } // 加载每个插件js的脚本的回调 function scriptLoadedCallback() { // 加载完成一个就把计数器减1 if (!--scriptCounter) { // 直到所有插件的js脚本都被加载完成后clobber onScriptLoadingComplete(moduleList, finishPluginLoading); } } // 依次把插件的js脚本添加到head中后加载 for (var i = 0; i < moduleList.length; i++) { injectScript(path + moduleList[i].file, scriptLoadedCallback); } } // 注入插件的js脚本 function injectPluginScript(pathPrefix, finishPluginLoading) { var pluginPath = pathPrefix + 'cordova_plugins.js'; // 根据cordova.js文件的路径首先把cordova_plugins.js添加到head中后加载 injectScript(pluginPath, function() { try { // 导入cordova_plugins.jsz中定义的'cordova/plugin_list'模块 // 这个文件的内容是根据所有插件的plugin.xml生成的。 var moduleList = require("cordova/plugin_list"); // 加载所有cordova_plugins.js中定义的js-module handlePluginsObject(pathPrefix, moduleList, finishPluginLoading); } catch (e) { // 忽略cordova_plugins.js记载失败、或者文件不存在等错误 finishPluginLoading(); } }, finishPluginLoading); } // 获取cordova.js文件的路径 function findCordovaPath() { var path = null; var scripts = document.getElementsByTagName('script'); var term = 'cordova.js'; for (var n = scripts.length-1; n>-1; n--) { var src = scripts[n].src; if (src.indexOf(term) == (src.length - term.length)) { path = src.substring(0, src.length - term.length); break; } } return path; } // 加载所有cordova_plugins.js中定义的js-module // 执行完成后会触发onPluginsReady(异步执行) exports.load = function(callback) { // 取cordova.js文件所在的路径 var pathPrefix = findCordovaPath(); if (pathPrefix === null) { console.log('Could not find cordova.js script tag. Plugin loading may fail.'); pathPrefix = ''; } // 注入插件的js脚本,执行完成后回调onPluginsReady injectPluginScript(pathPrefix, callback); }; });
发表评论
-
如何制作一个发布版的ionic应用?
2015-04-23 11:27 16797如何为Android APK签名,已经在这里说过了。这里说说如 ... -
Cordova各版本的不同
2015-04-12 17:26 31220Cordova每次大版本的发布都会带来系统架构很大的变化,很多 ... -
把CordovaWebView嵌入到自己的应用(Embedding WebViews)
2015-04-07 10:56 25140以下以Android为例。 (1)下载最新版的Cordova ... -
完整配置的Cordova-Phonegap-Ionic-Android环境
2015-01-22 17:01 9614搭建开发环境是程序员的基本功,虚拟机技术(VMware、Vir ... -
Cordova 3.x 入门 - 目录
2014-12-06 21:32 59422这个系列是基于Cordova 3. ... -
Awesome PhoneGap/Cordova
2014-12-03 22:23 3491A curated list of amazingly awe ... -
把Crosswalk打包到Cordova应用中
2014-10-09 16:02 4860(1)从Crosswalk官网下载Cordova Androi ... -
Eclipse开发ionic应用
2014-09-19 11:10 22129(1)首先下载最新版的Eclipse 4.4 (Luna) ... -
Cordova 3.x 实用插件(6) -- 检查APP是否被安装
2014-09-12 11:17 10075应用中经常要启动其他应用,比如:打开市场为自己的应用打分、强制 ... -
Cordova 3.x 实用插件(5) -- 通过自定义URL Scheme启动你的APP
2014-09-11 14:45 7577通过URL Scheme来启动APP是一种很常见的做法,比如: ... -
Cordova 3.x 实例开发 -- 基于Ionic的Todo应用
2014-05-27 13:04 32122基于Ionic的Todo应用,以下为Android截图,代码在 ... -
PhoneGap和Cordova的区别
2014-05-15 10:56 10017Cordova历史发展 ・2009年 通过iPhoneDevC ... -
Cordova Android中ShowTitle的问题
2014-04-28 13:34 3984根据官方文档的描述,要想显示TitleBar需要在config ... -
Cordova 3.x 源码分析(7) -- CordovaLib概要
2014-04-25 17:16 10280在http://rensanning.iteye.com/bl ... -
Cordova 3.x 源码分析(6) -- cordova.js本地交互JS<->Native
2014-04-24 12:11 15750src/android/android/nativeapipr ... -
Cordova 3.x 源码分析(4) -- cordova.js事件通道pub/sub
2014-04-22 15:40 4310作为观察者模式(Observer)的一种变形,很多MV*框架( ... -
Cordova 3.x 源码分析(3) -- cordova.js模块系统require/define
2014-04-16 13:21 6502类似于Java的package/import,在JavaScr ... -
Cordova 3.x 源码分析(2) -- cordova.js概要
2014-04-16 13:14 11523前提环境: 引用Platform: android Versi ... -
Cordova 3.x 源码分析(1) -- Cordova CLI
2014-04-15 15:07 6219(1)Node.js的使用 Cordova CLI基于node ... -
Cordova 3.x 实用插件(4) -- Android的SEND、VIEW、CALL(WebIntent)
2014-04-09 16:20 6652插件地址:https://github.com/Initsog ...
相关推荐
当应用启动时,`cordova.js`首先处理初始化工作。它会监听页面加载事件,当DOM加载完成后,它会触发`deviceready`事件。这是开发者可以开始调用Cordova API的信号,表明Cordova环境已经准备好。 2. `deviceready`...
**Cordova 3.x 实例开发 -- 基于Ionic的Todo应用** Cordova是一款开源的移动应用开发框架,它允许开发者使用Web技术(HTML、CSS、JavaScript)来构建原生的移动应用。Cordova 3.x是其早期的一个版本,尽管现在已...
这篇名为“Cordova 3.x 源码分析(7) -- CordovaLib概要”的博客文章深入探讨了Cordova的核心组件——CordovaLib。CordovaLib是Cordova项目的基础库,包含了实现Cordova功能的各种模块和插件,如设备API、生命周期...
Cordova 3.x 是一个流行的开源框架,用于构建原生移动应用,利用HTML、CSS和JavaScript等Web技术。它允许开发者使用一套统一的API来访问设备功能,如摄像头、GPS和 accelerometer,从而创建跨平台的应用程序。在...
Cordova 3.x 是一个流行的开源框架,它允许开发者使用Web技术(如HTML5、CSS3和JavaScript)来构建原生移动应用。这个框架通过桥接技术将Web应用与设备的API连接,使得Web开发者可以访问手机的各种功能,如摄像头、...
热更新时,我们执行命令 npm install -g cordova-hot-code-push-cli安装插件,但运行cordova-hcp server会报错,如:Could not create tunnel: { Error: ngrok is not yet ready to start tunnels...,这时我们找到...
实实在在经过ant编译的cordova-2.9.1.jar 而不是有些人坑蒙拐骗的rar文件
Apache Cordova 3.x 是一个跨平台的移动应用开发框架,允许开发者使用标准的Web技术,如HTML5、CSS3和JavaScript,来构建原生的移动应用。在本主题中,我们将深入探讨Cordova 3.x的基础知识,包括其工作原理、安装与...
Cordova 3.x 是一个非常重要的版本,它是Apache Cordova框架的一个里程碑,它为移动应用开发者提供了跨平台的HTML5、CSS3和JavaScript开发能力。Cordova的核心理念是利用Web技术构建原生移动应用,通过插件系统桥接...
Cordova 3.x入门教程是针对移动应用开发的框架,它允许开发者使用Web技术(HTML5、CSS3、JavaScript)来构建跨平台的移动应用程序。Cordova的核心理念是将Web应用封装在原生的移动应用壳中,使得Web应用能够访问设备...
**Cordova 3.x 基础:Native API的使用** Cordova,作为一个开源的移动应用开发框架,允许开发者使用Web技术(HTML5、CSS3、JavaScript)来构建跨平台的移动应用程序。在Cordova 3.x版本中,开发者可以通过其提供的...
Cordova 3.x 实用插件(2) -- 二维码Barcode Cordova 是一个流行的开源框架,用于构建原生移动应用程序,它允许开发者使用Web技术(HTML、CSS和JavaScript)来开发跨平台的应用。在Cordova 3.x版本中,开发者可以...
这篇博客“Cordova 3.x 实用插件(4) -- Android的SEND、VIEW、CALL(WebIntent)”主要探讨了如何在Android平台上利用Cordova插件来实现发送数据、查看内容和拨打电话的功能。 **发送数据(SEND)** 在Android中...