最近接手到需要写一个安卓blockly的项目,要求20天左右输出一个集成blockly的项目,一脸懵逼,啥是blockly?
查阅相关资料,值得推荐资料:
https://www.bilibili.com/video/BV1ME411L7Xh?p=2 一个B站的教程,把安卓集成的过程都详细了说明,
https://github.com/MDKusester/study_blocklyAndroid 视屏配套的 demo
https://github.com/google/blockly-android 官方blockly demo 安卓版本2018年 已经停止维护
https://www.jianshu.com/p/a5d608538ef1 另一篇关于blockly的文章
全部找了一圈,关于安卓集成blockly的文章貌似是这几篇,其他的可能都已经是web方式集成了
本文集成的方式按照B站教程走,但是B站教程因为在js执行命令上 遇到if(函数)类型的复杂语句无法解析执行的问题,采用了xml方式去执行,然鹅在demo里面却没有开源xml'解析,时间紧迫任务重,只能逼着我重新用起我vue 里学的js功力去考虑解决。
//安卓java的代码 不懂的先看B站视频 @NonNull protected CodeGenerationRequest.CodeGeneratorCallback mCodeGeneratorCallback = new CodeGenerationRequest.CodeGeneratorCallback() { @Override public void onFinishCodeGeneration(String generatedCode) {//得到的blockly运行后的代码 Log.d(TAG, "得到的代码:\n" + generatedCode); final String code = generatedCode; mWebview.post(new Runnable() { @Override public void run() { String encoded = "Move.execute(" + JavascriptUtil.makeJsString(code) + ")"; mWebview.loadUrl("javascript:" + encoded); Log.d(TAG, "执行的代码:\n" + encoded); } }); } };js 的代码
/**
* Execute the user's code. Heaven help us...
*/
Move.execute = function(code) {
console.log(`js里面执行的代码开始------------------`);
console.log(code);inputCode = code
try {
eval(code);
} catch (e) {
// Null is thrown for infinite loop.
// Otherwise, abnormal termination is a user error.
if (e !== Infinity) {
alert(e);
}
}// Turtle.log now contains a transcript of all the user's actions.
// Reset the graphic and animate the transcript.
};
获得blockly的代码是
if (move.getCDS(1,500)) {
move.setLED(1,1);
} else {
move.setDcMotor(1,0,0);
}
js 里面执行的 eval(code);的时候,日志显示,执行了getCDS 还有执行了setDcMotor的两个方法。。。这个搞得我就有点懵逼了,为啥一下执行了两个方法,我就设法在js里面做阻断,如果有if和get类型的方法调用的时候,set类型的方法不执行,然后把单个指令和指令集发给java处理,再用处理完的结果去替换单个命令字符串,最后再把命令集再给eval再处理,如此循环,就能处理完所有blockly的模块
js方法 在eval之前把要执行的code赋值给inputCode move.getCDS= function(INport, midnum) { console.log(`js执行方法-------move.getCDS`); if (!move.isIncludeIf(inputCode)) { //判断code里面是否含有if语句 Move.getCDS(`getCDS(${INport},${midnum})\r\n`, "");//调用java的方法,第一个参数单个命令字符串,第二参数,整个输入命令 } else { Move.getCDS(`getCDS(${INport},${midnum})\r\n`, inputCode);//调用java的方法,第一个参数单个命令字符串,第二参数,整个输入命令 } };安卓java
@JavascriptInterface public synchronized void getCDS(final String command, final String procedureCode) { Log.d(TAG, "getCDSjava需要执行的命令~~~~: " + command); if (procedureCode.length() > 0) { Log.d(TAG, "getCDS还有要继续处理的代码段: " + procedureCode); } }
TODO 安卓去拿getCDS的结果返回后解析判断,如果是true|false,用这个去替代procedureCode中的command字符串,得到新的字符串再放到js eval(procedureCode)里处理,
这样可以处理单个if的情况,但是如果有多if情况就会有问题,处理起来比较繁琐。
继续观察数据,查资料 发现 执行了getCDS 还有执行了setDcMotor 是不是因为getCDS执行的时候没有返回值直接按照false处理。如果在blockly模块的if语句不放模块
if (false) {
move.setLED(1,1);
}
move.getCDS(1,1);
由此可以推出是否因为getCDS没有返回值,所以直接eval()认为是false所以执行了下面的getCDS,尝试在getCDS给上true的返回值,就可以正常控制if了,这个是一大进步嗄
因为是蓝牙调用getCDS,是否可以在这儿做阻断,等蓝牙处理好后再给出true或false给if里面呢,尝试给java里面一个阻断3s后再返回给js,如下代码
js代码 move.getCDS = function(status, threshold) { console.log(`js执行方法-------getCDS status=${status} threshold=${threshold}`); return Move.getCDS(`getCDS(${status},${threshold})\r\n`, ""); };安卓java代码
@JavascriptInterface public synchronized boolean getCDS(final int INport, final int midnum) { String command="getCDS("+INport+","+midnum+")";try{ Thread.sleep(300); }catch (InterruptedException e){ e.printStackTrace(); } return false; }
程序等待了3秒后再执行setLED方法,因为js是单线程的,再调用java到时候,java用的是js的线程,java去调用蓝牙的时候,就形成了阻塞,所以拆除掉js的控制,最终的代码
'use strict';
/**
* Execute the user's code. Heaven help us...
*/
move.execute = function(code) {
console.log(`js里面执行的代码开始------------------`);
console.log(code);
inputCode = code
try {
eval(code);
} catch (e) {
// Null is thrown for infinite loop.
// Otherwise, abnormal termination is a user error.
if (e !== Infinity) {
alert(e);
}
}
};
public class MoveInterface {
private Activity activity;
private String TAG = "FriendsInterface";
public FriendsInterface(Activity activity) {
this.activity = activity;
}
// 定义JS需要调用的方法
// 被JS调用的方法必须加入@JavascriptInterface注解
@JavascriptInterface
public void hello(String msg) {
Log.d(TAG, "JS调用了Android的hello方法");
}
@JavascriptInterface
public synchronized boolean getCDS(final int INport, final int midnum) {
String command="getCDS("+INport+","+midnum+")";
//去拿结果,给出判断
return true|false;
}
public synchronized int getCDS(final int INport, final int midnum) {
String command="getCDS("+INport+","+midnum+")";
//去拿结果,给出判断
int aaa=getCDSInt();
return aaa;
}
}
至此blockly的集成调用完成,目前测试所有blockly的语句都可以正常运行,B站的博主还没有联系,记录一下这个折腾摸索几天的过程