在导师的帮助下,我终于看懂了一点QC啦!
QC是一个利用JS与java相互调用的框架。他的好处在于你可以不用android的UI显示界面,用js来显示界面。
这个框架是用来扩展你的js调用android系统功能的,说白了就是可以从js端直接调用android的功能,方便大家一起扩展js调用java的功能。其实质就是android端在调用相应API来完成一些功能,只不过与js之间相互交换一些参数罢了。
怎样在QC中扩展自己的功能
JS端 asset文件夹
1.发送请求handleRequest('browseFileJS','/sdcard/');
这个函数是开始执行框架的入口函数。handleRequest()的第一个参数是命令,第二个参数是命令的参数,即发送给java端BCO.java与VCO.java的参数。
2.asset/mappings.js
框架启动时会首先在mappings.js中映射JS端的请求命令与BCF与VCF函数进行映射
mapCommandToBCF('browseFileJS',changeTextBCF);
mapCommandToVCF('browseFileJS',changeTextVCF);
这两句话要在你发送JS请求命令之前写上。即你要在发送JS请求命令之前要把命令跟相关的BCF与VCF映射好,不然在你发送命令的时候,框架找不到相应的调用函数
3.asset/ function.js
这个js文件中写你自己的BCF与VCF函数
function browseFileBCF(parameters){
//parameters是你从JS端发送请求时附带的参数
pg_log.Debug("function.js:[browseFileBCF]");
browseFile(parameters);
document.getElementById('coco').innerText = '/sdcard/';
}
function browseFileVCF(data, param){
//data[0]是你从java端的VCO.java中的JSONArray中push进的第一个参数,即你要从java端返回给JS端的参数。
//param是你从JS端发送请求时附带的参数,与BCF中的parameters是同一个值
pg_log.Debug("function.js:[browseFileVCF]");
var returnFromJavaToJs=data[0];
var p2=param;
var s=new String();
for(var i=0;i<returnFromJavaToJs.length;i++){
var f=returnFromJavaToJs[i];
s=s+'/n'+f.type+' '+f.name;
}
document.getElementById('coco').innerText =p2+s;
}
4.asset/ QCAndroid/com.js
这个js文件中是写你自定义BCF与VCF函数需要调用到的函数。你也可以往这个js文件中写函数,直接在BCF与VCF函数中完成你想写的功能
function browseFile(parameters){
var dataArray = new Array();
var callBackParameters = generatePassThroughParameters();
dataArray.push(parameters);
dataArray.push(callBackParameters);
var dataString = JSON.stringify(dataArray);
pg_log.Debug("com.js:[browseFile]:"+dataString);
makeCall("browseFileJava", dataString);
return null;
}
1)有关回调函数VCF地址
generatePassThroughParameters()函数返回你自定义的VCF函数的回调地址。这个框架是这么个流程。从handleRequest发送命令与参数给Java端开始。js端调用BCF函数,BCF发送命令与参数给Java端,并且把VCF的回调地址也带给java端。然后java端调用BCO.java的handleIt()函数,BCO.java再把返回结果与原始参数传递给VCO.java函数,然后VCO.java把需要返回给JS端的参数和js端传递过来的VCF函数的回调地址再传回给JS端。
我开始也很奇怪为什么VCF回调函数的地址要传给Java又传回JS。
在导师的说明下,我明白啦!
这个框架中,一个是发送的装配车间,一个是回收结果的装配车间。即装配BCF与VCF。
当出装配车间的时候,他可以直接装配出 回调函数(参数) ,而不用再去很麻烦的去找对应的回调函数地址。因为这在之前已经map过acmd与VCF了。有人说,在之前map,与出装配车间后再map有什么区别呢。可能是为了框架的工整性着想。因为一气儿把BCF与VCF全部map完了就显得整个框架很工整,容易懂。不然某个地方map BCF,某个地方map VCF ,会造成混乱。
2)有关makeCall("browseFileJava", dataString)
我们来看下makeCall函数定义
asset/QCAndroid/com.js
function makeCall(command, dataString){
if(command){
qcDevice.makeCall(command, dataString);
}
}
我们来看下Java端怎样向JS端嵌入对象
org.quick.connect/QuickConnectActivity.java
webView.addJavascriptInterface(new JavaScriptCallHandler(), "qcDevice");
//将JavaScriptCallHandler.java对象绑定到JS端,并且这个对象命名为"qcDevice"
webView.loadUrl("file:///android_asset/index.html");
//加载asset文件中的html网页
3)有关传递 参数的顺序问题
asset/QCAndroid/com.js
function browseFile(parameters){
var dataArray = new Array() ;
var callBackParameters = generatePassThroughParameters();
dataArray.push(parameters);
dataArray.push(callBackParameters);
var dataString = JSON.stringify(dataArray);
makeCall("browseFileJava", dataString);
}
将要附带的参数与回调地址的参数分别放到Array中,然后转换成JSON字符串,再传递给Java端就可以了。
参数顺序可以自己调整,只要你传递到Java端的BCO中或者VCO中,你自己可以对上号就可以了。
即JS端发送的是Array,Java端的BCO.java接收的是JSONArray。这两端相互对应。
public class BrowseFileBCO implements CommandObject {
public Object handleIt(Object parameters) {
Log.d("coco", "ChangeTextBCO parameters : "+parameters);
Object fromJSParameters=null;
try {
fromJSParameters=((JSONArray)parameters ).get(0);
...
}
JAVA端 src文件夹
1.org.quick.connect/QCCommandMappings.java
Java端启动时首先也会做Java端的命令与相应BCO.java与VCO.java的映射
QCUtilities.mapCommandToBCO("browseFileJava", BrowseFileBCO.class);
QCUtilities.mapCommandToVCO("browseFileJava", BrowseFileVCO.class);
2.org.quick.connect.commandobjects/
写上自己的BCO.java与VCO.java文件,注意要实现CommandObject接口
public class BrowseFileBCO implements CommandObject {
public Object handleIt(Object parameters) {
Log.d("coco", "ChangeTextBCO parameters : "+parameters);
Object fromJSParameters=null;
try {
fromJSParameters=((JSONArray)parameters).get(0);
} catch (JSONException e) {
e.printStackTrace();
}
String fromJSString=(String)fromJSParameters;
JSONArray resultFileLists=FileOperation.getFiles_JSONArray(fromJSString);
return resultFileLists;
}
}
public class BrowseFileVCO implements CommandObject{
public Object handleIt(Object parameters) {
Log.d("coco", "ChangeTextVCO.handleIt( "+parameters+" )");
String callbackVCFAddr=null;
try {
callbackVCFAddr = (String)((JSONArray)((JSONArray)((ArrayList)parameters).get(0)).get(1)).get(0);
} catch (JSONException e) {
e.printStackTrace();
}
Object fromJavaBCOParams=((ArrayList)parameters).get(1);
JSONArray fromJavaBCOJSONArray=(JSONArray)fromJavaBCOParams;
String toJSString="Java get from JS : "+fromJavaBCOJSONArray.toString();
Log.d("coco", "ChangeTextVCO toJSString : "+toJSString);
JSONArray returnValues = new JSONArray();
returnValues.put(fromJavaBCOJSONArray);
returnValues.put(callbackVCFAddr);
String aJSONString = returnValues.toString();
String aJSCallString = "javascript:handleRequestCompletionFromNative('"+aJSONString+"')";
Log.d("coco", "ChangeTextVCO-aJSONString: "+aJSONString);
QuickConnectActivity.getWebView().loadUrl(aJSCallString);
return toJSString;
}
}
3.有关BCO与VCO的参数传递问题
1)BCO.java的参数
public Object handleIt(Object parameters) {}
这里的parameters是JSONArray。他与JS端的makeCall(command, dataString)中的dataString对应。dataString前身就是Array。
所以说Java中的JSONArray与JS端的Array对应。往数组里面写回调函数的地址和其他附带参数是可以在两端协商的,只要两端对应好了就可以了。
但是注意,也就是在后面的VCO中,回调函数的地址是必须写在JSONArray的最后一个的。这个是框架规定。
2)BCO.java返回的参数怎样传递给VCO.java
org.quick.connect/
public class QuickConnect {
public static Object handleRequest(String command, Object parameters){
Object retVal = null;
if(checkValidation(command, parameters)){
ArrayList newParameters = dispatchToBCO(command, parameters);
retVal = dispatchToVCO(command, newParameters);
...}
private static ArrayList<Object> dispatchToHandlers(HashMap<String, ArrayList<Class> > map, String command, Object parameters){
ArrayList<Object> resultData = new ArrayList<Object>();
resultData.add(parameters);
try {
result = ((CommandObject)handler).handleIt(parameters);
}...
if(result != null){
resultData.add(result);
}
return resultData;
...}
}
看到了吗,将BCO.java返回的参数添加到ArrayList的第二个成员中,然后将ArrayList当做参数传递给VCO.java。
即VCO.java的handleIt()参数是ArrayList。ArrayList第一个成员是BCO.java从JS端接收的JSONArray请求参数,ArrayList第二个成员是BCO.java的handleIt()函数返回的参数。
3)VCO.java怎样返回给JS端参数,以及怎样跳回JS端
public class BrowseFileVCO implements CommandObject{
public Object handleIt(Object parameters) {
...
String callbackVCFAddr=null;
try {
callbackVCFAddr = (String)((JSONArray)((JSONArray)((ArrayList)parameters).get(0)).get(1)).get(0);
}
...
JSONArray returnValues = new JSONArray();
returnValues.put(fromJavaBCOJSONArray);
returnValues.put(callbackVCFAddr);
String aJSONString = returnValues.toString();
String aJSCallString = "javascript:handleRequestCompletionFromNative('"+aJSONString+"')";
Log.d("coco", "ChangeTextVCO-aJSONString: "+aJSONString);
QuickConnectActivity.getWebView().loadUrl(aJSCallString);
...}
}
返回的JSONArray一定要这么写,第一个成员是你要返回的参数,第二个成员是回调函数VCF的地址。
我在JSONArray中的第二个成员也就是回调地址之前添加了一个成员。在VCF端,也做了相应的修改,但是调试的结果显示的是,找不到回调函数。如果发现可以修改返回的JSONArray,可以给我留言,我们交流一下哦。
4)JS端VCF接收Java端VCO.java传过来的参数
function browseFileVCF(data, param){
//data[0]是你从java端的VCO.java中的JSONArray中push进的第一个参数,即你要从java端返回给JS端的参数。
//param是你从JS端发送请求时附带的参数,与BCF中的parameters是同一个值
var returnFromJavaToJs=data[0];
var p2=param;
var s=new String();
for(var i=0;i<returnFromJavaToJs.length;i++){
var f=returnFromJavaToJs[i];
s=s+'/n'+f.type+' '+f.name;
}
document.getElementById('coco').innerText =p2+s;
}
//data[0]是你从java端的VCO.java中的JSONArray中push进的第一个参数,即你要从java端返回给JS端的参数。
只有data[0]可以提取出来。也就是说你所有的从Java端VCO.java返回的参数只能存在于JSONArray的第一个成员中。第一个成员你可以写成JSONArray的形式在存放各种参数,然后从VCF中data[0]就是这个JSONArray
如果有同学发现可以写到data[1]中,欢迎给我留言或者加QQ讨论哈。