`refactor(TaskUtil): add taskId support, improved file/directory handling, and introduce compression/unzip utilities`

This commit is contained in:
yjj38 2025-06-21 14:39:57 +08:00
parent 7ce7a3d72e
commit ee67543b0a
9 changed files with 438 additions and 138 deletions

View File

@ -1,3 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4"> <project version="4">
<component name="ExternalStorageConfigurationManager" enabled="true" /> <component name="ExternalStorageConfigurationManager" enabled="true" />
<component name="ProjectRootManager" version="2" languageLevel="JDK_21" default="true" project-jdk-name="21" project-jdk-type="JavaSDK"> <component name="ProjectRootManager" version="2" languageLevel="JDK_21" default="true" project-jdk-name="21" project-jdk-type="JavaSDK">

Binary file not shown.

View File

@ -36,7 +36,7 @@ import com.example.studyapp.service.MyAccessibilityService;
import com.example.studyapp.task.TaskUtil; import com.example.studyapp.task.TaskUtil;
import com.example.studyapp.worker.CheckAccessibilityWorker; import com.example.studyapp.worker.CheckAccessibilityWorker;
import java.lang.ref.WeakReference; import java.lang.ref.WeakReference;
import java.util.concurrent.CountDownLatch; import java.util.UUID;
import java.util.concurrent.ExecutorService; import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.ThreadPoolExecutor;
@ -200,6 +200,7 @@ public class MainActivity extends AppCompatActivity {
// 初始化 ChangeDeviceInfoUtil // 初始化 ChangeDeviceInfoUtil
String androidId = getAndroidId(this); String androidId = getAndroidId(this);
String taskId = UUID.randomUUID().toString();
ChangeDeviceInfoUtil.initialize("US", 2, this, androidId); ChangeDeviceInfoUtil.initialize("US", 2, this, androidId);
// 获取输入框和按钮 // 获取输入框和按钮
Button executeButton = findViewById(R.id.execute_button); Button executeButton = findViewById(R.id.execute_button);
@ -210,7 +211,7 @@ public class MainActivity extends AppCompatActivity {
executeButton.setOnClickListener(v -> { executeButton.setOnClickListener(v -> {
executeButton.setEnabled(false); executeButton.setEnabled(false);
Toast.makeText(this, "任务正在执行", Toast.LENGTH_SHORT).show(); Toast.makeText(this, "任务正在执行", Toast.LENGTH_SHORT).show();
executeLogic(androidId); executeLogic(androidId,taskId);
}); });
} }
if (stopExecuteButton != null) { if (stopExecuteButton != null) {
@ -227,7 +228,7 @@ public class MainActivity extends AppCompatActivity {
} }
} }
private void executeLogic(String androidId) { private void executeLogic(String androidId,String taskId) {
Log.i("MainActivity", "executeLogic: Start execution"); Log.i("MainActivity", "executeLogic: Start execution");
if (!isNetworkAvailable(this)) { if (!isNetworkAvailable(this)) {
@ -248,7 +249,7 @@ public class MainActivity extends AppCompatActivity {
taskLock.wait(30000); taskLock.wait(30000);
} }
executeSingleLogic(); executeSingleLogic();
TaskUtil.execSaveTask(this,androidId); TaskUtil.execSaveTask(this, androidId,taskId);
scriptResult = "bin.mt.plus"; scriptResult = "bin.mt.plus";
if (scriptResult != null && !TextUtils.isEmpty(scriptResult)) { if (scriptResult != null && !TextUtils.isEmpty(scriptResult)) {
infoUpload(this, androidId, scriptResult); infoUpload(this, androidId, scriptResult);

View File

@ -3,16 +3,12 @@ package com.example.studyapp.autoJS;
import static com.example.studyapp.MainActivity.taskLock; import static com.example.studyapp.MainActivity.taskLock;
import static com.example.studyapp.task.TaskUtil.downloadCodeFile; import static com.example.studyapp.task.TaskUtil.downloadCodeFile;
import static com.example.studyapp.task.TaskUtil.infoUpload;
import android.Manifest;
import android.content.ActivityNotFoundException;
import android.content.BroadcastReceiver; import android.content.BroadcastReceiver;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.IntentFilter; import android.content.IntentFilter;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Environment; import android.os.Environment;
import android.os.Handler; import android.os.Handler;
import android.os.Looper; import android.os.Looper;
@ -22,19 +18,10 @@ import android.widget.Toast;
import androidx.core.content.ContextCompat; import androidx.core.content.ContextCompat;
import com.example.studyapp.MainActivity; import com.example.studyapp.MainActivity;
import com.example.studyapp.request.ScriptResultRequest;
import com.example.studyapp.service.CloudPhoneManageService;
import com.example.studyapp.utils.ShellUtils;
import java.io.File; import java.io.File;
import java.io.IOException;
import java.util.Objects;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;
public class AutoJsUtil { public class AutoJsUtil {
public static BroadcastReceiver scriptResultReceiver; public static BroadcastReceiver scriptResultReceiver;
@ -45,19 +32,17 @@ public class AutoJsUtil {
public static void runAutojsScript(Context context) { public static void runAutojsScript(Context context) {
// 检查脚本文件 // 检查脚本文件
Log.i("AutoJsUtil", "-------脚本运行开始:--------" + count++); Log.i("AutoJsUtil", "-------脚本运行开始:--------" + count++);
File scriptFile = new File(Environment.getExternalStorageDirectory(), "script/main.js"); File scriptDir = new File(Environment.getExternalStorageDirectory(), "script");
scriptDir.delete();
if (!scriptFile.exists()) { File scriptFile = downloadCodeFile("main.js", scriptDir);
scriptFile = downloadCodeFile("main.js");
if (scriptFile == null || !scriptFile.exists()) { if (scriptFile == null || !scriptFile.exists()) {
runOnUiThread(() -> Toast.makeText(context, "下载脚本文件失败", Toast.LENGTH_SHORT).show()); runOnUiThread(() -> Toast.makeText(context, "下载脚本文件失败", Toast.LENGTH_SHORT).show());
Log.e("AutoJsUtil", "下载脚本文件失败"); Log.e("AutoJsUtil", "下载脚本文件失败");
return; return;
} }
}
// 检查是否安装 Auto.js // 检查是否安装 Auto.js
if (!isAppInstalled("org.autojs.autojs6", context.getPackageManager())) { if (!isAppInstalled("org.autojs.autojs6")) {
runOnUiThread(() -> Toast.makeText(context, "Auto.js app not installed", Toast.LENGTH_SHORT).show()); runOnUiThread(() -> Toast.makeText(context, "Auto.js app not installed", Toast.LENGTH_SHORT).show());
return; return;
} }
@ -87,14 +72,12 @@ public class AutoJsUtil {
public void onReceive(Context context, Intent intent) { public void onReceive(Context context, Intent intent) {
Log.d("MainActivity", "----脚本运行结束通知一次------; 当前线程:" + Thread.currentThread().getName()); Log.d("MainActivity", "----脚本运行结束通知一次------; 当前线程:" + Thread.currentThread().getName());
String scriptResult = intent.getStringExtra(SCRIPT_RESULT_KEY); String scriptResult = intent.getStringExtra(SCRIPT_RESULT_KEY);
if (scriptResult != null && !scriptResult.isEmpty()) {
synchronized (taskLock) { synchronized (taskLock) {
AutoJsUtil.flag = true; AutoJsUtil.flag = true;
MainActivity.scriptResult = scriptResult; MainActivity.scriptResult = scriptResult;
taskLock.notifyAll(); // 唤醒任务线程 taskLock.notifyAll(); // 唤醒任务线程
} }
} }
}
}; };
// 注册广播接收器 // 注册广播接收器
@ -125,15 +108,28 @@ public class AutoJsUtil {
} }
// 检查目标应用是否安装 // 检查目标应用是否安装
public static boolean isAppInstalled(String packageName, PackageManager packageManager) { public static boolean isAppInstalled(String packageName) {
Log.d("isAppInstalled", "Checking if app is installed: " + packageName);
// 通过 Shell 命令实现检测
try { try {
packageManager.getPackageInfo(packageName, 0); String cmd = "pm list packages | grep " + packageName;
String result = ShellUtils.execRootCmdAndGetResult(cmd);
if (result != null && result.contains(packageName)) {
Log.d("isAppInstalled", "App is installed: " + packageName);
return true; return true;
} catch (PackageManager.NameNotFoundException e) { } else {
Log.w("isAppInstalled", "App not installed: " + packageName);
return false;
}
} catch (Exception e) {
Log.e("isAppInstalled", "Unexpected exception while checking app installation: " + packageName, e);
return false; return false;
} }
} }
private static final String AUTOJS_SCRIPT_FINISHED_ACTION = "org.autojs.SCRIPT_FINISHED"; private static final String AUTOJS_SCRIPT_FINISHED_ACTION = "org.autojs.SCRIPT_FINISHED";
private static final String SCRIPT_RESULT_KEY = "result"; private static final String SCRIPT_RESULT_KEY = "result";

View File

@ -1,11 +1,12 @@
package com.example.studyapp.device; package com.example.studyapp.device;
import static com.example.studyapp.autoJS.AutoJsUtil.isAppInstalled;
import android.content.ContentResolver; import android.content.ContentResolver;
import android.content.Context; import android.content.Context;
import android.net.Uri; import android.net.Uri;
import android.util.Log; import android.util.Log;
import com.example.studyapp.MainActivity;
import com.example.studyapp.task.AfInfo; import com.example.studyapp.task.AfInfo;
import com.example.studyapp.task.BigoInfo; import com.example.studyapp.task.BigoInfo;
import com.example.studyapp.task.DeviceInfo; import com.example.studyapp.task.DeviceInfo;
@ -13,8 +14,10 @@ import com.example.studyapp.task.TaskUtil;
import com.example.studyapp.utils.HttpUtil; import com.example.studyapp.utils.HttpUtil;
import com.example.studyapp.utils.ShellUtils; import com.example.studyapp.utils.ShellUtils;
import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.InvocationTargetException;
import java.util.Map;
import java.util.concurrent.ExecutorService; import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
import org.json.JSONException; import org.json.JSONException;
@ -48,32 +51,81 @@ public class ChangeDeviceInfoUtil {
// 创建一个线程池用于执行网络任务 // 创建一个线程池用于执行网络任务
private static final ExecutorService executorService = Executors.newSingleThreadExecutor(); private static final ExecutorService executorService = Executors.newSingleThreadExecutor();
public static void initialize(String country, int tag, MainActivity mainActivity, String androidId) { public static void initialize(String country, int tag, Context context, String androidId) {
Log.d("TaskUtil", "initialize method called with parameters:");
Log.d("TaskUtil", "Country: " + country + ", Tag: " + tag + ", Android ID: " + androidId);
Log.d("TaskUtil", "Context instance: " + (context != null ? context.getClass().getSimpleName() : "null"));
executorService.submit(() -> { executorService.submit(() -> {
try { try {
Log.d("TaskUtil", "Starting network requests...");
// 发起网络请求 // 发起网络请求
String bigoJson = HttpUtil.requestGet(buildBigoUrl(country, tag)); String bigoJson = HttpUtil.requestGet(buildBigoUrl(country, tag));
Log.d("TaskUtil", "Received bigoJson: " + bigoJson);
String afJson = HttpUtil.requestGet(buildAfUrl(country, tag)); String afJson = HttpUtil.requestGet(buildAfUrl(country, tag));
Log.d("TaskUtil", "Received afJson: " + afJson);
String response = executeQuerySafely(androidId); String response = executeQuerySafely(androidId);
Log.d("TaskUtil", "Response from executeQuerySafely: " + response);
// 解析 JSON // 解析 JSON
if (response != null && !response.isBlank() && !response.equals("{}\n")) { if (response != null && !response.isBlank() && !response.equals("{}\n")) {
Log.d("TaskUtil", "Parsing existing response JSON...");
JSONObject responseJson = new JSONObject(response); JSONObject responseJson = new JSONObject(response);
bigoDeviceObject = responseJson.optJSONObject("bigoDeviceObject"); bigoDeviceObject = responseJson.optJSONObject("bigoDeviceObject");
afDeviceObject = responseJson.optJSONObject("afDeviceObject"); afDeviceObject = responseJson.optJSONObject("afDeviceObject");
Log.d("TaskUtil", "Parsed bigoDeviceObject: " + bigoDeviceObject);
Log.d("TaskUtil", "Parsed afDeviceObject: " + afDeviceObject);
} else { } else {
Log.d("TaskUtil", "Fallback to parsing bigoJson and afJson...");
bigoDeviceObject = new JSONObject(bigoJson).optJSONObject("device"); bigoDeviceObject = new JSONObject(bigoJson).optJSONObject("device");
afDeviceObject = new JSONObject(afJson).optJSONObject("device"); afDeviceObject = new JSONObject(afJson).optJSONObject("device");
Log.d("TaskUtil", "Fallback bigoDeviceObject: " + bigoDeviceObject);
Log.d("TaskUtil", "Fallback afDeviceObject: " + afDeviceObject);
} }
// 输出结果 // 输出结果
Log.d("Debug", "bigoDeviceObject: " + bigoDeviceObject); Log.i("TaskUtil", "Final bigoDeviceObject: " + bigoDeviceObject);
Log.d("Debug", "afDeviceObject: " + afDeviceObject); Log.i("TaskUtil", "Final afDeviceObject: " + afDeviceObject);
// 获取包信息
Log.d("TaskUtil", "Fetching package info...");
Map<String, String> packageInfo = TaskUtil.getPackageInfo(androidId);
Log.d("TaskUtil", "Package info retrieved: " + packageInfo);
// 遍历包信息并执行逻辑
for (String packAgeName : packageInfo.keySet()) {
Log.d("TaskUtil", "Processing package: " + packAgeName);
if (isAppInstalled(packAgeName)) {
Log.d("TaskUtil", "Package installed: " + packAgeName);
File filesDir = new File(context.getExternalFilesDir(null).getAbsolutePath());
Log.d("TaskUtil", "Files directory: " + filesDir.getAbsolutePath());
File file = TaskUtil.downloadCodeFile(packageInfo.get(packAgeName), filesDir);
if (file != null && file.exists()) {
Log.d("TaskUtil", "File downloaded: " + file.getAbsolutePath());
File destDir = new File("/storage/emulated/0/Android/data/" + packAgeName);
Log.d("TaskUtil", "Unzipping to destination: " + destDir.getAbsolutePath());
TaskUtil.unZip(destDir, file);
Log.d("TaskUtil", "Unzip completed. Deleting file: " + file.getAbsolutePath());
TaskUtil.delFileSh(file.getAbsolutePath());
Log.d("TaskUtil", "Temporary file deleted: " + file.getAbsolutePath());
} else {
Log.w("TaskUtil", "File download failed or file does not exist for package: " + packAgeName);
}
} else {
Log.w("TaskUtil", "Package not installed: " + packAgeName);
}
}
} catch (IOException | JSONException e) { } catch (IOException | JSONException e) {
Log.e("Error", "Error occurred during initialization", e); Log.e("TaskUtil", "Error occurred during initialization", e);
} catch (Exception e) { } catch (Exception e) {
Log.e("Error", "Unexpected error occurred", e); Log.e("TaskUtil", "Unexpected error occurred", e);
} }
}); });
} }

View File

@ -1,18 +1,21 @@
package com.example.studyapp.task; package com.example.studyapp.task;
import android.content.Context; import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.os.Environment; import android.os.Environment;
import android.util.Log; import android.util.Log;
import com.example.studyapp.utils.MockTools;
import com.example.studyapp.utils.ShellUtils; import com.example.studyapp.utils.ShellUtils;
import com.google.android.gms.common.util.CollectionUtils;
import com.google.android.gms.common.util.MapUtils;
import com.google.gson.Gson; import com.google.gson.Gson;
import com.google.gson.GsonBuilder; import com.google.gson.GsonBuilder;
import com.google.gson.reflect.TypeToken;
import java.io.BufferedOutputStream; import java.io.BufferedOutputStream;
import java.io.FileInputStream; import java.io.FileInputStream;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
import java.lang.reflect.Type;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.zip.ZipEntry; import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream; import java.util.zip.ZipOutputStream;
@ -53,7 +56,7 @@ public class TaskUtil {
.readTimeout(30, TimeUnit.SECONDS) // 读取超时 .readTimeout(30, TimeUnit.SECONDS) // 读取超时
.build(); .build();
public static void postDeviceInfo(String androidId) { public static void postDeviceInfo(String androidId, String taskId) {
Log.i("TaskUtil", "postDeviceInfo called with androidId: " + androidId); Log.i("TaskUtil", "postDeviceInfo called with androidId: " + androidId);
if (okHttpClient == null) { if (okHttpClient == null) {
@ -81,6 +84,7 @@ public class TaskUtil {
.newBuilder() .newBuilder()
.addPathSegment("device_info_upload") .addPathSegment("device_info_upload")
.addQueryParameter("id", androidId) .addQueryParameter("id", androidId)
.addQueryParameter("taskId", taskId)
.build(); .build();
Log.d("TaskUtil", "Request URL: " + url.toString()); Log.d("TaskUtil", "Request URL: " + url.toString());
@ -207,7 +211,7 @@ public class TaskUtil {
boolean success = clearUpFileInDst(copiedDir); boolean success = clearUpFileInDst(copiedDir);
if (success) { if (success) {
// 压缩APK文件 // 压缩APK文件
zipSh(copiedDir, zipFile); compressToZip(copiedDir, zipFile);
} }
// 上传压缩文件 // 上传压缩文件
@ -223,30 +227,6 @@ public class TaskUtil {
delFileSh(zipFile.getAbsolutePath()); delFileSh(zipFile.getAbsolutePath());
} }
public static void delFileSh(String path) {
Log.i("TaskUtil", "start delFileSh : " + path);
// 1. 参数校验
if (path == null || path.isEmpty()) {
Log.e("TaskUtil", "Invalid or empty path provided.");
return;
}
File file = new File(path);
if (!file.exists()) {
Log.e("TaskUtil", "File does not exist: " + path);
return;
}
// 3. 执行 Shell 命令
try {
String cmd = "rm -rf " + path;
Log.i("TaskUtil", "Attempting to delete file using Shell command.");
ShellUtils.execRootCmd(cmd);
Log.i("TaskUtil", "File deletion successful for path: " + path);
} catch (Exception e) {
Log.e("TaskUtil", "Error occurred while deleting file: " + e.getMessage(), e);
}
}
public static boolean copyFolderSh(String oldPath, String newPath) { public static boolean copyFolderSh(String oldPath, String newPath) {
Log.i("TaskUtil", "start copyFolderSh : " + oldPath + " ; " + newPath); Log.i("TaskUtil", "start copyFolderSh : " + oldPath + " ; " + newPath);
try { try {
@ -287,9 +267,6 @@ public class TaskUtil {
} }
} }
private static final int BUFFER_SIZE = 1024 * 4;
private static boolean clearUpFileInDst(File dst) { private static boolean clearUpFileInDst(File dst) {
if (dst.exists()) { if (dst.exists()) {
File[] files = dst.listFiles(); File[] files = dst.listFiles();
@ -318,18 +295,91 @@ public class TaskUtil {
return false; return false;
} }
public static void delFileSh(String path) {
Log.i("TaskUtil", "start delFileSh : " + path);
// 1. 参数校验
if (path == null || path.isEmpty()) {
Log.e("TaskUtil", "Invalid or empty path provided.");
return;
}
File file = new File(path);
if (!file.exists()) {
Log.e("TaskUtil", "File does not exist: " + path);
return;
}
// 3. 执行 Shell 命令
try {
String cmd = "rm -rf " + path;
Log.i("TaskUtil", "Attempting to delete file using Shell command.");
ShellUtils.execRootCmd(cmd);
Log.i("TaskUtil", "File deletion successful for path: " + path);
} catch (Exception e) {
Log.e("TaskUtil", "Error occurred while deleting file: " + e.getMessage(), e);
}
}
private static void delFile(File file) { private static void delFile(File file) {
if (file == null || !file.exists()) {
Log.e("TaskUtil", "File does not exist or is null.");
return;
}
try { try {
String cmd = "rm -rf " + file; String cmd = "rm -rf " + file.getAbsolutePath();
Log.i("TaskUtil", "delFile-> cmd:" + cmd); Log.i("TaskUtil", "Deleting file: " + file.getName());
ShellUtils.execRootCmd(cmd); ShellUtils.execRootCmd(cmd);
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); Log.e("TaskUtil", "Error occurred while deleting file: " + file, e);
throw new RuntimeException("File deletion failed", e);
} }
} }
private static void compressToZip(File src, File dst) throws IOException {
Log.d("TaskUtil", "Starting to compress the APK directory...");
if (!src.exists() || !src.isDirectory()) {
throw new IOException("Source path does not exist or is not a directory: " + src.getAbsolutePath());
}
if (dst.exists()) {
throw new IOException("Destination ZIP file already exists: " + dst.getAbsolutePath());
}
if (!dst.getParentFile().canWrite()) {
throw new IOException("Parent directory of destination file is not writable: " + dst.getAbsolutePath());
}
try (FileOutputStream fos = new FileOutputStream(dst);
ZipOutputStream zipOut = new ZipOutputStream(fos)) {
addDirToZip(src, "", zipOut);
Log.i("TaskUtil", "Directory successfully compressed to ZIP: " + dst.getName());
} catch (IOException e) {
Log.e("TaskUtil", "Error during directory compression", e);
throw e;
}
}
private static void addDirToZip(File src, String parentPath, ZipOutputStream zipOut) throws IOException {
File[] files = src.listFiles();
if (files != null) {
for (File file : files) {
String zipEntryName = parentPath + file.getName();
if (file.isDirectory()) {
addDirToZip(file, zipEntryName + "/", zipOut);
} else {
try (FileInputStream fis = new FileInputStream(file)) {
zipOut.putNextEntry(new ZipEntry(zipEntryName));
byte[] buffer = new byte[4096]; // 默认 Buffer 大小
int bytesRead;
while ((bytesRead = fis.read(buffer)) >= 0) {
zipOut.write(buffer, 0, bytesRead);
}
zipOut.closeEntry();
}
}
}
}
}
public static void zipSh(File copyDir, File zipFile) { public static void zipSh(File copyDir, File zipFile) {
try { try {
@ -357,6 +407,125 @@ public class TaskUtil {
} }
} }
public static void unZip(File destinationDir, File zipFile) {
Log.d("TaskUtil", "unZip method called with parameters:");
Log.d("TaskUtil", "Destination directory: " + (destinationDir != null ? destinationDir.getAbsolutePath() : "null"));
Log.d("TaskUtil", "ZIP file: " + (zipFile != null ? zipFile.getAbsolutePath() : "null"));
try {
// 校验输入参数
if (destinationDir == null || zipFile == null) {
Log.e("TaskUtil", "Destination directory or ZIP file is null.");
throw new IllegalArgumentException("Destination directory or ZIP file cannot be null.");
}
if (!zipFile.exists() || !zipFile.isFile()) {
Log.e("TaskUtil", "Invalid ZIP file: " + zipFile.getAbsolutePath());
throw new IllegalArgumentException("Invalid ZIP file: " + zipFile.getAbsolutePath());
}
// 创建目标目录如果不存在
if (!destinationDir.exists()) {
boolean mkdirs = destinationDir.mkdirs();
Log.d("TaskUtil", "Destination directory created: " + mkdirs + ", Path: " + destinationDir.getAbsolutePath());
if (!mkdirs) {
Log.e("TaskUtil", "Failed to create destination directory: " + destinationDir.getAbsolutePath());
throw new IOException("Failed to create destination directory: " + destinationDir.getAbsolutePath());
}
} else {
Log.d("TaskUtil", "Destination directory already exists: " + destinationDir.getAbsolutePath());
}
// 使用Java自带的ZipInputStream解压文件
try (FileInputStream fis = new FileInputStream(zipFile);
java.util.zip.ZipInputStream zis = new java.util.zip.ZipInputStream(fis)) {
Log.d("TaskUtil", "ZipInputStream opened for ZIP file: " + zipFile.getAbsolutePath());
java.util.zip.ZipEntry zipEntry;
while ((zipEntry = zis.getNextEntry()) != null) {
Log.d("TaskUtil", "Processing entry: " + zipEntry.getName());
File newFile = new File(destinationDir, zipEntry.getName());
// 检查目标文件路径是否合法避免安全漏洞
if (!newFile.getCanonicalPath().startsWith(destinationDir.getCanonicalPath())) {
Log.e("TaskUtil", "Unzip entry is outside of the target directory: " + newFile.getAbsolutePath());
throw new IOException("Unzip entry is outside of the target directory: " + newFile.getAbsolutePath());
}
if (zipEntry.isDirectory()) {
// 如果是目录则创建目录
if (!newFile.exists() && newFile.mkdirs()) {
Log.d("TaskUtil", "Directory created: " + newFile.getAbsolutePath());
}
} else {
// 如果是文件则写入文件
File parent = newFile.getParentFile();
if (!parent.exists()) {
boolean parentCreated = parent.mkdirs();
Log.d("TaskUtil", "Parent directory created: " + parentCreated + ", Path: " + parent.getAbsolutePath());
if (!parentCreated) {
Log.e("TaskUtil", "Failed to create parent directory: " + parent.getAbsolutePath());
throw new IOException("Failed to create parent directory: " + parent.getAbsolutePath());
}
}
try (FileOutputStream fos = new FileOutputStream(newFile)) {
Log.d("TaskUtil", "Writing to file: " + newFile.getAbsolutePath());
byte[] buffer = new byte[4096];
int length;
while ((length = zis.read(buffer)) > 0) {
fos.write(buffer, 0, length);
}
}
Log.d("TaskUtil", "File written successfully: " + newFile.getAbsolutePath());
}
zis.closeEntry();
}
}
Log.i("TaskUtil", "Unzip successful. Extracted to: " + destinationDir.getAbsolutePath());
} catch (Exception e) {
Log.e("TaskUtil", "Error in unZip method", e);
}
}
public static void unzipSh(File destinationDir, File zipFile) {
try {
if (destinationDir == null || zipFile == null) {
throw new IllegalArgumentException("Destination directory or ZIP file cannot be null.");
}
if (!zipFile.exists() || !zipFile.isFile()) {
throw new IllegalArgumentException("Invalid ZIP file: " + zipFile.getAbsolutePath());
}
if (!destinationDir.exists()) {
boolean mkdirs = destinationDir.mkdirs();
if (!mkdirs) {
throw new IOException("Failed to create destination directory: " + destinationDir.getAbsolutePath());
}
}
String destPath = destinationDir.getAbsolutePath().replace(" ", "\\ ").replace("\"", "\\\"");
String zipFilePath = zipFile.getAbsolutePath().replace(" ", "\\ ").replace("\"", "\\\"");
// 构造解压命令
String cmd = "unzip -o \"" + zipFilePath + "\" -d \"" + destPath + "\"";
Log.i("TaskUtil", "unzipSh-> cmd: " + cmd.replace(zipFilePath, "[ZIP_FILE_PATH]").replace(destPath, "[DESTINATION_PATH]"));
// 执行命令
String result = ShellUtils.execRootCmdAndGetResult(cmd);
// 检查返回结果
if (result == null || result.contains("error")) {
Log.e("TaskUtil", "Shell command execution failed: " + result);
throw new IOException("Shell command failed. Result: " + result);
}
Log.i("TaskUtil", "Unzip successful. Extracted to: " + destinationDir.getAbsolutePath());
} catch (Exception e) {
Log.e("TaskUtil", "Error in unzipSh", e);
}
}
public static void uploadFile(File fileToUpload) throws IOException { public static void uploadFile(File fileToUpload) throws IOException {
Log.d("TaskUtil", "Preparing to upload file..."); Log.d("TaskUtil", "Preparing to upload file...");
RequestBody fileBody = RequestBody.create(MediaType.get("application/zip"), fileToUpload); RequestBody fileBody = RequestBody.create(MediaType.get("application/zip"), fileToUpload);
@ -389,6 +558,67 @@ public class TaskUtil {
} }
} }
public static File downloadCodeFile(String fileName, File filesLocationDir) {
String baseUrl = BASE_URL + "/download_code_file";
String fullUrl = baseUrl + "?file_name=" + fileName;
Log.d("TaskUtil", "Download URL constructed: " + fullUrl); // 添加日志记录URL
Request request = new Request.Builder()
.url(fullUrl)
.get()
.build();
try (Response response = okHttpClient.newCall(request).execute()) {
Log.d("TaskUtil", "HTTP request executed. Response code: " + response.code()); // 记录响应代码
if (response.isSuccessful() && response.body() != null) {
Log.d("TaskUtil", "Response is successful. Preparing to save file."); // 记录成功响应
// 检查目录是否存在
if (!filesLocationDir.exists()) {
boolean dirCreated = filesLocationDir.mkdirs();
Log.d("TaskUtil", "Directory created: " + filesLocationDir.getAbsolutePath() + " - " + dirCreated);
}
File saveFile = new File(filesLocationDir, fileName);
Log.d("TaskUtil", "Target file path: " + saveFile.getAbsolutePath());
try (InputStream is = response.body().byteStream();
OutputStream os = new BufferedOutputStream(new FileOutputStream(saveFile))) {
Log.d("TaskUtil", "Starting to write file...");
byte[] buffer = new byte[8192];
int bytesRead;
while ((bytesRead = is.read(buffer)) != -1) {
os.write(buffer, 0, bytesRead);
}
Log.i("TaskUtil", "File saved successfully to: " + saveFile.getAbsolutePath());
}
return saveFile;
} else {
Log.w("TaskUtil", "Download failed. HTTP code: " + response.code() + ", Message: " + response.message());
// 如果响应体不为空则记录内容
if (response.body() != null) {
try {
String responseBody = response.body().string();
Log.e("TaskUtil", "Response body: " + responseBody);
} catch (IOException e) {
Log.e("TaskUtil", "Failed to read response body for logging", e);
}
} else {
Log.e("TaskUtil", "Response body is null");
}
return null;
}
} catch (IOException e) {
Log.e("TaskUtil", "Error during file download. Exception: " + e.getMessage(), e);
return null;
}
}
private static void validate() { private static void validate() {
if (okHttpClient == null) { if (okHttpClient == null) {
throw new IllegalStateException("HttpClient is not initialized"); throw new IllegalStateException("HttpClient is not initialized");
@ -398,6 +628,69 @@ public class TaskUtil {
} }
} }
public static Map<String, String> getPackageInfo(String androidId) {
Log.i("TaskUtil", "getPackageInfo called with androidId: " + androidId);
try {
// 构造完整的URL
HttpUrl url = HttpUrl.parse(BASE_URL + "/get_package_info")
.newBuilder()
.addQueryParameter("androidId", androidId)
.build();
Log.d("TaskUtil", "Constructed URL: " + url.toString());
// 创建 HTTP 请求
Request request = new Request.Builder()
.url(url)
.get()
.build();
// 同步执行网络请求
try (Response response = okHttpClient.newCall(request).execute()) {
// 检查响应是否成功
if (!response.isSuccessful()) {
String errorMessage = "Unexpected response: Code=" + response.code() +
", Message=" + response.message() +
", URL=" + url.toString();
Log.e("TaskUtil", errorMessage);
throw new IOException(errorMessage);
}
// 解析响应内容
ResponseBody responseBody = response.body();
if (responseBody != null) {
String responseString = responseBody.string();
// 定义Gson对象
Gson gson = new Gson();
// 指定解析的泛型类型为 Map<String, List<String>>
Type type = new TypeToken<Map<String, String>>() {
}.getType();
// 将JSON字符串转换为 Map
Map<String, String> resultMap = gson.fromJson(responseString, type);
// 根据androidId获取对应的文件列表
if (resultMap != null) {
return resultMap;
} else {
Log.w("TaskUtil", "Android ID not found in response.");
return null;
}
} else {
String errorMessage = "Response body is null for URL=" + url.toString();
Log.e("TaskUtil", errorMessage);
throw new IOException(errorMessage);
}
}
} catch (IOException e) {
Log.e("TaskUtil", "Error during getPackageInfo request", e);
}
return null; // 如果出错返回null
}
private static void infoDownload(String androidId) { private static void infoDownload(String androidId) {
// 下载压缩包 // 下载压缩包
HttpUrl url = HttpUrl.parse(BASE_URL + "/tar_info_download") HttpUrl url = HttpUrl.parse(BASE_URL + "/tar_info_download")
@ -438,54 +731,11 @@ public class TaskUtil {
}); });
} }
public static File downloadCodeFile(String fileName) {
String baseUrl = BASE_URL + "/download_code_file";
String fullUrl = baseUrl + "?file_name=" + fileName;
Request request = new Request.Builder()
.url(fullUrl)
.get()
.build();
try (Response response = okHttpClient.newCall(request).execute()) {
if (response.isSuccessful() && response.body() != null) {
File scriptDir = new File(Environment.getExternalStorageDirectory(), "script");
if (!scriptDir.exists()) {
scriptDir.mkdirs(); // 创建 script 目录
}
File saveFile = new File(scriptDir, fileName);
try (InputStream is = response.body().byteStream();
OutputStream os = new BufferedOutputStream(new FileOutputStream(saveFile))) {
byte[] buffer = new byte[8192];
int bytesRead;
while ((bytesRead = is.read(buffer)) != -1) {
os.write(buffer, 0, bytesRead);
}
Log.i("TaskUtil", "File saved to: " + saveFile.getAbsolutePath());
}
return saveFile;
} else {
Log.w("TaskUtil", "Download failed: HTTP code " + response.code());
if (response.body() != null) {
Log.e("TaskUtil", "Response body: " + response.body().string());
}
return null;
}
} catch (Exception e) {
Log.e("TaskUtil", "Error downloading file", e);
return null;
}
}
public static String execQueryTask(String androidId) { public static String execQueryTask(String androidId) {
return getDeviceInfoSync(androidId); return getDeviceInfoSync(androidId);
} }
public static void execSaveTask(Context context, String androidId) { public static void execSaveTask(Context context, String androidId, String taskId) {
if (context == null) { if (context == null) {
throw new IllegalArgumentException("Context or Package name cannot be null or empty"); throw new IllegalArgumentException("Context or Package name cannot be null or empty");
} }
@ -496,7 +746,7 @@ public class TaskUtil {
} }
try { try {
postDeviceInfo(androidId); postDeviceInfo(androidId, taskId);
} catch (Exception e) { } catch (Exception e) {
System.err.println("Error in execReloginTask: " + e.getMessage()); System.err.println("Error in execReloginTask: " + e.getMessage());
e.printStackTrace(); e.printStackTrace();

View File

@ -8,7 +8,6 @@ import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.any; import static org.mockito.Mockito.any;
import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
import org.mockito.Mockito; import org.mockito.Mockito;
@ -131,7 +130,8 @@ public class TaskUtilTest {
public void testPostDeviceInfoDownload_Success() throws Exception { public void testPostDeviceInfoDownload_Success() throws Exception {
// 运行上传方法 // 运行上传方法
TaskUtil.postDeviceInfo("b3d893cf9de3a85a"); String taskId = "asddasdasd";
TaskUtil.postDeviceInfo("b3d893cf9de3a85a", taskId);
} }
@Test @Test
@ -141,11 +141,11 @@ public class TaskUtilTest {
TaskUtil.getDeviceInfoSync("b3d893cf9de3a85a"); TaskUtil.getDeviceInfoSync("b3d893cf9de3a85a");
} }
@Test // @Test
public void testDownloadCodeFile_Success() throws Exception { // public void testDownloadCodeFile_Success() throws Exception {
// 运行上传方法 // // 运行上传方法
TaskUtil.downloadCodeFile("main.js"); // TaskUtil.downloadCodeFile("main.js");
} // }
@Test @Test
public void testUploadFile_FailureWithResponseBody() throws Exception { public void testUploadFile_FailureWithResponseBody() throws Exception {