This commit is contained in:
Administrator 2025-06-25 18:09:58 +08:00
parent d21136edf5
commit 4642f6e459
8 changed files with 216 additions and 32 deletions

View File

@ -7,7 +7,7 @@ android {
compileSdk 35 compileSdk 35
defaultConfig { defaultConfig {
applicationId "com.example.studyapp" applicationId "com.example.retention"
minSdk 24 minSdk 24
targetSdk 35 targetSdk 35
versionCode 1 versionCode 1

View File

@ -39,7 +39,7 @@
android:usesCleartextTraffic="true" android:usesCleartextTraffic="true"
android:fullBackupContent="@xml/backup_rules" android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/box" android:icon="@mipmap/box"
android:label="Script helper" android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round" android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true" android:supportsRtl="true"
android:theme="@style/Theme.StudyApp" android:theme="@style/Theme.StudyApp"

View File

@ -1,6 +1,7 @@
package com.example.studyapp; package com.example.studyapp;
import static com.example.studyapp.task.TaskUtil.infoUpload; import static com.example.studyapp.task.TaskUtil.infoUpload;
import static com.example.studyapp.utils.Utils.isNetworkAvailable;
import android.app.Activity; import android.app.Activity;
import android.app.AlertDialog; import android.app.AlertDialog;
@ -36,7 +37,9 @@ import com.example.studyapp.service.MyAccessibilityService;
import com.example.studyapp.task.TaskUtil; import com.example.studyapp.task.TaskUtil;
import com.example.studyapp.utils.LogFileUtil; import com.example.studyapp.utils.LogFileUtil;
import com.example.studyapp.utils.ShellUtils; import com.example.studyapp.utils.ShellUtils;
import com.example.studyapp.utils.Utils;
import com.example.studyapp.worker.CheckAccessibilityWorker; import com.example.studyapp.worker.CheckAccessibilityWorker;
import com.example.studyapp.worker.LoadDeviceWorker;
import java.io.File; import java.io.File;
import java.lang.ref.WeakReference; import java.lang.ref.WeakReference;
@ -95,19 +98,20 @@ public class MainActivity extends AppCompatActivity {
* @return 设备的 ANDROID_ID若无法获取则返回 null * @return 设备的 ANDROID_ID若无法获取则返回 null
*/ */
private String getAndroidId(Context context) { private String getAndroidId(Context context) {
if (context == null) { // if (context == null) {
LogFileUtil.logAndWrite(Log.ERROR, "MainActivity", "getAndroidId: Context cannot be null",null); // LogFileUtil.logAndWrite(Log.ERROR, "MainActivity", "getAndroidId: Context cannot be null",null);
throw new IllegalArgumentException("Context cannot be null"); // throw new IllegalArgumentException("Context cannot be null");
} // }
try { // try {
return Settings.Secure.getString( // return Settings.Secure.getString(
context.getContentResolver(), // context.getContentResolver(),
Settings.Secure.ANDROID_ID // Settings.Secure.ANDROID_ID
); // );
} catch (Exception e) { // } catch (Exception e) {
LogFileUtil.logAndWrite(Log.ERROR, "MainActivity", "getAndroidId: Failed to get ANDROID_ID",e); // LogFileUtil.logAndWrite(Log.ERROR, "MainActivity", "getAndroidId: Failed to get ANDROID_ID",e);
return null; // return null;
} // }
return "FyZqWrStUvOpKlMn";
} }
@ -153,7 +157,10 @@ public class MainActivity extends AppCompatActivity {
LogFileUtil.logAndWrite(Log.INFO, "MainActivity", "onCreate: Setting up UI components",null); LogFileUtil.logAndWrite(Log.INFO, "MainActivity", "onCreate: Setting up UI components",null);
Button runScriptButton = findViewById(R.id.run_script_button); Button runScriptButton = findViewById(R.id.run_script_button);
if (runScriptButton != null) { if (runScriptButton != null) {
runScriptButton.setOnClickListener(v -> AutoJsUtil.runAutojsScript(this)); // runScriptButton.setOnClickListener(v -> AutoJsUtil.runAutojsScript(this));
runScriptButton.setOnClickListener(v -> {
Utils.writePackageName("com.test.app");
});
} else { } else {
LogFileUtil.logAndWrite(Log.WARN, "MainActivity", "Run Script Button not found",null); LogFileUtil.logAndWrite(Log.WARN, "MainActivity", "Run Script Button not found",null);
Toast.makeText(this, "Button not found", Toast.LENGTH_SHORT).show(); Toast.makeText(this, "Button not found", Toast.LENGTH_SHORT).show();
@ -210,7 +217,8 @@ 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,taskId); // executeLogic(androidId,taskId);
startLoadWork();
}); });
} }
if (stopExecuteButton != null) { if (stopExecuteButton != null) {
@ -227,6 +235,12 @@ public class MainActivity extends AppCompatActivity {
} }
} }
private void startLoadWork(){
PeriodicWorkRequest workRequest = new PeriodicWorkRequest.Builder(LoadDeviceWorker.class, 15, TimeUnit.MINUTES)
.setInitialDelay(0, TimeUnit.SECONDS).build();
WorkManager.getInstance(this).enqueue(workRequest);
}
private void executeLogic(String androidId, String taskId) { private void executeLogic(String androidId, String taskId) {
LogFileUtil.logAndWrite(Log.INFO, "MainActivity", "executeLogic: Start execution",null); LogFileUtil.logAndWrite(Log.INFO, "MainActivity", "executeLogic: Start execution",null);
@ -393,17 +407,4 @@ public class MainActivity extends AppCompatActivity {
public static MainActivity getInstance() { public static MainActivity getInstance() {
return instance.get(); // 返回实例 return instance.get(); // 返回实例
} }
private boolean isNetworkAvailable(Context context) {
ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
if (connectivityManager != null) {
Network network = connectivityManager.getActiveNetwork();
if (network != null) {
NetworkCapabilities capabilities = connectivityManager.getNetworkCapabilities(network);
return capabilities != null && capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
&& capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED);
}
}
return false;
}
} }

View File

@ -34,6 +34,9 @@ public class ChangeDeviceInfoUtil {
private static JSONObject afDeviceObject; private static JSONObject afDeviceObject;
public static String packageName = "";
public static String zipName = "";
public static String buildBigoUrl(String country, int tag) { public static String buildBigoUrl(String country, int tag) {
return Uri.parse("http://8.217.137.25/tt/zj/dispatcher!bigo.do") return Uri.parse("http://8.217.137.25/tt/zj/dispatcher!bigo.do")
.buildUpon() .buildUpon()
@ -75,6 +78,34 @@ public class ChangeDeviceInfoUtil {
}); });
} }
public static boolean getDeviceInfoSync(String taskId, String androidId){
String response = "";
try{
response = executeQuerySafely(androidId, taskId);
} catch (Exception e) {
e.printStackTrace();
}
if (response == null || response.isBlank()) {
LogFileUtil.logAndWrite(android.util.Log.ERROR, LOG_TAG, "Error occurred during query", null);
return false;
}
if (isValidResponse(response)) {
try {
synchronized (ChangeDeviceInfoUtil.class) { // 防止并发访问
parseAndSetDeviceObjects(response);
}
return true;
} catch (JSONException e) {
LogFileUtil.logAndWrite(android.util.Log.ERROR, LOG_TAG, "Error parsing JSON", e);
return false;
}
} else {
LogFileUtil.logAndWrite(android.util.Log.ERROR, LOG_TAG, "Error occurred during query",null);
return false;
}
}
public static void getDeviceInfo(String taskId, String androidId) { public static void getDeviceInfo(String taskId, String androidId) {
if (taskId == null || androidId == null || taskId.isBlank() || androidId.isBlank()) { if (taskId == null || androidId == null || taskId.isBlank() || androidId.isBlank()) {
LogFileUtil.logAndWrite(android.util.Log.ERROR, LOG_TAG, "Invalid task",null); LogFileUtil.logAndWrite(android.util.Log.ERROR, LOG_TAG, "Invalid task",null);
@ -146,6 +177,8 @@ public class ChangeDeviceInfoUtil {
JSONObject responseJson = new JSONObject(cleanJson); JSONObject responseJson = new JSONObject(cleanJson);
bigoDeviceObject = responseJson.optJSONObject("bigoDeviceObject"); bigoDeviceObject = responseJson.optJSONObject("bigoDeviceObject");
afDeviceObject = responseJson.optJSONObject("afDeviceObject"); afDeviceObject = responseJson.optJSONObject("afDeviceObject");
packageName = responseJson.optString("package_name");
zipName = responseJson.optString("file_name");
} }
private static void fallBackToNetworkData(String bigoJson, String afJson) throws JSONException { private static void fallBackToNetworkData(String bigoJson, String afJson) throws JSONException {
@ -171,6 +204,15 @@ public class ChangeDeviceInfoUtil {
} }
} }
public static void processPackageInfoWithDeviceInfo(String packageName,String zipName, Context context, String androidId, String taskId) {
if (!isAppInstalled(packageName)) {
processPackage(packageName, zipName, context);
TaskUtil.postDeviceInfo(androidId, taskId, packageName);
} else {
LogFileUtil.logAndWrite(android.util.Log.WARN, LOG_TAG, "Package not installed: " + packageName, null);
}
}
private static void processPackage(String packageName, String zipName, Context context) { private static void processPackage(String packageName, String zipName, Context context) {
try { try {
File filesDir = new File(context.getExternalFilesDir(null).getAbsolutePath()); File filesDir = new File(context.getExternalFilesDir(null).getAbsolutePath());

View File

@ -0,0 +1,52 @@
package com.example.studyapp.utils;
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.Network;
import android.net.NetworkCapabilities;
import android.os.Environment;
import android.util.Log;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
public class Utils {
public static boolean isNetworkAvailable(Context context) {
ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
if (connectivityManager != null) {
Network network = connectivityManager.getActiveNetwork();
if (network != null) {
NetworkCapabilities capabilities = connectivityManager.getNetworkCapabilities(network);
return capabilities != null && capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
&& capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED);
}
}
return false;
}
public static void writePackageName(String packageName){
File file = new File(Environment.getExternalStorageDirectory(),
"script/packagesname.txt");
File parentDir = file.getParentFile();
if (parentDir != null && !parentDir.exists()) {
boolean dirsCreated = parentDir.mkdirs();
if (!dirsCreated) {
Log.e("FileWrite", "Failed to create directories: " + parentDir);
return;
}
}
Log.d("TAG", "writePackageName: "+packageName);
try (BufferedOutputStream bos = new BufferedOutputStream(
new FileOutputStream(file))) {
bos.write(packageName.getBytes(StandardCharsets.UTF_8));
bos.flush(); // 确保数据写入磁盘
} catch (IOException e) {
Log.e("FileWrite", "Failed to write package name: " + packageName, e);
// 6. 可以考虑添加重试机制或通知用户
}
}
}

View File

@ -0,0 +1,89 @@
package com.example.studyapp.worker;
import static com.example.studyapp.utils.Utils.isNetworkAvailable;
import android.app.Activity;
import android.content.Context;
import android.os.Environment;
import android.os.Handler;
import android.os.Looper;
import android.text.TextUtils;
import android.util.Log;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.work.CoroutineWorker;
import androidx.work.WorkerParameters;
import com.example.studyapp.autoJS.AutoJsUtil;
import com.example.studyapp.device.ChangeDeviceInfoUtil;
import com.example.studyapp.proxy.ClashUtil;
import com.example.studyapp.task.TaskUtil;
import com.example.studyapp.utils.LogFileUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Map;
import java.util.UUID;
import kotlin.coroutines.Continuation;
public class LoadDeviceWorker extends CoroutineWorker {
private String androidId = "FyZqWrStUvOpKlMn";
public LoadDeviceWorker(@NonNull Context context, @NonNull WorkerParameters workerParams) {
super(context, workerParams);
}
@Override
public @Nullable Object doWork(@NotNull Continuation<? super Result> continuation) {
String taskId = UUID.randomUUID().toString();
boolean result = ChangeDeviceInfoUtil.getDeviceInfoSync(taskId, androidId);
String packageName = ChangeDeviceInfoUtil.packageName;
String zipName = ChangeDeviceInfoUtil.zipName;
if (result && !TextUtils.isEmpty(packageName) && !TextUtils.isEmpty(zipName)){
ChangeDeviceInfoUtil.processPackageInfoWithDeviceInfo(packageName,zipName, getApplicationContext(), androidId, taskId);
executeSingleLogic(getApplicationContext());
}
return Result.success();
}
public void executeSingleLogic(Context context) {
LogFileUtil.logAndWrite(Log.INFO, "MainActivity", "executeSingleLogic: Proxy not active, starting VPN",null);
new Handler(Looper.getMainLooper()).post(() -> {
startProxyVpn(context);
});
LogFileUtil.logAndWrite(Log.INFO, "MainActivity", "executeSingleLogic: Changing device info",null);
ChangeDeviceInfoUtil.changeDeviceInfo(context.getPackageName(), context);
LogFileUtil.logAndWrite(Log.INFO, "MainActivity", "executeSingleLogic: Running AutoJs script",null);
AutoJsUtil.runAutojsScript(context);
}
private void startProxyVpn(Context context) {
if (!isNetworkAvailable(context)) {
Toast.makeText(context, "Network is not available", Toast.LENGTH_SHORT).show();
LogFileUtil.logAndWrite(Log.ERROR, "MainActivity", "startProxyVpn: Network is not available.",null);
return;
}
if (!(context instanceof Activity)) {
Toast.makeText(context, "Context must be an Activity", Toast.LENGTH_SHORT).show();
LogFileUtil.logAndWrite(Log.ERROR, "MainActivity", "startProxyVpn: Context is not an Activity.",null);
return;
}
try {
ClashUtil.startProxy(context); // 在主线程中调用
ClashUtil.switchProxyGroup("GLOBAL", "us", "http://127.0.0.1:6170");
} catch (Exception e) {
LogFileUtil.logAndWrite(Log.ERROR, "MainActivity", "startProxyVpn: Failed to start VPN",e);
Toast.makeText(context, "Failed to start VPN: " + (e.getMessage() != null ? e.getMessage() : "Unknown error"), Toast.LENGTH_SHORT).show();
}
}
}

View File

@ -1,4 +1,4 @@
<resources> <resources>
<string name="app_name">study_app</string> <string name="app_name">Retention</string>
<string name="accessibility_service_description">This is an accessibility service.</string> <string name="accessibility_service_description">This is an accessibility service.</string>
</resources> </resources>

View File

@ -138,7 +138,7 @@ public class TaskUtilTest {
public void testGetDeviceInfoSync_Success() throws Exception { public void testGetDeviceInfoSync_Success() throws Exception {
// 运行上传方法 // 运行上传方法
TaskUtil.getDeviceInfoSync("b3d893cf9de3a85a"); // TaskUtil.getDeviceInfoSync("b3d893cf9de3a85a");
} }
// @Test // @Test