- 浏览: 3513693 次
- 性别:
- 来自: 大连
博客专栏
-
使用Titanium Mo...
浏览量:37477
-
Cordova 3.x入门...
浏览量:604281
-
常用Java开源Libra...
浏览量:678011
-
搭建 CentOS 6 服...
浏览量:87236
-
Spring Boot 入...
浏览量:399799
-
基于Spring Secu...
浏览量:69058
-
MQTT入门
浏览量:90460
文章分类
最新评论
-
afateg:
阿里云的图是怎么画出来的?用什么工具?
各云服务平台的架构图 -
cbn_1992:
博主,采用jdbctoken也就是数据库形式之后,反复点击获取 ...
Spring Security OAuth2 Provider 之 数据库存储 -
ipodao:
写的很是清楚了,我找到一份中文协议:https://mcxia ...
MQTT入门(6)- 主题Topics -
Cavani_cc:
还行
MQTT入门(6)- 主题Topics -
fexiong:
博主,能否提供完整源码用于学习?邮箱:2199611997@q ...
TensorFlow 之 构建人物识别系统
src/android/android/nativeapiprovider.js JS->Native的具体交互形式
src/android/android/promptbasednativeapi.js 通过prompt()和Native交互(Android2.3 simulator的Bug)
src/android/exec.js 执行JS->Native交互
// file: src/android/android/nativeapiprovider.js define("cordova/android/nativeapiprovider", function(require, exports, module) { // WebView中是否通过addJavascriptInterface提供了访问ExposedJsApi.java的_cordovaNative对象 // 如果不存在选择prompt()形式的交互方式 var nativeApi = this._cordovaNative || require('cordova/android/promptbasednativeapi'); var currentApi = nativeApi; module.exports = { // 获取当前交互方式 get: function() { return currentApi; }, // 设置使用prompt()交互方式 // (true:prompt false:自动选择) setPreferPrompt: function(value) { currentApi = value ? require('cordova/android/promptbasednativeapi') : nativeApi; }, // 直接设置交互方式对象(很少用到) set: function(value) { currentApi = value; } }; });
src/android/android/promptbasednativeapi.js 通过prompt()和Native交互(Android2.3 simulator的Bug)
// file: src/android/android/promptbasednativeapi.js define("cordova/android/promptbasednativeapi", function(require, exports, module) { // 由于Android2.3模拟器存在Bug,不支持addJavascriptInterface() // 所以借助prompt()来和Native进行交互 // Native端会在CordovaChromeClient.onJsPrompt()中拦截处理 module.exports = { // 调用Native API exec: function(service, action, callbackId, argsJson) { return prompt(argsJson, 'gap:'+JSON.stringify([service, action, callbackId])); }, // 设置Native->JS的桥接模式 setNativeToJsBridgeMode: function(value) { prompt(value, 'gap_bridge_mode:'); }, // 接收消息 retrieveJsMessages: function(fromOnlineEvent) { return prompt(+fromOnlineEvent, 'gap_poll:'); } }; });
src/android/exec.js 执行JS->Native交互
// file: src/android/exec.js define("cordova/exec", function(require, exports, module) { var cordova = require('cordova'), nativeApiProvider = require('cordova/android/nativeapiprovider'), utils = require('cordova/utils'), base64 = require('cordova/base64'), // JS->Native的可选交互形式一览 jsToNativeModes = { // 基于prompt()的交互 PROMPT: 0, // 基于JavascriptInterface的交互 JS_OBJECT: 1, // 基于URL的交互 // ***由于安全问题,默认已经设置成不可用的!!! // NativeToJsMessageQueue.ENABLE_LOCATION_CHANGE_EXEC_MODE=false LOCATION_CHANGE: 2 }, // Native->JS的可选交互形式一览 nativeToJsModes = { // 轮询(JS->Native自助获取消息) POLLING: 0, // 使用 webView.loadUrl("javascript:") 来执行消息 // 解决软键盘的Bug LOAD_URL: 1, // 拦截事件监听,使用online/offline事件来告诉JS获取消息 // 默认值 NativeToJsMessageQueue.DEFAULT_BRIDGE_MODE=2 ONLINE_EVENT: 2, // 反射Webview的私有API来执行JS(需要Android 3.2.4以上版本) PRIVATE_API: 3 }, // 当前JS->Native的交互形式 jsToNativeBridgeMode, // 当前Native->JS的交互形式 nativeToJsBridgeMode = nativeToJsModes.ONLINE_EVENT, pollEnabled = false, messagesFromNative = []; // 执行Cordova提供的API // 比如: exec(successCallback, errorCallback, "Camera", "takePicture", args); function androidExec(success, fail, service, action, args) { // 默认采用JavascriptInterface交互方式 if (jsToNativeBridgeMode === undefined) { androidExec.setJsToNativeBridgeMode(jsToNativeModes.JS_OBJECT); } // 如果参数中存在ArrayBuffer类型的参数,转化成字符串 for (var i = 0; i < args.length; i++) { if (utils.typeName(args[i]) == 'ArrayBuffer') { args[i] = base64.fromArrayBuffer(args[i]); } } var callbackId = service + cordova.callbackId++, // 把所有参数转换成JSON串 argsJson = JSON.stringify(args); // 设置回调函数 if (success || fail) { cordova.callbacks[callbackId] = {success:success, fail:fail}; } if (jsToNativeBridgeMode == jsToNativeModes.LOCATION_CHANGE) { // 基于URL的交互(需要手动修改NativeToJsMessageQueue.java的常量配置才能起效) // Native端会在CordovaWebViewClient.shouldOverrideUrlLoading()中拦截处理 window.location = 'http://cdv_exec/' + service + '#' + action + '#' + callbackId + '#' + argsJson; } else { // 选择合适的交互方式和Native进行交互 // 根据Native端NativeToJsMessageQueue.DISABLE_EXEC_CHAINING的配置,回传消息可以是同步或者异步 // 默认是同步的,返回PluginResult对象的JSON串。异步的话messages为空。 var messages = nativeApiProvider.get().exec(service, action, callbackId, argsJson); if (jsToNativeBridgeMode == jsToNativeModes.JS_OBJECT && messages === "@Null arguments.") { // 如果参数被传递到Java端,但是接收到的是null,切换交互方式到prompt()在执行一次 // Galaxy S2在传递某些Unicode字符的时候少数情况下有问题, // 参考 https://issues.apache.org/jira/browse/CB-2666 androidExec.setJsToNativeBridgeMode(jsToNativeModes.PROMPT); androidExec(success, fail, service, action, args); // 执行完成后,把交互方式再切回JavascriptInterface androidExec.setJsToNativeBridgeMode(jsToNativeModes.JS_OBJECT); return; } else { // 处理Native返回的消息 androidExec.processMessages(messages); } } } function pollOnceFromOnlineEvent() { pollOnce(true); } // 从Native的消息队列中获取消息 function pollOnce(opt_fromOnlineEvent) { var msg = nativeApiProvider.get().retrieveJsMessages(!!opt_fromOnlineEvent); androidExec.processMessages(msg); } function pollingTimerFunc() { if (pollEnabled) { pollOnce(); setTimeout(pollingTimerFunc, 50); } } function hookOnlineApis() { function proxyEvent(e) { cordova.fireWindowEvent(e.type); } window.addEventListener('online', pollOnceFromOnlineEvent, false); window.addEventListener('offline', pollOnceFromOnlineEvent, false); cordova.addWindowEventHandler('online'); cordova.addWindowEventHandler('offline'); document.addEventListener('online', proxyEvent, false); document.addEventListener('offline', proxyEvent, false); } // 添加online/offline事件 hookOnlineApis(); // 外部可以访问到交互方式的常量 androidExec.jsToNativeModes = jsToNativeModes; androidExec.nativeToJsModes = nativeToJsModes; // 设置JS->Native的交互方式 androidExec.setJsToNativeBridgeMode = function(mode) { // JavascriptInterface方式但是Native无法提供_cordovaNative对象的时候强制切到prompt() if (mode == jsToNativeModes.JS_OBJECT && !window._cordovaNative) { console.log('Falling back on PROMPT mode since _cordovaNative is missing. Expected for Android 3.2 and lower only.'); mode = jsToNativeModes.PROMPT; } nativeApiProvider.setPreferPrompt(mode == jsToNativeModes.PROMPT); jsToNativeBridgeMode = mode; }; // 设置Native->JS的交互方式 androidExec.setNativeToJsBridgeMode = function(mode) { if (mode == nativeToJsBridgeMode) { return; } // 如果以前是Poll的方式,,先回置到非Poll if (nativeToJsBridgeMode == nativeToJsModes.POLLING) { pollEnabled = false; } nativeToJsBridgeMode = mode; // 告诉Native端,JS端获取消息的方式 nativeApiProvider.get().setNativeToJsBridgeMode(mode); · // 如果是在JS端Poll的方式的话 if (mode == nativeToJsModes.POLLING) { pollEnabled = true; // 停顿后执行exec获取消息message setTimeout(pollingTimerFunc, 1); } }; // 处理从Native返回的一条消息 // // 回传消息的完整格式: // (1)消息的长度+空格+J+JavaScript代码 // 44 Jcordova.callbackFromNative('InAppBrowser1478332075',true,1,[{"type":"loadstop","url":"http:\/\/www.baidu.com\/"}],true}); // (2)消息的长度+空格+成功失败标示(J/S/F)+keepCallback标示+具体的状态码+空格+回调ID+空格+回传数据 // 78 S11 InAppBrowser970748887 {"type":"loadstop","url":"http:\/\/www.baidu.com\/"} // 28 S01 Notification970748888 n0 // // 默认是关闭了返回Js代码,使用返回数据。 // NativeToJsMessageQueue.FORCE_ENCODE_USING_EVAL=false function processMessage(message) { try { var firstChar = message.charAt(0); if (firstChar == 'J') { // 执行回传的JavaScript代码 eval(message.slice(1)); } else if (firstChar == 'S' || firstChar == 'F') { // S代表处理成功(包含没有数据),F代表处理失败 var success = firstChar == 'S'; var keepCallback = message.charAt(1) == '1'; var spaceIdx = message.indexOf(' ', 2); var status = +message.slice(2, spaceIdx); var nextSpaceIdx = message.indexOf(' ', spaceIdx + 1); var callbackId = message.slice(spaceIdx + 1, nextSpaceIdx); // 回传值类型 var payloadKind = message.charAt(nextSpaceIdx + 1); var payload; if (payloadKind == 's') { // 字符串:s+字符串 payload = message.slice(nextSpaceIdx + 2); } else if (payloadKind == 't') { // 布尔值:t/f payload = true; } else if (payloadKind == 'f') { // 布尔值:t/f payload = false; } else if (payloadKind == 'N') { // Null:N payload = null; } else if (payloadKind == 'n') { // 数值:n+具体值 payload = +message.slice(nextSpaceIdx + 2); } else if (payloadKind == 'A') { // ArrayBuffer:A+数据 var data = message.slice(nextSpaceIdx + 2); var bytes = window.atob(data); var arraybuffer = new Uint8Array(bytes.length); for (var i = 0; i < bytes.length; i++) { arraybuffer[i] = bytes.charCodeAt(i); } payload = arraybuffer.buffer; } else if (payloadKind == 'S') { // 二进制字符串:S+字符串 payload = window.atob(message.slice(nextSpaceIdx + 2)); } else { // JSON:JSON串 payload = JSON.parse(message.slice(nextSpaceIdx + 1)); } // 调用回调函数 cordova.callbackFromNative(callbackId, success, status, [payload], keepCallback); } else { console.log("processMessage failed: invalid message:" + message); } } catch (e) { console.log("processMessage failed: Message: " + message); console.log("processMessage failed: Error: " + e); console.log("processMessage failed: Stack: " + e.stack); } } // 处理Native返回的消息 androidExec.processMessages = function(messages) { // 如果消息存在的话(异步没有直接返回) if (messages) { // 把传入的消息放到数组中 messagesFromNative.push(messages); // messagesFromNative是全局的,而processMessages方法可重入, // 所以只需放到数组,后边循环处理即可 if (messagesFromNative.length > 1) { return; } // 遍历从Native获得所有消息 while (messagesFromNative.length) { // 处理完成后才可以从数组中删除 messages = messagesFromNative[0]; // Native返回星号代表消息需要等一会儿再取 if (messages == '*') { // 删除数组的第一个元素 messagesFromNative.shift(); // 再次去获取消息 window.setTimeout(pollOnce, 0); return; } // 获取消息的长度 var spaceIdx = messages.indexOf(' '); var msgLen = +messages.slice(0, spaceIdx); // 获取第一个消息 var message = messages.substr(spaceIdx + 1, msgLen); // 截取掉第一个消息 messages = messages.slice(spaceIdx + msgLen + 1); // 处理第一个消息 processMessage(message); // 如果消息包含多个,继续处理;单个的话删除本地消息数组中的数据 if (messages) { messagesFromNative[0] = messages; } else { messagesFromNative.shift(); } } } }; module.exports = androidExec; });
评论
2 楼
rensanning
2014-12-08
总的来说:在cordova.js里发给Webview的请求可以是同步或异步的,如果是同步的会返回PluginResult对象的JSON串,异步的返回空字符串。
源码里能看到nativeToJsModes有四种:POLLING,LOAD_URL,ONLINE_EVENT,PRIVATE_API,默认是ONLINE_EVENT。Java代码NativeToJsMessageQueue专门来处理JsMessage,通过激活online/offline事件来通知JS代码的调用,online事件也被注册为pollOnceFromOnlineEvent(),里边会poll一次Message从而获得执行结果。
如果使用POLL的话就是异步,需要你用JS timer来轮询结果。
源码里能看到nativeToJsModes有四种:POLLING,LOAD_URL,ONLINE_EVENT,PRIVATE_API,默认是ONLINE_EVENT。Java代码NativeToJsMessageQueue专门来处理JsMessage,通过激活online/offline事件来通知JS代码的调用,online事件也被注册为pollOnceFromOnlineEvent(),里边会poll一次Message从而获得执行结果。
如果使用POLL的话就是异步,需要你用JS timer来轮询结果。
1 楼
yijianpiaoxue2011
2014-12-08
楼主,你好:
拜读你的文章,受益良多,有个问题想请教一下,PluginManager.exec can be used either synchronously or async. 这是cordova对于插件的注释,楼组怎么理解,他是如何实现同步和异步的,望帮助解答,非常感谢。
拜读你的文章,受益良多,有个问题想请教一下,PluginManager.exec can be used either synchronously or async. 这是cordova对于插件的注释,楼组怎么理解,他是如何实现同步和异步的,望帮助解答,非常感谢。
发表评论
-
如何制作一个发布版的ionic应用?
2015-04-23 11:27 16725如何为Android APK签名,已经在这里说过了。这里说说如 ... -
Cordova各版本的不同
2015-04-12 17:26 31112Cordova每次大版本的发布都会带来系统架构很大的变化,很多 ... -
把CordovaWebView嵌入到自己的应用(Embedding WebViews)
2015-04-07 10:56 25053以下以Android为例。 (1)下载最新版的Cordova ... -
完整配置的Cordova-Phonegap-Ionic-Android环境
2015-01-22 17:01 9531搭建开发环境是程序员的基本功,虚拟机技术(VMware、Vir ... -
Cordova 3.x 入门 - 目录
2014-12-06 21:32 59234这个系列是基于Cordova 3. ... -
Awesome PhoneGap/Cordova
2014-12-03 22:23 3422A curated list of amazingly awe ... -
把Crosswalk打包到Cordova应用中
2014-10-09 16:02 4800(1)从Crosswalk官网下载Cordova Androi ... -
Eclipse开发ionic应用
2014-09-19 11:10 22066(1)首先下载最新版的Eclipse 4.4 (Luna) ... -
Cordova 3.x 实用插件(6) -- 检查APP是否被安装
2014-09-12 11:17 10000应用中经常要启动其他应用,比如:打开市场为自己的应用打分、强制 ... -
Cordova 3.x 实用插件(5) -- 通过自定义URL Scheme启动你的APP
2014-09-11 14:45 7446通过URL Scheme来启动APP是一种很常见的做法,比如: ... -
Cordova 3.x 实例开发 -- 基于Ionic的Todo应用
2014-05-27 13:04 31879基于Ionic的Todo应用,以下为Android截图,代码在 ... -
PhoneGap和Cordova的区别
2014-05-15 10:56 9963Cordova历史发展 ・2009年 通过iPhoneDevC ... -
Cordova Android中ShowTitle的问题
2014-04-28 13:34 3934根据官方文档的描述,要想显示TitleBar需要在config ... -
Cordova 3.x 源码分析(7) -- CordovaLib概要
2014-04-25 17:16 10191在http://rensanning.iteye.com/bl ... -
Cordova 3.x 源码分析(5) -- cordova.js导入、初始化、启动、加载插件
2014-04-22 16:44 27005执行cordova.js的入口就以下2行代码: // 导入co ... -
Cordova 3.x 源码分析(4) -- cordova.js事件通道pub/sub
2014-04-22 15:40 4251作为观察者模式(Observer)的一种变形,很多MV*框架( ... -
Cordova 3.x 源码分析(3) -- cordova.js模块系统require/define
2014-04-16 13:21 6443类似于Java的package/import,在JavaScr ... -
Cordova 3.x 源码分析(2) -- cordova.js概要
2014-04-16 13:14 11443前提环境: 引用Platform: android Versi ... -
Cordova 3.x 源码分析(1) -- Cordova CLI
2014-04-15 15:07 6145(1)Node.js的使用 Cordova CLI基于node ... -
Cordova 3.x 实用插件(4) -- Android的SEND、VIEW、CALL(WebIntent)
2014-04-09 16:20 6595插件地址:https://github.com/Initsog ...
相关推荐
一个 Cordova 插件,用于使用 NativeScript 调用任何本机 API。 目前仅支持 iOS。 安装 科尔多瓦插件添加 在 iOS 上,元数据生成脚本必须在编译应用程序和部署到设备之间运行。 after-compile 钩子对此不起作用,...
键盘cordova.plugins.Keyboard对象提供了使与键盘的交互更容易的函数,并触发事件以指示键盘将隐藏/显示。 cordova plugin add com.ionic.keyboard方法cordova.plugins.Keyboard.hideKeyboardAccessoryBar cordova....
cordova自定义插件,实现toast,jar包的调用(利于对第三方jar包调用的理解),native与js的交互,实现android与js的信息回调。
cordova自定义插件,实现toast,jar包的调用(利于对第三方jar包调用的理解),native与js的交互,实现android与js的信息回调。
X5Bridge X5Bridge Android本机和JavaScript之间的桥梁的库Google本机具有一组通信,实际上,它也可以完成回调交互i X5Bridge X5Bridge Android本机和JavaScript之间的桥梁的库一组通信,实际上,它也可以完成回调...
因为项目使用了Cordova,也使用了很长时间。至于有很多hybride框架,为什么我们使用Cordova,这里不做过多的叙述,我们也是根据项目需求来选定的,需要及时更新、还要输出别人...核心的东西就是H5与Native的交互原理、
本地化 English: https://github.com/unruledboy/WebFrontEndStack/ 中文博客: http://www.cnblogs.com/unruledboy/p/WebFrontEndStack.html Español: ...
LDJSBridge_IOS的核心目标是完成在IOS客户端中WAP页面和客户端(Native)的深度交互。 如何集成LDJSBridge_IOS 强烈推荐采用Pod集成:在项目工程的Podfile文件中加载LDJSBridge库: pod 'LDJSBridge' :git => '...
在这本书中,作者可能会介绍一些跨平台开发框架或工具,如PhoneGap(现在称为Apache Cordova)或React Native等,这些工具允许开发者使用HTML、CSS和JavaScript等Web技术来构建原生移动应用程序。它们通过将Web内容...
会话存储) 性能关键型应用cordova / phonegap移动应用程序,您可以在其中利用javascript的功能并避免与本机数据库进行交互数据集加载到浏览器页面中并在工作会话结束时进行同步节点Webkit桌面应用程序nativescript...
主要是针对原生和h5 js的交互,最原始的方式进行交互,这种方式也是为了后来的跨平台webjavascritbridge 和cordova 做了铺垫
LDJSBridge_Android =============== LDJSBridge_Android的核心目标是完成在Android客户端中WAP页面和客户端...本LDJSBridge_IOS是基于Phonegap的Cordova引擎的基础上简化而来, Android平台Webview和JS的交互方式共有