mirror of
https://github.com/TonyJiangWJ/Auto.js.git
synced 2026-06-24 21:33:16 +08:00
p7zip支持以及添加OCR、p7zip的API及示例文件
This commit is contained in:
parent
375ad67239
commit
c4e7a1a810
36
app/src/main/assets/sample/7zip/7zip压缩.js
Normal file
36
app/src/main/assets/sample/7zip/7zip压缩.js
Normal file
@ -0,0 +1,36 @@
|
||||
//目录路径(必须是完整路径)
|
||||
var dirPath = "/sdcard/脚本/";
|
||||
if(!files.isDir(dirPath)) files.create(dirPath);
|
||||
//压缩文件路径(必须是完整路径)
|
||||
var filePath = "/sdcard/脚本.7z";
|
||||
//压缩类型
|
||||
//支持的压缩类型包括:zip 7z bz2 bzip2 tbz2 tbz gz gzip tgz tar wim swm xz txz。
|
||||
var type = "7z";
|
||||
//压缩密码
|
||||
var password = "password"
|
||||
|
||||
//7z加密压缩(若文件已存在则跳过)
|
||||
//zips.A(type, filePath, dirPath, password)
|
||||
|
||||
//压缩
|
||||
switch (zips.A(type, filePath, dirPath)) {
|
||||
case 0:
|
||||
toastLog("压缩成功!文件已保存为: " + filePath)
|
||||
break;
|
||||
case 1:
|
||||
toastLog("压缩结束,存在非致命错误(例如某些文件正在被使用,没有被压缩)")
|
||||
break;
|
||||
case 2:
|
||||
toastLog("致命错误")
|
||||
break;
|
||||
case 7:
|
||||
toastLog("命令行错误")
|
||||
break;
|
||||
case 8:
|
||||
toastLog("没有足够内存")
|
||||
break;
|
||||
case 255:
|
||||
toastLog("用户中止操作")
|
||||
break;
|
||||
default: toastLog("未知错误")
|
||||
}
|
||||
BIN
app/src/main/assets/sample/7zip/bonus.rar
Normal file
BIN
app/src/main/assets/sample/7zip/bonus.rar
Normal file
Binary file not shown.
33
app/src/main/assets/sample/7zip/rar解压缩.js
Normal file
33
app/src/main/assets/sample/7zip/rar解压缩.js
Normal file
@ -0,0 +1,33 @@
|
||||
//压缩文件路径(必须是完整路径)
|
||||
var filePath = files.path("./bonus.rar");
|
||||
//目录路径(必须是完整路径)
|
||||
var dirPath = "/sdcard/脚本";
|
||||
//压缩密码
|
||||
var password = "password"
|
||||
|
||||
//支持的解压缩类型包括:zip、7z、bz2、bzip2、tbz2、tbz、gz、gzip、tgz、tar、wim、swm、xz、txz以及rar、chm、iso、msi等众多格式。
|
||||
//解压无加密的压缩包(若文件已存在则跳过)
|
||||
//zips.X(filePath, dirPath)
|
||||
|
||||
//解压加密的压缩包(若文件已存在则跳过)
|
||||
switch (zips.X(filePath, dirPath, password)) {
|
||||
case 0:
|
||||
toastLog("解压缩成功!请到 " + dirPath + " 目录下查看。")
|
||||
break;
|
||||
case 1:
|
||||
toastLog("压缩结束,存在非致命错误(例如某些文件正在被使用,没有被压缩)")
|
||||
break;
|
||||
case 2:
|
||||
toastLog("致命错误")
|
||||
break;
|
||||
case 7:
|
||||
toastLog("命令行错误")
|
||||
break;
|
||||
case 8:
|
||||
toastLog("没有足够内存")
|
||||
break;
|
||||
case 255:
|
||||
toastLog("用户中止操作")
|
||||
break;
|
||||
default: toastLog("未知错误")
|
||||
}
|
||||
19
app/src/main/assets/sample/OCR/OCR.js
Normal file
19
app/src/main/assets/sample/OCR/OCR.js
Normal file
@ -0,0 +1,19 @@
|
||||
const img = images.read("./test.png");
|
||||
const cpuThreadNum = 4;
|
||||
// PaddleOCR 移动端提供了两种模型:ocr_v2_for_cpu与ocr_v2_for_cpu(slim),此选项用于选择加载的模型,默认true使用v2的slim版(速度更快),false使用v2的普通版(准确率更高)
|
||||
var useSlim = true;
|
||||
// 识别图片中的文字,返回完整识别信息(兼容百度OCR格式)。
|
||||
const result = ocr.R(img, cpuThreadNum, useSlim);
|
||||
// 可以使用简化的调用命令,默认参数:cpuThreadNum = 4, useSlim = true;
|
||||
// const result = ocr.R(img);
|
||||
toastLog("完整识别信息(兼容百度OCR格式): " + JSON.stringify(result));
|
||||
|
||||
// 识别图片中的文字,只返回文本识别信息(字符串列表)。
|
||||
const stringList = ocr.T(img, cpuThreadNum, useSlim);
|
||||
// 可以使用简化的调用命令,默认参数:cpuThreadNum = 4, useSlim = true;
|
||||
// const stringList = ocr.T(img);
|
||||
toastLog("文本识别信息(字符串列表): " + JSON.stringify(stringList));
|
||||
// 释放模型 用于释放native内存
|
||||
ocr.release()
|
||||
// 回收图片
|
||||
img.recycle()
|
||||
2
autojs-aar/p7zip/build.gradle
Normal file
2
autojs-aar/p7zip/build.gradle
Normal file
@ -0,0 +1,2 @@
|
||||
configurations.maybeCreate("default")
|
||||
artifacts.add("default", file('libp7zip-1.7.2.aar'))
|
||||
BIN
autojs-aar/p7zip/libp7zip-1.7.2.aar
Normal file
BIN
autojs-aar/p7zip/libp7zip-1.7.2.aar
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -57,7 +57,8 @@ public class OCRPredictorNative {
|
||||
|
||||
}
|
||||
|
||||
public void destory(){
|
||||
// 原代码中该方法名为“destory()”,此处应该是拼写错误,其它类中调用此方法的名称也已修正
|
||||
public void destroy(){
|
||||
if (nativePointer != 0) {
|
||||
release(nativePointer);
|
||||
nativePointer = 0;
|
||||
@ -105,6 +106,6 @@ public class OCRPredictorNative {
|
||||
@Override
|
||||
protected void finalize() throws Throwable {
|
||||
super.finalize();
|
||||
destory();
|
||||
destroy();
|
||||
}
|
||||
}
|
||||
|
||||
@ -2,11 +2,16 @@ package com.baidu.paddle.lite.ocr;
|
||||
|
||||
import android.graphics.Point;
|
||||
import android.graphics.Rect;
|
||||
import android.os.Parcelable;
|
||||
|
||||
public class OcrResult {
|
||||
public float confidence;
|
||||
public float preprocessTime;
|
||||
public float inferenceTime;
|
||||
public String words;
|
||||
public Rect bounds;
|
||||
public RectLocation location;
|
||||
private String label;
|
||||
private float confidence;
|
||||
private Rect bounds;
|
||||
|
||||
public OcrResult() {
|
||||
}
|
||||
@ -61,4 +66,18 @@ public class OcrResult {
|
||||
public void setBounds(Rect bounds) {
|
||||
this.bounds = bounds;
|
||||
}
|
||||
|
||||
public static class RectLocation {
|
||||
public int left;
|
||||
public int top;
|
||||
public int width;
|
||||
public int height;
|
||||
|
||||
public RectLocation(int left, int top, int width, int height) {
|
||||
this.left = left;
|
||||
this.top = top;
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -7,6 +7,7 @@ import android.graphics.Color;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.Path;
|
||||
import android.graphics.Point;
|
||||
import android.graphics.Rect;
|
||||
import android.util.Log;
|
||||
|
||||
import java.io.File;
|
||||
@ -42,6 +43,7 @@ public class Predictor {
|
||||
protected volatile String outputResult = "";
|
||||
protected float preprocessTime = 0;
|
||||
protected float postprocessTime = 0;
|
||||
protected boolean useSlim = true;;
|
||||
|
||||
|
||||
public Predictor() {
|
||||
@ -140,7 +142,7 @@ public class Predictor {
|
||||
|
||||
public void releaseModel() {
|
||||
if (paddlePredictor != null) {
|
||||
paddlePredictor.destory();
|
||||
paddlePredictor.destroy();
|
||||
paddlePredictor = null;
|
||||
}
|
||||
isLoaded = false;
|
||||
@ -434,4 +436,126 @@ public class Predictor {
|
||||
}
|
||||
}
|
||||
|
||||
public boolean init(Context appCtx, boolean useSlim) {
|
||||
if (!this.isLoaded || (this.useSlim != useSlim)) {
|
||||
loadLabel(appCtx, "labels/ppocr_keys_v1.txt");
|
||||
if (useSlim) {
|
||||
loadModel(appCtx, "models/ocr_v2_for_cpu(slim)", 4, "LITE_POWER_HIGH");
|
||||
} else {
|
||||
loadModel(appCtx, "models/ocr_v2_for_cpu", 4, "LITE_POWER_HIGH");
|
||||
}
|
||||
}
|
||||
this.isLoaded = true;
|
||||
this.useSlim = useSlim;
|
||||
Log.i(TAG, "isLoaded: " + this.isLoaded);
|
||||
return this.isLoaded;
|
||||
}
|
||||
|
||||
public List<OcrResult> transformData(List<OcrResultModel> OcrResultModelList) {
|
||||
if (OcrResultModelList == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
List<OcrResult> words_result = new ArrayList<>();
|
||||
for (OcrResultModel model : OcrResultModelList) {
|
||||
List<Point> pointList = model.getPoints();
|
||||
if (pointList.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
Point firstPoint = pointList.get(0);
|
||||
int left = firstPoint.x;
|
||||
int top = firstPoint.y;
|
||||
int right = firstPoint.x;
|
||||
int bottom = firstPoint.y;
|
||||
for (Point p : pointList) {
|
||||
if (p.x < left) {
|
||||
left = p.x;
|
||||
}
|
||||
if (p.x > right) {
|
||||
right = p.x;
|
||||
}
|
||||
if (p.y < top) {
|
||||
top = p.y;
|
||||
}
|
||||
if (p.y > bottom) {
|
||||
bottom = p.y;
|
||||
}
|
||||
}
|
||||
OcrResult ocrResult = new OcrResult();
|
||||
ocrResult.preprocessTime = preprocessTime;
|
||||
ocrResult.inferenceTime = inferenceTime;
|
||||
ocrResult.confidence = model.getConfidence();
|
||||
ocrResult.words = model.getLabel().trim().replace("\r", "");
|
||||
ocrResult.location = new OcrResult.RectLocation(left, top, Math.abs(right - left), Math.abs(bottom - top));
|
||||
ocrResult.bounds = new Rect(left, top, right, bottom);
|
||||
words_result.add(ocrResult);
|
||||
}
|
||||
return words_result;
|
||||
}
|
||||
|
||||
public List<OcrResult> ocr(Bitmap inputImage, int cpuThreadNum) {
|
||||
this.cpuThreadNum = cpuThreadNum;
|
||||
if (inputImage == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
// Pre-process image, and feed input tensor with pre-processed data
|
||||
Bitmap scaleImage = Utils.resizeWithStep(inputImage, Long.valueOf(inputShape[2]).intValue(), 32);
|
||||
Date start = new Date();
|
||||
int channels = (int) inputShape[1];
|
||||
int width = scaleImage.getWidth();
|
||||
int height = scaleImage.getHeight();
|
||||
float[] inputData = new float[channels * width * height];
|
||||
if (channels == 3) {
|
||||
int[] channelIdx = null;
|
||||
if (inputColorFormat.equalsIgnoreCase("RGB")) {
|
||||
channelIdx = new int[]{0, 1, 2};
|
||||
} else if (inputColorFormat.equalsIgnoreCase("BGR")) {
|
||||
channelIdx = new int[]{2, 1, 0};
|
||||
} else {
|
||||
Log.i(TAG, "Unknown color format " + inputColorFormat + ", only RGB and BGR color format is " +
|
||||
"supported!");
|
||||
return Collections.emptyList();
|
||||
}
|
||||
int[] channelStride = new int[]{width * height, width * height * 2};
|
||||
int[] pixels = new int[width * height];
|
||||
scaleImage.getPixels(pixels, 0, scaleImage.getWidth(), 0, 0, scaleImage.getWidth(), scaleImage.getHeight());
|
||||
for (int i = 0; i < pixels.length; i++) {
|
||||
int color = pixels[i];
|
||||
float[] rgb = new float[]{(float) red(color) / 255.0f, (float) green(color) / 255.0f,
|
||||
(float) blue(color) / 255.0f};
|
||||
inputData[i] = (rgb[channelIdx[0]] - inputMean[0]) / inputStd[0];
|
||||
inputData[i + channelStride[0]] = (rgb[channelIdx[1]] - inputMean[1]) / inputStd[1];
|
||||
inputData[i + channelStride[1]] = (rgb[channelIdx[2]] - inputMean[2]) / inputStd[2];
|
||||
}
|
||||
} else if (channels == 1) {
|
||||
int[] pixels = new int[width * height];
|
||||
scaleImage.getPixels(pixels, 0, scaleImage.getWidth(), 0, 0, scaleImage.getWidth(), scaleImage.getHeight());
|
||||
for (int i = 0; i < pixels.length; i++) {
|
||||
int color = pixels[i];
|
||||
float gray = (float) (red(color) + green(color) + blue(color)) / 3.0f / 255.0f;
|
||||
inputData[i] = (gray - inputMean[0]) / inputStd[0];
|
||||
}
|
||||
} else {
|
||||
Log.i(TAG, "Unsupported channel size " + Integer.toString(channels) + ", only channel 1 and 3 is " +
|
||||
"supported!");
|
||||
return Collections.emptyList();
|
||||
}
|
||||
float[] pixels = inputData;
|
||||
Log.i(TAG, "pixels " + pixels[0] + " " + pixels[1] + " " + pixels[2] + " " + pixels[3]
|
||||
+ " " + pixels[pixels.length / 2] + " " + pixels[pixels.length / 2 + 1] + " " + pixels[pixels.length - 2] + " " + pixels[pixels.length - 1]);
|
||||
Date end = new Date();
|
||||
preprocessTime = (float) (end.getTime() - start.getTime());
|
||||
|
||||
// Warm up
|
||||
for (int i = 0; i < warmupIterNum; i++) {
|
||||
paddlePredictor.runImage(inputData, width, height, channels, inputImage);
|
||||
}
|
||||
warmupIterNum = 0; // do not need warm
|
||||
// Run inference
|
||||
start = new Date();
|
||||
ArrayList<OcrResultModel> results = paddlePredictor.runImage(inputData, width, height, channels, inputImage);
|
||||
end = new Date();
|
||||
inferenceTime = (float) (end.getTime() - start.getTime());
|
||||
results = postprocess(results);
|
||||
return transformData(results);
|
||||
}
|
||||
}
|
||||
|
||||
@ -75,6 +75,7 @@ dependencies {
|
||||
api project(path: ':autojs-aar:term')
|
||||
api project(path: ':autojs-aar:rhino-jdk7')
|
||||
api project(path: ':autojs-aar:paddleocr')
|
||||
api project(path: ':autojs-aar:p7zip')
|
||||
api project(path: ':common')
|
||||
api project(path: ':automator')
|
||||
implementation 'com.rmtheis:tess-two:9.1.0'
|
||||
|
||||
@ -141,5 +141,7 @@ module.exports = function(runtime, global){
|
||||
return buildTypes.release;
|
||||
}
|
||||
|
||||
global.zips = Object.create(runtime.zips);
|
||||
global.ocr = Object.create(runtime.ocr);
|
||||
|
||||
}
|
||||
@ -32,8 +32,10 @@ import com.stardust.autojs.runtime.api.Files;
|
||||
import com.stardust.autojs.runtime.api.Floaty;
|
||||
import com.stardust.autojs.runtime.api.Images;
|
||||
import com.stardust.autojs.runtime.api.Media;
|
||||
import com.stardust.autojs.runtime.api.OCR;
|
||||
import com.stardust.autojs.runtime.api.Plugins;
|
||||
import com.stardust.autojs.runtime.api.Sensors;
|
||||
import com.stardust.autojs.runtime.api.SevenZip;
|
||||
import com.stardust.autojs.runtime.api.Threads;
|
||||
import com.stardust.autojs.runtime.api.Timers;
|
||||
import com.stardust.autojs.runtime.api.UI;
|
||||
@ -193,6 +195,12 @@ public class ScriptRuntime {
|
||||
@ScriptVariable
|
||||
public final Plugins plugins;
|
||||
|
||||
@ScriptVariable
|
||||
public SevenZip zips;
|
||||
|
||||
@ScriptVariable
|
||||
public OCR ocr;
|
||||
|
||||
private Images images;
|
||||
|
||||
private static WeakReference<Context> applicationContext;
|
||||
@ -224,6 +232,8 @@ public class ScriptRuntime {
|
||||
files = new Files(this);
|
||||
media = new Media(context, this);
|
||||
plugins = new Plugins(context, this);
|
||||
zips = new SevenZip();
|
||||
ocr = new OCR();
|
||||
}
|
||||
|
||||
public void init() {
|
||||
|
||||
@ -0,0 +1,77 @@
|
||||
package com.stardust.autojs.runtime.api;
|
||||
|
||||
import android.graphics.Bitmap;
|
||||
import android.os.Looper;
|
||||
import android.util.Log;
|
||||
|
||||
import com.baidu.paddle.lite.ocr.OcrResult;
|
||||
import com.baidu.paddle.lite.ocr.Predictor;
|
||||
import com.stardust.app.GlobalAppContext;
|
||||
import com.stardust.autojs.core.image.ImageWrapper;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class OCR {
|
||||
|
||||
private Predictor mPredictor = new Predictor();
|
||||
|
||||
public synchronized boolean init(boolean useSlim) {
|
||||
if (!mPredictor.isLoaded) {
|
||||
if (Looper.getMainLooper() == Looper.myLooper()) {
|
||||
new Thread(() -> {
|
||||
mPredictor.init(GlobalAppContext.get(), useSlim);
|
||||
}).start();
|
||||
} else {
|
||||
mPredictor.init(GlobalAppContext.get(), useSlim);
|
||||
}
|
||||
}
|
||||
return mPredictor.isLoaded;
|
||||
}
|
||||
|
||||
public void release() {
|
||||
mPredictor.releaseModel();
|
||||
}
|
||||
|
||||
public List<OcrResult> R(ImageWrapper image, int cpuThreadNum, boolean useSlim) {
|
||||
if (image == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
Bitmap bitmap = image.getBitmap();
|
||||
if (bitmap == null || bitmap.isRecycled()) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
init(useSlim);
|
||||
return mPredictor.ocr(bitmap, cpuThreadNum);
|
||||
}
|
||||
|
||||
public List<OcrResult> R(ImageWrapper image, int cpuThreadNum) {
|
||||
return R(image, cpuThreadNum, true);
|
||||
}
|
||||
|
||||
public List<OcrResult> R(ImageWrapper image) {
|
||||
return R(image, 4, true);
|
||||
}
|
||||
|
||||
public String[] T(ImageWrapper image, int cpuThreadNum, boolean useSlim) {
|
||||
List<OcrResult> words_result = R(image, cpuThreadNum, useSlim);
|
||||
String[] outputResult = new String[words_result.size()];
|
||||
for (int i = 0; i < words_result.size(); i++) {
|
||||
outputResult[i] = words_result.get(i).words;
|
||||
Log.i("outputResult", outputResult[i].toString()); // show LOG in Logcat panel
|
||||
}
|
||||
return outputResult;
|
||||
}
|
||||
|
||||
public String[] T(ImageWrapper image, int cpuThreadNum) {
|
||||
return T(image, cpuThreadNum, true);
|
||||
}
|
||||
|
||||
public String[] T(ImageWrapper image) {
|
||||
return T(image, 4, true);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -0,0 +1,88 @@
|
||||
package com.stardust.autojs.runtime.api;
|
||||
|
||||
import com.hzy.libp7zip.P7ZipApi;
|
||||
import com.stardust.autojs.runtime.exception.ScriptException;
|
||||
import com.stardust.pio.PFiles;
|
||||
|
||||
|
||||
public class SevenZip {
|
||||
public int cmdExec(String cmdStr) {
|
||||
try {
|
||||
return P7ZipApi.executeCommand(cmdStr);
|
||||
} catch (Exception e) {
|
||||
throw new ScriptException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public int A(String type, String destFilePath, String srcPath) {
|
||||
String typeOption = "";
|
||||
if (!type.trim().isEmpty()) {
|
||||
typeOption = " -t" + type.trim();
|
||||
}
|
||||
String cmdStr = "7z";
|
||||
if (PFiles.isFile(srcPath)) {
|
||||
cmdStr = "7z a -y" + typeOption + " -ms=off -mx=1 -mmt " + destFilePath + " " + srcPath;
|
||||
} else if (PFiles.isDir(srcPath)) {
|
||||
cmdStr = "7z a -y" + typeOption + " -ms=off -mx=1 -mmt -r " + destFilePath + " " + srcPath;
|
||||
}
|
||||
try {
|
||||
return P7ZipApi.executeCommand(cmdStr);
|
||||
} catch (Exception e) {
|
||||
throw new ScriptException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public int A(String type, String destFilePath, String srcPath, String password) {
|
||||
String typeOption = "";
|
||||
if (!type.trim().isEmpty()) {
|
||||
typeOption = " -t" + type.trim();
|
||||
}
|
||||
String cmdStr = "7z";
|
||||
if (PFiles.isFile(srcPath)) {
|
||||
cmdStr = "7z a -y" + typeOption + " -ms=off -mx=1 -mmt -p" + password + " " + destFilePath + " " + srcPath;
|
||||
} else if (PFiles.isDir(srcPath)) {
|
||||
cmdStr = "7z a -y" + typeOption + " -ms=off -mx=1 -mmt -r -p" + password + " " + destFilePath + " " + srcPath;
|
||||
}
|
||||
try {
|
||||
return P7ZipApi.executeCommand(cmdStr);
|
||||
} catch (Exception e) {
|
||||
throw new ScriptException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public int X(String filePath0, String dirPath1) {
|
||||
String cmdStr = "7z x -y -aos " + filePath0;
|
||||
if (PFiles.isFile(filePath0)) {
|
||||
if (PFiles.isDir(dirPath1)) {
|
||||
cmdStr = "7z x -y -aos -o" + dirPath1 + " " + filePath0 + "";
|
||||
} else {
|
||||
cmdStr = "7z x -y -aos " + filePath0 + "";
|
||||
}
|
||||
}
|
||||
try {
|
||||
return P7ZipApi.executeCommand(cmdStr);
|
||||
} catch (Exception e) {
|
||||
throw new ScriptException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public int X(String filePath0, String dirPath1, String password) {
|
||||
String cmdStr = "7z x -y -aos " + filePath0 + "";
|
||||
if (password == "") {
|
||||
X(filePath0, dirPath1);
|
||||
} else {
|
||||
if (PFiles.isFile(filePath0)) {
|
||||
if (PFiles.isDir(dirPath1)) {
|
||||
cmdStr = "7z x -y -aos -p" + password + " -o" + dirPath1 + " " + filePath0;
|
||||
} else {
|
||||
cmdStr = "7z x -y -aos -p" + password + " " + filePath0;
|
||||
}
|
||||
}
|
||||
}
|
||||
try {
|
||||
return P7ZipApi.executeCommand(cmdStr);
|
||||
} catch (Exception e) {
|
||||
throw new ScriptException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -11,3 +11,4 @@ include ':js-supports:autojs-tool-common'
|
||||
include ':js-supports:kill-pro-limit'
|
||||
include ':autojs-aar:rhino-jdk7'
|
||||
include ':autojs-aar:paddleocr'
|
||||
include ':autojs-aar:p7zip'
|
||||
|
||||
Loading…
Reference in New Issue
Block a user