diff --git a/app/build.gradle b/app/build.gradle
index 3317bad..4ce4220 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -8,7 +8,7 @@ android {
defaultConfig {
applicationId "com.example.studyapp"
- minSdk 24
+ minSdk 23
targetSdk 35
versionCode 1
versionName "1.0"
@@ -73,4 +73,11 @@ dependencies {
// 如果需要 RxJava 支持(可选)
implementation 'com.squareup.retrofit2:adapter-rxjava3:2.9.0'
+
+ // 添加 Mockito 核心依赖
+ testImplementation 'org.mockito:mockito-core:5.4.0'
+
+ // 如果需要在 Android Instrumented Tests 中使用 Mockito
+ androidTestImplementation 'org.mockito:mockito-android:5.4.0'
+
}
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 8ac24cf..df578f1 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -20,6 +20,11 @@
+
+
+
+
+
-
-
-
-
-
+ android:foregroundServiceType="mediaProjection"
+ android:exported="true">
diff --git a/app/src/main/java/com/example/studyapp/MainActivity.java b/app/src/main/java/com/example/studyapp/MainActivity.java
index 1082467..b7426ef 100644
--- a/app/src/main/java/com/example/studyapp/MainActivity.java
+++ b/app/src/main/java/com/example/studyapp/MainActivity.java
@@ -2,7 +2,6 @@ package com.example.studyapp;
import android.app.Activity;
import android.app.AlertDialog;
-import android.content.BroadcastReceiver;
import android.net.Uri;
import android.content.Context;
import android.content.Intent;
@@ -31,16 +30,15 @@ import androidx.work.WorkManager;
import com.example.studyapp.autoJS.AutoJsUtil;
import com.example.studyapp.device.ChangeDeviceInfoUtil;
-import com.example.studyapp.utils.ClashUtil;
+import com.example.studyapp.proxy.ClashUtil;
+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.ExecutorService;
-import java.util.concurrent.Executors;
-import java.util.concurrent.Future;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
-import java.util.concurrent.TimeoutException;
public class MainActivity extends AppCompatActivity {
@@ -69,6 +67,8 @@ public class MainActivity extends AppCompatActivity {
"ge", "ps"
};
+ public static String androidId;
+
// 初始化 ExecutorService
private void initializeExecutorService() {
if (executorService == null || executorService.isShutdown()) {
@@ -82,6 +82,30 @@ public class MainActivity extends AppCompatActivity {
}
}
+ /**
+ * 获取 Android 设备的 ANDROID_ID
+ *
+ * @param context 应用上下文
+ * @return 设备的 ANDROID_ID,若无法获取,则返回 null
+ */
+ private void getAndroidId(Context context) {
+ if (context == null) {
+ throw new IllegalArgumentException("Context cannot be null");
+ }
+ executorService.submit(() -> {
+ try {
+ androidId = Settings.Secure.getString(
+ context.getContentResolver(),
+ Settings.Secure.ANDROID_ID
+ );
+ } catch (Exception e) {
+ Log.e("MainActivity", "getAndroidId: Failed to get ANDROID_ID", e);
+ }
+ });
+ }
+
+ private static final int REQUEST_CODE_PERMISSIONS = 100;
+
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -89,6 +113,7 @@ public class MainActivity extends AppCompatActivity {
instance = new WeakReference<>(this);
initializeExecutorService();
+ getAndroidId(this);
System.setProperty("java.library.path", this.getApplicationInfo().nativeLibraryDir);
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) {
// 针对 Android 10 或更低版本检查普通存储权限
@@ -110,6 +135,16 @@ public class MainActivity extends AppCompatActivity {
startActivityForResult(intent, ALLOW_ALL_FILES_ACCESS_PERMISSION_CODE);
}
}
+ // 添加对 FOREGROUND_SERVICE 权限的检查和请求
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { // 判断 Android 13+
+ String[] requiredPermissions = {
+ android.Manifest.permission.FOREGROUND_SERVICE_MEDIA_PROJECTION,
+ "android.permission.CAPTURE_VIDEO_OUTPUT"
+ };
+ ActivityCompat.requestPermissions(this, requiredPermissions, REQUEST_CODE_PERMISSIONS);
+ } else {
+ Toast.makeText(this, "当前设备不支持这些权限", Toast.LENGTH_SHORT).show();
+ }
if (!isNetworkAvailable(this)) {
Toast.makeText(this, "Network is not available", Toast.LENGTH_SHORT).show();
@@ -123,7 +158,7 @@ public class MainActivity extends AppCompatActivity {
// 初始化按钮
Button runScriptButton = findViewById(R.id.run_script_button);
if (runScriptButton != null) {
- runScriptButton.setOnClickListener(v -> AutoJsUtil.runAutojsScript(this,""));
+ runScriptButton.setOnClickListener(v -> AutoJsUtil.runAutojsScript(this));
} else {
Toast.makeText(this, "Button not found", Toast.LENGTH_SHORT).show();
}
@@ -164,7 +199,7 @@ public class MainActivity extends AppCompatActivity {
}
// 初始化 ChangeDeviceInfoUtil
- ChangeDeviceInfoUtil.initialize("US", 2);
+ ChangeDeviceInfoUtil.initialize("US", 2, this);
// 获取输入框和按钮
EditText inputNumber = findViewById(R.id.input_number);
Button executeButton = findViewById(R.id.execute_button);
@@ -237,13 +272,13 @@ public class MainActivity extends AppCompatActivity {
AutoJsUtil.flag = true; // 广播状态更新
}
- for (int i = 0; i < number; i++) {
+ while (true) {
synchronized (taskLock) {
while (!AutoJsUtil.flag) {
taskLock.wait(30000);
}
- Log.d("MainActivity", "任务执行第:" + i);
- executeSingleLogic(i);
+ executeSingleLogic();
+ TaskUtil.execSaveTask(this);
}
}
} catch (InterruptedException e) {
@@ -257,14 +292,11 @@ public class MainActivity extends AppCompatActivity {
public static final Object broadcastLock = new Object(); // 广播锁
public static final Object taskLock = new Object(); // 任务逻辑锁
- public void executeSingleLogic(int i) {
- Log.i("MainActivity", "executeSingleLogic: Start execution for index " + i);
- long startTime = System.currentTimeMillis(); // 开始计时
+ public void executeSingleLogic() {
Log.i("MainActivity", "executeSingleLogic: Proxy not active, starting VPN");
startProxyVpn(this);
- Log.i("MainActivity", "executeSingleLogic: Switching proxy group to " + proxyNames[i]);
try {
ClashUtil.switchProxyGroup("GLOBAL", "us", "http://127.0.0.1:6170");
} catch (Exception e) {
@@ -273,15 +305,10 @@ public class MainActivity extends AppCompatActivity {
}
Log.i("MainActivity", "executeSingleLogic: Changing device info");
- String url = ChangeDeviceInfoUtil.changeDeviceInfo(getPackageName(), this);
+ ChangeDeviceInfoUtil.changeDeviceInfo(getPackageName(), this);
Log.i("MainActivity", "executeSingleLogic: Running AutoJs script");
- AutoJsUtil.runAutojsScript(this, url);
-
- runOnUiThread(() -> Toast.makeText(this, "第 " + (i + 1) + " 次执行完成", Toast.LENGTH_SHORT).show());
-
- long endTime = System.currentTimeMillis(); // 结束计时
- Log.i("MainActivity", "executeSingleLogic: Finished execution for index " + i + " in " + (endTime - startTime) + " ms");
+ AutoJsUtil.runAutojsScript(this);
}
private void startProxyVpn(Context context) {
@@ -315,8 +342,30 @@ public class MainActivity extends AppCompatActivity {
showPermissionExplanationDialog();
}
}
+ if (requestCode == REQUEST_CODE_PERMISSIONS) {
+ boolean allGranted = true;
+ for (int result : grantResults) {
+ if (result != PackageManager.PERMISSION_GRANTED) {
+ allGranted = false;
+ break;
+ }
+ }
+
+ if (allGranted) {
+ // 所有权限已授予
+ startMyForegroundService();
+ } else {
+ Toast.makeText(this, "未授予必要权限,请检查设置", Toast.LENGTH_SHORT).show();
+ }
+ }
}
+ private void startMyForegroundService() {
+ Intent serviceIntent = new Intent(this, MyAccessibilityService.class);
+ ContextCompat.startForegroundService(this, serviceIntent);
+ }
+
+
@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
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 44e48ea..623d671 100644
--- a/app/src/main/java/com/example/studyapp/autoJS/AutoJsUtil.java
+++ b/app/src/main/java/com/example/studyapp/autoJS/AutoJsUtil.java
@@ -3,6 +3,7 @@ package com.example.studyapp.autoJS;
import static androidx.core.content.ContextCompat.startActivity;
import static com.example.studyapp.MainActivity.broadcastLock;
import static com.example.studyapp.MainActivity.taskLock;
+import static com.example.studyapp.task.TaskUtil.infoUpload;
import android.Manifest;
import android.content.ActivityNotFoundException;
@@ -26,6 +27,7 @@ import com.example.studyapp.service.CloudPhoneManageService;
import java.io.File;
+import java.io.IOException;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
@@ -38,7 +40,7 @@ public class AutoJsUtil {
public static volatile boolean flag;
private static int count;
- public static void runAutojsScript(Context context,String url) {
+ public static void runAutojsScript(Context context) {
// 检查脚本文件
Log.i("AutoJsUtil", "-------脚本运行开始:--------"+ count++ );
File scriptFile = new File(Environment.getExternalStorageDirectory(), "script/main.js");
@@ -58,7 +60,6 @@ public class AutoJsUtil {
Intent intent = new Intent();
intent.setClassName("org.autojs.autojs6", "org.autojs.autojs.external.open.RunIntentActivity");
intent.putExtra("path", scriptFile.getAbsolutePath());
- intent.putExtra("url", url);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
try {
context.startActivity(intent);
@@ -85,6 +86,13 @@ public class AutoJsUtil {
AutoJsUtil.flag = true;
}
synchronized (taskLock) {
+ try {
+ infoUpload(context, MainActivity.androidId, scriptResult);
+ } catch (IOException e) {
+ // 例如:可以显示给用户一条错误消息
+ Log.e("AutoJsUtil", "File upload failed: " + e.getMessage());
+ }
+
taskLock.notifyAll(); // 唤醒任务线程
}
}
@@ -129,10 +137,7 @@ public class AutoJsUtil {
}
private static final String AUTOJS_SCRIPT_FINISHED_ACTION = "org.autojs.SCRIPT_FINISHED";
- private static final String SCRIPT_RESULT_KEY = "result";
- private static final Object lock = new Object();
-
-
+ private static final String SCRIPT_RESULT_KEY = "package";
public static void stopAutojsScript(Context context) {
// 停止运行脚本的 Intent
@@ -157,5 +162,4 @@ public class AutoJsUtil {
Log.e("AutoJsUtil", "目标活动未找到: org.autojs.autojs.external.open.StopServiceActivity");
}
}
-
}
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 4af97db..00615c6 100644
--- a/app/src/main/java/com/example/studyapp/device/ChangeDeviceInfoUtil.java
+++ b/app/src/main/java/com/example/studyapp/device/ChangeDeviceInfoUtil.java
@@ -2,24 +2,21 @@ package com.example.studyapp.device;
import android.content.ContentResolver;
import android.content.Context;
-import android.net.ConnectivityManager;
-import android.net.Network;
-import android.net.NetworkCapabilities;
import android.net.Uri;
-import android.text.TextUtils;
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;
+import com.example.studyapp.task.TaskUtil;
import com.example.studyapp.utils.HttpUtil;
import com.example.studyapp.utils.ShellUtils;
-import com.google.android.gms.ads.identifier.AdvertisingIdClient;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
-import java.util.HashMap;
-import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
-import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
@@ -28,9 +25,9 @@ import java.lang.reflect.Method;
public class ChangeDeviceInfoUtil {
- private static JSONObject bigoDeviceObject;
+ private static JSONObject bigoDeviceObject;
- private static JSONObject afDeviceObject;
+ private static JSONObject afDeviceObject;
public static String buildBigoUrl(String country, int tag) {
return Uri.parse("http://8.217.137.25/tt/zj/dispatcher!bigo.do")
@@ -51,30 +48,65 @@ public class ChangeDeviceInfoUtil {
// 创建一个线程池用于执行网络任务
private static final ExecutorService executorService = Executors.newSingleThreadExecutor();
- public static void initialize(String country, int tag) {
+ public static void initialize(String country, int tag, MainActivity mainActivity) {
executorService.submit(() -> {
try {
- String bigoJson = HttpUtil.requestGet(buildBigoUrl(country, tag));
- String afJson = HttpUtil.requestGet(buildAfUrl(country, tag ));
-
- bigoDeviceObject = new JSONObject(bigoJson).optJSONObject("device");
- afDeviceObject = new JSONObject(afJson).optJSONObject("device");
-
- if (bigoDeviceObject == null || afDeviceObject == null) {
- throw new JSONException("Device object is missing in the response JSON");
+ // 发起网络请求并捕获可能的异常
+ String bigoJson;
+ String afJson;
+ try {
+ bigoJson = HttpUtil.requestGet(buildBigoUrl(country, tag));
+ afJson = HttpUtil.requestGet(buildAfUrl(country, tag));
+ } catch (IOException ioException) {
+ Log.e("Error", "Network request failed", ioException);
+ return;
}
- Log.d("Debug", "bigoDeviceObject: " + bigoDeviceObject.toString());
- Log.d("Debug", "afDeviceObject: " + afDeviceObject.toString());
+ // 执行查询任务
+ String response;
+ try {
+ response = TaskUtil.execQueryTask(mainActivity);
+ } catch (Exception e) {
+ Log.e("Error", "Task execution failed", e);
+ return;
+ }
+
+ // 解析 JSON 数据
+ JSONObject bigoDeviceObject;
+ JSONObject afDeviceObject;
+ try {
+ if (response != null) {
+ JSONObject responseJson = new JSONObject(response);
+ bigoDeviceObject = responseJson.optJSONObject("bigoDeviceObject");
+ afDeviceObject = responseJson.optJSONObject("afDeviceObject");
+ } else {
+ bigoDeviceObject = new JSONObject(bigoJson).optJSONObject("device");
+ afDeviceObject = new JSONObject(afJson).optJSONObject("device");
+ }
+ } catch (JSONException e) {
+ Log.e("Error", "Failed to parse JSON", e);
+ return;
+ }
+
+ // 检查解析结果
+ if (bigoDeviceObject == null || afDeviceObject == null) {
+ Log.e("Error", "Device object is missing in response");
+ return;
+ }
+
+ // 输出结果(附加空检查)
+ Log.d("Debug", "bigoDeviceObject: " + (bigoDeviceObject != null ? bigoDeviceObject.toString() : "null"));
+ Log.d("Debug", "afDeviceObject: " + (afDeviceObject != null ? afDeviceObject.toString() : "null"));
+
} catch (Exception e) {
- Log.e("Error", "Failed to load or parse the response JSON", e);
+ Log.e("Error", "Unexpected error occurred", e);
}
});
}
- public static String changeDeviceInfo(String current_pkg_name, Context context) {
+ public static void changeDeviceInfo(String current_pkg_name, Context context) {
if (bigoDeviceObject == null || afDeviceObject == null) {
Log.e("ChangeDeviceInfoUtil", "Required device JSON objects are not initialized");
@@ -95,14 +127,31 @@ public class ChangeDeviceInfoUtil {
String resolution = bigoDeviceObject.optString("resolution");
String vendor = bigoDeviceObject.optString("vendor");
int batteryScale = bigoDeviceObject.optInt("bat_scale");
- //String model = deviceObject.optString("model");
+ // String model = deviceObject.optString("model");
String net = bigoDeviceObject.optString("net");
int dpi = bigoDeviceObject.optInt("dpi");
long romFreeExt = bigoDeviceObject.optLong("rom_free_ext");
String dpiF = bigoDeviceObject.optString("dpi_f");
int cpuCoreNum = bigoDeviceObject.optInt("cpu_core_num");
- //AF
+ BigoInfo bigoDevice = new BigoInfo();
+ bigoDevice.cpuClockSpeed = cpuClockSpeed;
+ bigoDevice.gaid = gaid;
+ bigoDevice.userAgent = userAgent;
+ bigoDevice.osLang = osLang;
+ bigoDevice.osVer = osVer;
+ bigoDevice.tz = tz;
+ bigoDevice.systemCountry = systemCountry;
+ bigoDevice.simCountry = simCountry;
+ bigoDevice.romFreeIn = romFreeIn;
+ bigoDevice.resolution = resolution;
+ bigoDevice.vendor = vendor;
+ bigoDevice.batteryScale = batteryScale;
+ bigoDevice.net = net;
+ bigoDevice.dpi = dpi;
+ bigoDevice.romFreeExt = romFreeExt;
+ bigoDevice.dpiF = dpiF;
+ bigoDevice.cpuCoreNum = cpuCoreNum;
String advertiserId = afDeviceObject.optString(".advertiserId");
String model = afDeviceObject.optString(".model");
String brand = afDeviceObject.optString(".brand");
@@ -118,33 +167,93 @@ public class ChangeDeviceInfoUtil {
String langCode = afDeviceObject.optString(".lang_code");
String cpuAbi = afDeviceObject.optString(".deviceData.cpu_abi");
int yDp = afDeviceObject.optInt(".deviceData.dim.ydp");
+ TaskUtil.setBigoDevice(bigoDevice);
+
+ AfInfo afDevice = new AfInfo();
+ afDevice.advertiserId = advertiserId;
+ afDevice.model = model;
+ afDevice.brand = brand;
+ afDevice.androidId = androidId;
+ afDevice.xPixels = xPixels;
+ afDevice.yPixels = yPixels;
+ afDevice.densityDpi = densityDpi;
+ afDevice.country = country;
+ afDevice.batteryLevel = batteryLevel;
+ afDevice.stackInfo = stackInfo;
+ afDevice.product = product;
+ afDevice.network = network;
+ afDevice.langCode = langCode;
+ afDevice.cpuAbi = cpuAbi;
+ afDevice.yDp = yDp;
+ TaskUtil.setAfDevice(afDevice);
+
String lang = afDeviceObject.optString(".lang");
+ String ro_product_brand = afDeviceObject.optString("ro.product.brand", "");
+ String ro_product_model = afDeviceObject.optString("ro.product.model", "");
+ String ro_product_manufacturer = afDeviceObject.optString("ro.product.manufacturer", "");
+ String ro_product_device = afDeviceObject.optString("ro.product.device", "");
+ String ro_product_name = afDeviceObject.optString("ro.product.name", "");
+ String ro_build_version_incremental = afDeviceObject.optString("ro.build.version.incremental", "");
+ String ro_build_fingerprint = afDeviceObject.optString("ro.build.fingerprint", "");
+ String ro_odm_build_fingerprint = afDeviceObject.optString("ro.odm.build.fingerprint", "");
+ String ro_product_build_fingerprint = afDeviceObject.optString("ro.product.build.fingerprint", "");
+ String ro_system_build_fingerprint = afDeviceObject.optString("ro.system.build.fingerprint", "");
+ String ro_system_ext_build_fingerprint = afDeviceObject.optString("ro.system_ext.build.fingerprint", "");
+ String ro_vendor_build_fingerprint = afDeviceObject.optString("ro.vendor.build.fingerprint", "");
+ String ro_build_platform = afDeviceObject.optString("ro.board.platform", "");
+ String persist_sys_cloud_drm_id = afDeviceObject.optString("persist.sys.cloud.drm.id", "");
+ int persist_sys_cloud_battery_capacity = afDeviceObject.optInt("persist.sys.cloud.battery.capacity", -1);
+ String persist_sys_cloud_gpu_gl_vendor = afDeviceObject.optString("persist.sys.cloud.gpu.gl_vendor", "");
+ String persist_sys_cloud_gpu_gl_renderer = afDeviceObject.optString("persist.sys.cloud.gpu.gl_renderer", "");
+ String persist_sys_cloud_gpu_gl_version = afDeviceObject.optString("persist.sys.cloud.gpu.gl_version", "");
+ String persist_sys_cloud_gpu_egl_vendor = afDeviceObject.optString("persist.sys.cloud.gpu.egl_vendor", "");
+ String persist_sys_cloud_gpu_egl_version = afDeviceObject.optString("persist.sys.cloud.gpu.egl_version", "");
+ DeviceInfo deviceInfo = new DeviceInfo();
+ deviceInfo.lang = lang;
+ deviceInfo.roProductBrand = ro_product_brand;
+ deviceInfo.roProductModel = ro_product_model;
+ deviceInfo.roProductManufacturer = ro_product_manufacturer;
+ deviceInfo.roProductDevice = ro_product_device;
+ deviceInfo.roProductName = ro_product_name;
+ deviceInfo.roBuildVersionIncremental = ro_build_version_incremental;
+ deviceInfo.roBuildFingerprint = ro_build_fingerprint;
+ deviceInfo.roOdmBuildFingerprint = ro_odm_build_fingerprint;
+ deviceInfo.roProductBuildFingerprint = ro_product_build_fingerprint;
+ deviceInfo.roSystemBuildFingerprint = ro_system_build_fingerprint;
+ deviceInfo.roSystemExtBuildFingerprint = ro_system_ext_build_fingerprint;
+ deviceInfo.roVendorBuildFingerprint = ro_vendor_build_fingerprint;
+ deviceInfo.roBuildPlatform = ro_build_platform;
+ deviceInfo.persistSysCloudDrmId = persist_sys_cloud_drm_id;
+ deviceInfo.persistSysCloudBatteryCapacity = persist_sys_cloud_battery_capacity;
+ deviceInfo.persistSysCloudGpuGlVendor = persist_sys_cloud_gpu_gl_vendor;
+ deviceInfo.persistSysCloudGpuGlRenderer = persist_sys_cloud_gpu_gl_renderer;
+ deviceInfo.persistSysCloudGpuGlVersion = persist_sys_cloud_gpu_gl_version;
+ deviceInfo.persistSysCloudGpuEglVendor = persist_sys_cloud_gpu_egl_vendor;
+ deviceInfo.persistSysCloudGpuEglVersion = persist_sys_cloud_gpu_egl_version;
+ TaskUtil.setDeviceInfo(deviceInfo);
-
- String url = "https://app.appsflyer.com/com.gateio.gateio?pid=seikoads_int&af_siteid={aff}&c=Cj4jwOBf&af_sub_siteid={aff_sub6}&af_c_id={offer_id}&af_ad={adx_bundle_id}&af_ad_id={affiliate_id}&af_adset_id={offer_id}&af_channel={adx_id}&af_cost_currency={currency}&af_cost_value={payout}&af_adset={transaction_id}&af_click_lookback=7d&af_ip={ip}&af_lang={aff_sub4}&af_ua={ua}&clickid={transaction_id}&advertising_id={aff_sub3}&idfa={aff_sub3}&af_model={model}&af_os_version={os_version}&is_incentivized=false&af_prt=huiimedia";
- Map params = new HashMap<>();
- params.put("aff", "12345");
- params.put("aff_sub6", "sub6Value");
- params.put("offer_id", "offer123");
- params.put("adx_bundle_id", "adxBundle123");
- params.put("affiliate_id", "affiliateID123");
- params.put("currency", "USD");
- params.put("payout", "5.0");
- params.put("transaction_id","");
- params.put("ip",HttpUtil.getLocalIpAddress());
- params.put("aff_sub4", "English");
- params.put("aff_sub3", "AdvertisingID123");
-
- params.put("adx_id", advertiserId);
- params.put("ua",userAgent);
- params.put("model", model);
- params.put("os_version", osVer);
+ String global_android_id = afDeviceObject.optString(".android_id", "");
+ String anticheck_pkgs = afDeviceObject.optString(".anticheck_pkgs", "");
+ String pm_list_features = afDeviceObject.optString(".pm_list_features", "");
+ String pm_list_libraries = afDeviceObject.optString(".pm_list_libraries", "");
+ String system_http_agent = afDeviceObject.optString("system.http.agent", "");
+ String webkit_http_agent = afDeviceObject.optString("webkit.http.agent", "");
+ String com_fk_tools_pkgInfo = afDeviceObject.optString(".pkg_info", "");
+ String appsflyerKey = afDeviceObject.optString(".appsflyerKey", "");
+ String appUserId = afDeviceObject.optString(".appUserId", "");
+ String disk = afDeviceObject.optString(".disk", "");
+ String operator = afDeviceObject.optString(".operator", "");
+ String cell_mcc = afDeviceObject.optString(".cell.mcc", "");
+ String cell_mnc = afDeviceObject.optString(".cell.mnc", "");
+ String date1 = afDeviceObject.optString(".date1", "");
+ String date2 = afDeviceObject.optString(".date2", "");
+ String bootId = afDeviceObject.optString("BootId", "");
// 自动处理分辨率信息
// int widthPixels = Integer.parseInt(resolution.split("x")[0]);
// int heightPixels = Integer.parseInt(resolution.split("x")[1]);
-
+ //
// 更新屏幕显示相关参数
// JSONObject displayMetrics = new JSONObject();
// displayMetrics.put("widthPixels", widthPixels);
@@ -152,7 +261,7 @@ public class ChangeDeviceInfoUtil {
// displayMetrics.put("densityDpi", dpi);
// callVCloudSettings_put("screen.device.displayMetrics", displayMetrics.toString(), context);
- //BIGO 替换写死的值为 JSON 动态值
+ // BIGO 替换写死的值为 JSON 动态值
callVCloudSettings_put(current_pkg_name + ".system_country", systemCountry, context);
callVCloudSettings_put(current_pkg_name + ".sim_country", simCountry, context);
callVCloudSettings_put(current_pkg_name + ".rom_free_in", String.valueOf(romFreeIn), context);
@@ -160,7 +269,7 @@ public class ChangeDeviceInfoUtil {
callVCloudSettings_put(current_pkg_name + ".vendor", vendor, context);
callVCloudSettings_put(current_pkg_name + ".battery_scale", String.valueOf(batteryScale), context);
callVCloudSettings_put(current_pkg_name + ".os_lang", osLang, context);
- //callVCloudSettings_put(current_pkg_name + ".model", model, context);
+ // callVCloudSettings_put(current_pkg_name + ".model", model, context);
callVCloudSettings_put(current_pkg_name + ".net", net, context);
callVCloudSettings_put(current_pkg_name + ".dpi", String.valueOf(dpi), context);
callVCloudSettings_put(current_pkg_name + ".rom_free_ext", String.valueOf(romFreeExt), context);
@@ -177,7 +286,7 @@ public class ChangeDeviceInfoUtil {
// **tz** (时区)
callVCloudSettings_put(current_pkg_name + "_tz", tz, context);
- //AF 替换写死的值为 JSON 动态值
+ // AF 替换写死的值为 JSON 动态值
callVCloudSettings_put(current_pkg_name + ".advertiserId", advertiserId, context);
callVCloudSettings_put(current_pkg_name + ".model", model, context);
callVCloudSettings_put(current_pkg_name + ".brand", brand, context);
@@ -203,74 +312,34 @@ public class ChangeDeviceInfoUtil {
if (!ShellUtils.hasRootAccess()) {
Log.e("ChangeDeviceInfoUtil", "Root access is required to execute system property changes");
- return null;
}
- String ro_product_brand = afDeviceObject.optString("ro.product.brand", "");
- String ro_product_model = afDeviceObject.optString("ro.product.model", "");
- String ro_product_manufacturer = afDeviceObject.optString("ro.product.manufacturer", "");
- String ro_product_device = afDeviceObject.optString("ro.product.device", "");
- String ro_product_name = afDeviceObject.optString("ro.product.name", "");
- String ro_build_version_incremental = afDeviceObject.optString("ro.build.version.incremental", "");
- String ro_build_fingerprint = afDeviceObject.optString("ro.build.fingerprint", "");
- String ro_odm_build_fingerprint = afDeviceObject.optString("ro.odm.build.fingerprint", "");
- String ro_product_build_fingerprint = afDeviceObject.optString("ro.product.build.fingerprint", "");
- String ro_system_build_fingerprint = afDeviceObject.optString("ro.system.build.fingerprint", "");
- String ro_system_ext_build_fingerprint = afDeviceObject.optString("ro.system_ext.build.fingerprint", "");
- String ro_vendor_build_fingerprint = afDeviceObject.optString("ro.vendor.build.fingerprint", "");
- String ro_build_platform = afDeviceObject.optString("ro.board.platform", "");
- String persist_sys_cloud_drm_id = afDeviceObject.optString("persist.sys.cloud.drm.id", "");
- int persist_sys_cloud_battery_capacity = afDeviceObject.optInt("persist.sys.cloud.battery.capacity", -1);
- String persist_sys_cloud_gpu_gl_vendor = afDeviceObject.optString("persist.sys.cloud.gpu.gl_vendor", "");
- String persist_sys_cloud_gpu_gl_renderer = afDeviceObject.optString("persist.sys.cloud.gpu.gl_renderer", "");
- String persist_sys_cloud_gpu_gl_version = afDeviceObject.optString("persist.sys.cloud.gpu.gl_version", "");
- String persist_sys_cloud_gpu_egl_vendor = afDeviceObject.optString("persist.sys.cloud.gpu.egl_vendor", "");
- String persist_sys_cloud_gpu_egl_version = afDeviceObject.optString("persist.sys.cloud.gpu.egl_version", "");
- String global_android_id = afDeviceObject.optString(".android_id", "");
- String anticheck_pkgs = afDeviceObject.optString(".anticheck_pkgs", "");
- String pm_list_features = afDeviceObject.optString(".pm_list_features", "");
- String pm_list_libraries = afDeviceObject.optString(".pm_list_libraries", "");
- String system_http_agent = afDeviceObject.optString("system.http.agent", "");
- String webkit_http_agent = afDeviceObject.optString("webkit.http.agent", "");
- String com_fk_tools_pkgInfo = afDeviceObject.optString(".pkg_info", "");
- String appsflyerKey = afDeviceObject.optString(".appsflyerKey", "");
- String appUserId = afDeviceObject.optString(".appUserId", "");
- String disk = afDeviceObject.optString(".disk", "");
- String operator = afDeviceObject.optString(".operator", "");
- String cell_mcc = afDeviceObject.optString(".cell.mcc", "");
- String cell_mnc = afDeviceObject.optString(".cell.mnc", "");
- String date1 = afDeviceObject.optString(".date1", "");
- String date2 = afDeviceObject.optString(".date2", "");
- String bootId = afDeviceObject.optString("BootId", "");
// 设置机型, 直接设置属性
ShellUtils.execRootCmd("setprop ro.product.brand " + ro_product_brand);
- ShellUtils.execRootCmd("setprop ro.product.model "+ ro_product_model );
- ShellUtils.execRootCmd("setprop ro.product.manufacturer "+ro_product_manufacturer );
- ShellUtils.execRootCmd("setprop ro.product.device "+ ro_product_device);
- ShellUtils.execRootCmd("setprop ro.product.name "+ro_product_name );
- ShellUtils.execRootCmd("setprop ro.build.version.incremental "+ro_build_version_incremental);
- ShellUtils.execRootCmd("setprop ro.build.fingerprint "+ro_build_fingerprint );
- ShellUtils.execRootCmd("setprop ro.odm.build.fingerprint "+ro_odm_build_fingerprint );
- ShellUtils.execRootCmd("setprop ro.product.build.fingerprint "+ro_product_build_fingerprint );
- ShellUtils.execRootCmd("setprop ro.system.build.fingerprint "+ro_system_build_fingerprint );
- ShellUtils.execRootCmd("setprop ro.system_ext.build.fingerprint "+ro_system_ext_build_fingerprint );
- ShellUtils.execRootCmd("setprop ro.vendor.build.fingerprint "+ro_vendor_build_fingerprint );
- ShellUtils.execRootCmd("setprop ro.board.platform "+ro_build_platform );
+ ShellUtils.execRootCmd("setprop ro.product.model " + ro_product_model);
+ ShellUtils.execRootCmd("setprop ro.product.manufacturer " + ro_product_manufacturer);
+ ShellUtils.execRootCmd("setprop ro.product.device " + ro_product_device);
+ ShellUtils.execRootCmd("setprop ro.product.name " + ro_product_name);
+ ShellUtils.execRootCmd("setprop ro.build.version.incremental " + ro_build_version_incremental);
+ ShellUtils.execRootCmd("setprop ro.build.fingerprint " + ro_build_fingerprint);
+ ShellUtils.execRootCmd("setprop ro.odm.build.fingerprint " + ro_odm_build_fingerprint);
+ ShellUtils.execRootCmd("setprop ro.product.build.fingerprint " + ro_product_build_fingerprint);
+ ShellUtils.execRootCmd("setprop ro.system.build.fingerprint " + ro_system_build_fingerprint);
+ ShellUtils.execRootCmd("setprop ro.system_ext.build.fingerprint " + ro_system_ext_build_fingerprint);
+ ShellUtils.execRootCmd("setprop ro.vendor.build.fingerprint " + ro_vendor_build_fingerprint);
+ ShellUtils.execRootCmd("setprop ro.board.platform " + ro_build_platform);
- // Native.setBootId(bootId);
+ // Native.setBootId(bootId);
// 修改drm id
- ShellUtils.execRootCmd("setprop persist.sys.cloud.drm.id "+persist_sys_cloud_drm_id);
+ ShellUtils.execRootCmd("setprop persist.sys.cloud.drm.id " + persist_sys_cloud_drm_id);
// 电量模拟需要大于1000
- ShellUtils.execRootCmd("setprop persist.sys.cloud.battery.capacity "+persist_sys_cloud_battery_capacity);
- ShellUtils.execRootCmd("setprop persist.sys.cloud.gpu.gl_vendor "+persist_sys_cloud_gpu_gl_vendor);
- ShellUtils.execRootCmd("setprop persist.sys.cloud.gpu.gl_renderer "+persist_sys_cloud_gpu_gl_renderer);
+ ShellUtils.execRootCmd("setprop persist.sys.cloud.battery.capacity " + persist_sys_cloud_battery_capacity);
+ ShellUtils.execRootCmd("setprop persist.sys.cloud.gpu.gl_vendor " + persist_sys_cloud_gpu_gl_vendor);
+ ShellUtils.execRootCmd("setprop persist.sys.cloud.gpu.gl_renderer " + persist_sys_cloud_gpu_gl_renderer);
// 这个值不能随便改 必须是 OpenGL ES %d.%d 这个格式
- ShellUtils.execRootCmd("setprop persist.sys.cloud.gpu.gl_version "+persist_sys_cloud_gpu_gl_version);
- ShellUtils.execRootCmd("setprop persist.sys.cloud.gpu.egl_vendor "+persist_sys_cloud_gpu_egl_vendor);
- ShellUtils.execRootCmd("setprop persist.sys.cloud.gpu.egl_version "+persist_sys_cloud_gpu_egl_version);
-
- // 填充占位符
- return HttpUtil.fillUrlPlaceholders(url, params);
+ ShellUtils.execRootCmd("setprop persist.sys.cloud.gpu.gl_version " + persist_sys_cloud_gpu_gl_version);
+ ShellUtils.execRootCmd("setprop persist.sys.cloud.gpu.egl_vendor " + persist_sys_cloud_gpu_egl_vendor);
+ ShellUtils.execRootCmd("setprop persist.sys.cloud.gpu.egl_version " + persist_sys_cloud_gpu_egl_version);
} catch (Throwable e) {
Log.e("ChangeDeviceInfoUtil", "Error occurred while changing device info", e);
throw new RuntimeException("Error occurred in changeDeviceInfo", e);
diff --git a/app/src/main/java/com/example/studyapp/device/DeviceConfiguration.json b/app/src/main/java/com/example/studyapp/device/DeviceConfiguration.json
new file mode 100644
index 0000000..4756d93
--- /dev/null
+++ b/app/src/main/java/com/example/studyapp/device/DeviceConfiguration.json
@@ -0,0 +1,63 @@
+{
+ "cpuClockSpeed": "cpu_clock_speed_value",
+ "gaid": "gaid_value",
+ "userAgent": "User-Agent_value",
+ "osLang": "os_lang_value",
+ "osVer": "os_ver_value",
+ "tz": "tz_value",
+ "systemCountry": "system_country_value",
+ "simCountry": "sim_country_value",
+ "romFreeIn": "rom_free_in_value",
+ "resolution": "resolution_value",
+ "vendor": "vendor_value",
+ "batteryScale": "bat_scale_value",
+ "net": "net_value",
+ "dpi": "dpi_value",
+ "romFreeExt": "rom_free_ext_value",
+ "dpiF": "dpi_f_value",
+ "cpuCoreNum": "cpu_core_num_value",
+ "afDeviceObject": {
+ "advertiserId": "advertiserId_value",
+ "model": "model_value",
+ "brand": "brand_value",
+ "androidId": "android_id_value",
+ "xPixels": "x_px_value",
+ "yPixels": "y_px_value",
+ "densityDpi": "density_dpi_value",
+ "country": "country_value",
+ "batteryLevel": "batteryLevel_value",
+ "stackInfo": "stack_info_value",
+ "product": "product_value",
+ "network": "network_value",
+ "langCode": "lang_code_value",
+ "cpuAbi": "cpu_abi_value",
+ "yDp": "ydp_value",
+ "lang": "lang_value",
+ "roProductDetails": {
+ "brand": "ro_product_brand_value",
+ "model": "ro_product_model_value",
+ "manufacturer": "ro_product_manufacturer_value",
+ "device": "ro_product_device_value",
+ "name": "ro_product_name_value"
+ },
+ "roBuildDetails": {
+ "versionIncremental": "ro_build_version_incremental_value",
+ "fingerprint": "ro_build_fingerprint_value",
+ "productBuildFingerprint": "ro_product_build_fingerprint_value",
+ "systemBuildFingerprint": "ro_system_build_fingerprint_value",
+ "systemExtBuildFingerprint": "ro_system_ext_build_fingerprint_value",
+ "vendorBuildFingerprint": "ro_vendor_build_fingerprint_value"
+ },
+ "cloudProperties": {
+ "gpuProperties": {
+ "glVendor": "persist_sys_cloud_gpu_gl_vendor_value",
+ "glRenderer": "persist_sys_cloud_gpu_gl_renderer_value",
+ "glVersion": "persist_sys_cloud_gpu_gl_version_value",
+ "eglVendor": "persist_sys_cloud_gpu_egl_vendor_value",
+ "eglVersion": "persist_sys_cloud_gpu_egl_version_value"
+ },
+ "drmId": "persist_sys_cloud_drm_id_value",
+ "batteryCapacity": "persist_sys_cloud_battery_capacity_value"
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/studyapp/utils/ClashUtil.java b/app/src/main/java/com/example/studyapp/proxy/ClashUtil.java
similarity index 98%
rename from app/src/main/java/com/example/studyapp/utils/ClashUtil.java
rename to app/src/main/java/com/example/studyapp/proxy/ClashUtil.java
index ebf94d8..0bc9528 100644
--- a/app/src/main/java/com/example/studyapp/utils/ClashUtil.java
+++ b/app/src/main/java/com/example/studyapp/proxy/ClashUtil.java
@@ -1,4 +1,4 @@
-package com.example.studyapp.utils;
+package com.example.studyapp.proxy;
import android.content.BroadcastReceiver;
import android.content.Context;
@@ -10,7 +10,6 @@ import java.io.IOException;
import java.util.concurrent.CountDownLatch;
import okhttp3.Call;
import okhttp3.Callback;
-import okhttp3.Credentials;
import okhttp3.HttpUrl;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
diff --git a/app/src/main/java/com/example/studyapp/service/MyAccessibilityService.java b/app/src/main/java/com/example/studyapp/service/MyAccessibilityService.java
index 40b975c..36b0edc 100644
--- a/app/src/main/java/com/example/studyapp/service/MyAccessibilityService.java
+++ b/app/src/main/java/com/example/studyapp/service/MyAccessibilityService.java
@@ -1,16 +1,22 @@
package com.example.studyapp.service;
+import android.Manifest;
import android.accessibilityservice.AccessibilityService;
+import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ServiceInfo;
import android.os.Build;
import android.os.IBinder;
import android.view.accessibility.AccessibilityEvent;
+import android.widget.Toast;
import androidx.core.app.NotificationCompat;
+import androidx.core.content.ContextCompat;
import com.example.studyapp.MainActivity;
import com.example.studyapp.R;
@@ -35,28 +41,56 @@ public class MyAccessibilityService extends AccessibilityService {
private void createNotificationChannel() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
- String channelId = "2";
- String channelName = "Foreground Service";
- int importance = NotificationManager.IMPORTANCE_LOW;
- NotificationChannel channel = new NotificationChannel(channelId, channelName, importance);
- NotificationManager notificationManager = getSystemService(NotificationManager.class);
- if (notificationManager != null) {
- notificationManager.createNotificationChannel(channel);
+ NotificationChannel channel = new NotificationChannel(
+ "2",
+ "无障碍服务",
+ NotificationManager.IMPORTANCE_LOW
+ );
+ channel.setDescription("此服务在后台运行,提供无障碍支持。");
+ NotificationManager manager = getSystemService(NotificationManager.class);
+ if (manager != null) {
+ manager.createNotificationChannel(channel);
}
}
}
private void startForegroundService() {
createNotificationChannel();
+
Intent notificationIntent = new Intent(this, MainActivity.class);
int pendingIntentFlags = Build.VERSION.SDK_INT >= Build.VERSION_CODES.M ? PendingIntent.FLAG_IMMUTABLE : 0;
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, pendingIntentFlags);
+
NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this, "2")
.setContentTitle("无障碍服务运行中")
.setContentText("此服务正在持续运行")
.setSmallIcon(R.drawable.ic_launcher_foreground)
.setContentIntent(pendingIntent);
- android.app.Notification notification = notificationBuilder.build();
- startForeground(1, notification);
+
+ Notification notification = notificationBuilder.build();
+
+ if (ContextCompat.checkSelfPermission(this, Manifest.permission.FOREGROUND_SERVICE_MEDIA_PROJECTION)
+ != PackageManager.PERMISSION_GRANTED) {
+ Toast.makeText(this, "请授予前台服务权限以启动服务", Toast.LENGTH_SHORT).show();
+ return;
+ }
+
+ String[] requiredPermissions = {
+ Manifest.permission.FOREGROUND_SERVICE_MEDIA_PROJECTION,
+ "android.permission.CAPTURE_VIDEO_OUTPUT"
+ };
+
+ for (String permission : requiredPermissions) {
+ if (ContextCompat.checkSelfPermission(this, permission) != PackageManager.PERMISSION_GRANTED) {
+ return;
+ }
+ }
+
+ // 设置前台服务类型(仅在 API 29+)
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
+ startForeground(1, notification, ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PROJECTION);
+ } else {
+ startForeground(1, notification);
+ }
}
}
diff --git a/app/src/main/java/com/example/studyapp/task/AfInfo.java b/app/src/main/java/com/example/studyapp/task/AfInfo.java
new file mode 100644
index 0000000..793da1b
--- /dev/null
+++ b/app/src/main/java/com/example/studyapp/task/AfInfo.java
@@ -0,0 +1,19 @@
+package com.example.studyapp.task;
+
+public class AfInfo {
+ public String advertiserId;
+ public String model;
+ public String brand;
+ public String androidId;
+ public int xPixels;
+ public int yPixels;
+ public int densityDpi;
+ public String country;
+ public String batteryLevel;
+ public String stackInfo;
+ public String product;
+ public String network;
+ public String langCode;
+ public String cpuAbi;
+ public long yDp;
+}
diff --git a/app/src/main/java/com/example/studyapp/task/BigoInfo.java b/app/src/main/java/com/example/studyapp/task/BigoInfo.java
new file mode 100644
index 0000000..d67d5c6
--- /dev/null
+++ b/app/src/main/java/com/example/studyapp/task/BigoInfo.java
@@ -0,0 +1,22 @@
+package com.example.studyapp.task;
+
+// 使用 JSON 库动态生成 JSON 请求体 (使用 Gson 示例)
+public class BigoInfo {
+ public String cpuClockSpeed;
+ public String gaid;
+ public String userAgent;
+ public String osLang;
+ public String osVer;
+ public String tz;
+ public String systemCountry;
+ public String simCountry;
+ public long romFreeIn;
+ public String resolution;
+ public String vendor;
+ public int batteryScale;
+ public String net;
+ public long dpi;
+ public long romFreeExt;
+ public String dpiF;
+ public long cpuCoreNum;
+}
diff --git a/app/src/main/java/com/example/studyapp/task/DeviceInfo.java b/app/src/main/java/com/example/studyapp/task/DeviceInfo.java
new file mode 100644
index 0000000..d69a9bc
--- /dev/null
+++ b/app/src/main/java/com/example/studyapp/task/DeviceInfo.java
@@ -0,0 +1,26 @@
+package com.example.studyapp.task;
+
+public class DeviceInfo {
+
+ public String lang;
+ public String roProductBrand;
+ public String roProductModel;
+ public String roProductManufacturer;
+ public String roProductDevice;
+ public String roProductName;
+ public String roBuildVersionIncremental;
+ public String roBuildFingerprint;
+ public String roOdmBuildFingerprint;
+ public String roProductBuildFingerprint;
+ public String roSystemBuildFingerprint;
+ public String roSystemExtBuildFingerprint;
+ public String roVendorBuildFingerprint;
+ public String roBuildPlatform;
+ public String persistSysCloudDrmId;
+ public int persistSysCloudBatteryCapacity;
+ public String persistSysCloudGpuGlVendor;
+ public String persistSysCloudGpuGlRenderer;
+ public String persistSysCloudGpuGlVersion;
+ public String persistSysCloudGpuEglVendor;
+ public String persistSysCloudGpuEglVersion;
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/studyapp/task/TaskUtil.java b/app/src/main/java/com/example/studyapp/task/TaskUtil.java
new file mode 100644
index 0000000..0a1e1ee
--- /dev/null
+++ b/app/src/main/java/com/example/studyapp/task/TaskUtil.java
@@ -0,0 +1,336 @@
+package com.example.studyapp.task;
+
+import android.content.Context;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.os.Build.VERSION;
+import android.os.Build.VERSION_CODES;
+import android.provider.Settings;
+import com.example.studyapp.MainActivity;
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+import java.io.FileInputStream;
+import java.nio.file.Files;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipOutputStream;
+import okhttp3.Call;
+import okhttp3.Callback;
+import okhttp3.HttpUrl;
+import okhttp3.MediaType;
+import okhttp3.MultipartBody;
+import okhttp3.OkHttpClient;
+import okhttp3.Request;
+import okhttp3.RequestBody;
+import okhttp3.Response;
+import okhttp3.ResponseBody;
+import org.jetbrains.annotations.NotNull;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+
+/**
+ * @Time: 2025/6/16 11:11
+ * @Creator: 初屿贤
+ * @File: TaskUtil
+ * @Project: study.App
+ * @Description:
+ */
+public class TaskUtil {
+
+ private static volatile DeviceInfo deviceInfo;
+ private static volatile BigoInfo bigoDevice;
+ private static volatile AfInfo afDevice;
+
+ private static final String BASE_URL = "http://47.238.96.231:8112";
+ private static OkHttpClient okHttpClient = new OkHttpClient();
+
+ private static void postDeviceInfo(String androidId) {
+ if (okHttpClient == null) {
+ throw new IllegalStateException("HttpClient is not initialized");
+ }
+ if (BASE_URL == null || BASE_URL.isEmpty()) {
+ throw new IllegalStateException("BASE_URL is not initialized");
+ }
+ if (bigoDevice == null || afDevice == null || deviceInfo == null) {
+ throw new IllegalStateException("Device information is missing");
+ }
+
+ Payload payload = new Payload();
+ payload.bigoDeviceObject = bigoDevice;
+ payload.afDeviceObject = afDevice;
+ payload.other = deviceInfo;
+
+ Gson gson = new GsonBuilder().serializeNulls().create();
+ String jsonRequestBody = gson.toJson(payload);
+
+ HttpUrl url = HttpUrl.parse(BASE_URL)
+ .newBuilder()
+ .addPathSegment("device_info_upload")
+ .addQueryParameter("id", androidId)
+ .build();
+
+ RequestBody body = RequestBody.create(MediaType.get("application/json; charset=utf-8"), jsonRequestBody);
+
+ Request request = new Request.Builder()
+ .url(url)
+ .post(body)
+ .build();
+
+ okHttpClient.newCall(request).enqueue(new Callback() {
+ @Override
+ public void onFailure(@NotNull Call call, @NotNull IOException e) {
+ System.err.println("Request failed: " + e.getMessage());
+ // Optional: Add retry logic
+ }
+
+ @Override
+ public void onResponse(@NotNull Call call, @NotNull Response response) {
+ try (ResponseBody responseBody = response.body()) {
+ if (!response.isSuccessful()) {
+ System.err.println("Request failed with status: " + response.code() + ", message: " + response.message());
+ return;
+ }
+ if (responseBody != null) {
+ System.out.println(responseBody.string());
+ } else {
+ System.err.println("Response body is null");
+ }
+ } catch (Exception e) {
+ System.err.println("Error while processing response: " + e.getMessage());
+ }
+ }
+ });
+ }
+
+ public static void infoUpload(Context context, String androidId, String packAge) throws IOException {
+
+ if (context == null) {
+ throw new IllegalArgumentException("Context or Package name cannot be null or empty");
+ }
+
+ if (androidId == null || androidId.isEmpty()) {
+ System.err.println("ANDROID_ID is null or empty");
+ return;
+ }
+ PackageInfo packageInfo;
+ try {
+ // 根据包名获取APK路径
+ packageInfo = context.getPackageManager().getPackageInfo(packAge, 0);
+ if (packageInfo == null) {
+ throw new IllegalStateException("未找到包名对应的信息:" + packAge);
+ }
+ } catch (PackageManager.NameNotFoundException e) {
+ throw new RuntimeException("未找到包名对应的应用:" + packAge, e);
+ }
+
+ String apkSourceDir = packageInfo.applicationInfo.sourceDir; // APK路径
+ String outputZipPath = new File(
+ context.getExternalFilesDir(null),
+ androidId + "_" + packAge + ".zip"
+ ).getAbsolutePath(); // 压缩文件输出路径
+
+ File zipFile = new File(outputZipPath);
+ if (zipFile.exists() && !zipFile.delete()) {
+ System.err.println("旧的压缩文件无法删除:" + outputZipPath);
+ return;
+ }
+
+ File sourceApk = new File(apkSourceDir);
+ File copiedApk = new File(context.getCacheDir(), packAge + "_temp.apk");
+ if (copiedApk.exists() && !copiedApk.delete()) {
+ System.err.println("旧的临时apk文件无法删除:" + copiedApk.getAbsolutePath());
+ return;
+ }
+ Files.copy(sourceApk.toPath(), copiedApk.toPath());
+
+ // 压缩APK文件
+ try (
+ FileInputStream fis = new FileInputStream(copiedApk);
+ FileOutputStream fos = new FileOutputStream(outputZipPath);
+ ZipOutputStream zipOut = new ZipOutputStream(fos)) {
+
+ ZipEntry zipEntry = new ZipEntry(new File(apkSourceDir).getName());
+ zipOut.putNextEntry(zipEntry);
+ byte[] buffer = new byte[1024];
+ int bytesRead;
+ while ((bytesRead = fis.read(buffer)) >= 0) {
+ zipOut.write(buffer, 0, bytesRead);
+ }
+ System.out.println("APK文件成功压缩至:" + outputZipPath);
+ } catch (IOException e) {
+ e.printStackTrace();
+ return;
+ }
+
+ // 上传压缩文件
+ File fileToUpload = new File(outputZipPath);
+ if (!fileToUpload.exists()) {
+ System.out.println("上传文件不存在:" + outputZipPath);
+ return;
+ }
+
+ RequestBody fileBody = RequestBody.create(
+ MediaType.get("application/zip"), fileToUpload
+ );
+ MultipartBody requestBody = new MultipartBody.Builder()
+ .setType(MultipartBody.FORM)
+ .addFormDataPart("file", fileToUpload.getName(), fileBody)
+ .build();
+
+ Request request = new Request.Builder()
+ .url(BASE_URL + "/tar_info_upload")
+ .post(requestBody)
+ .build();
+
+ okHttpClient.newCall(request).enqueue(new Callback() {
+ @Override
+ public void onFailure(@NotNull Call call, @NotNull IOException e) {
+ e.printStackTrace();
+ System.out.println("上传失败: " + e.getMessage());
+ }
+
+ @Override
+ public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException {
+ try {
+ if (response.isSuccessful()) {
+ System.out.println("文件上传成功: " + response.body().string());
+ } else {
+ System.out.println("上传失败: " + response.message());
+ }
+ } finally {
+ response.close(); // 确保关闭 response 以避免资源泄漏
+ }
+ }
+ });
+ }
+
+ private static void validate() {
+ if (okHttpClient == null) {
+ throw new IllegalStateException("HttpClient is not initialized");
+ }
+ if (BASE_URL == null || BASE_URL.isEmpty()) {
+ throw new IllegalStateException("BASE_URL is not initialized");
+ }
+ }
+
+ private static String getDeviceInfoSync(String androidId) {
+ validate(); // 检查 BASE_URL 和 okHttpClient 的合法性
+
+ HttpUrl url = HttpUrl.parse(BASE_URL + "/device_info_download")
+ .newBuilder()
+ .addQueryParameter("androidId", androidId)
+ .build();
+
+ Request request = new Request.Builder()
+ .url(url)
+ .get()
+ .build();
+
+ try (Response response = okHttpClient.newCall(request).execute()) {
+ if (!response.isSuccessful()) { // 检查响应状态
+ throw new IOException("Unexpected response: " + response);
+ }
+ ResponseBody body = response.body();
+ if (body != null) {
+ return body.string();
+ } else {
+ throw new IOException("Response body is null");
+ }
+ } catch (IOException e) {
+ e.printStackTrace();
+ return null; // 或者抛出上层处理
+ }
+ }
+
+ private static void infoDownload(String androidId) {
+ // 下载压缩包
+ HttpUrl url = HttpUrl.parse(BASE_URL + "/tar_info_download")
+ .newBuilder()
+ .addQueryParameter("file_name", "test")
+ .build();
+
+ Request request = new Request.Builder()
+ .url(url)
+ .get()
+ .build();
+
+ okHttpClient.newCall(request).enqueue(new Callback() {
+ @Override
+ public void onFailure(@NotNull Call call, @NotNull IOException e) {
+ e.printStackTrace();
+ }
+
+ @Override
+ public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException {
+ if (response.isSuccessful()) {
+ byte[] fileBytes = response.body().bytes();
+ String savePath = "/storage/emulated/0/Download/test.zip";
+
+ File file = new File(savePath);
+ file.getParentFile().mkdirs();
+
+ try (FileOutputStream fos = new FileOutputStream(file)) {
+ fos.write(fileBytes);
+ System.out.println("File saved to " + savePath);
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ } else {
+ System.out.println("Download failed: " + response.message());
+ }
+ }
+ });
+ }
+
+ public static String execQueryTask(Context context) {
+ String androidId = Settings.Secure.getString(
+ context.getContentResolver(),
+ Settings.Secure.ANDROID_ID
+ );
+ return getDeviceInfoSync(androidId);
+ }
+
+ public static void execSaveTask(Context context) {
+ if (context == null) {
+ throw new IllegalArgumentException("Context or Package name cannot be null or empty");
+ }
+
+ if (MainActivity.androidId == null || MainActivity.androidId.isEmpty()) {
+ System.err.println("ANDROID_ID is null or empty");
+ return;
+ }
+
+ try {
+ postDeviceInfo(MainActivity.androidId);
+ } catch (Exception e) {
+ System.err.println("Error in execReloginTask: " + e.getMessage());
+ e.printStackTrace();
+ }
+ }
+
+ public static void setHttpClient(OkHttpClient client) {
+ okHttpClient = client;
+ }
+
+ public static void setDeviceInfo(DeviceInfo info) {
+ deviceInfo = info;
+ }
+
+ public static void setBigoDevice(BigoInfo info) {
+ bigoDevice = info;
+ }
+
+ public static void setAfDevice(AfInfo info) {
+ afDevice = info;
+ }
+}
+
+class Payload {
+
+ BigoInfo bigoDeviceObject;
+ AfInfo afDeviceObject;
+ DeviceInfo other;
+}
+
diff --git a/app/src/main/jniLibs/arm64-v8a/libnative.so b/app/src/main/jniLibs/arm64-v8a/libnative.so
index 1935dd8..2366804 100644
Binary files a/app/src/main/jniLibs/arm64-v8a/libnative.so and b/app/src/main/jniLibs/arm64-v8a/libnative.so differ
diff --git a/app/src/main/res/xml/network_security_config.xml b/app/src/main/res/xml/network_security_config.xml
index 718a98a..ce01498 100644
--- a/app/src/main/res/xml/network_security_config.xml
+++ b/app/src/main/res/xml/network_security_config.xml
@@ -11,5 +11,6 @@
8.211.204.20
127.0.0.1
8.217.137.25
+ 47.238.96.231
diff --git a/app/src/test/java/com/example/studyapp/task/TaskUtilTest.java b/app/src/test/java/com/example/studyapp/task/TaskUtilTest.java
new file mode 100644
index 0000000..aaaed11
--- /dev/null
+++ b/app/src/test/java/com/example/studyapp/task/TaskUtilTest.java
@@ -0,0 +1,99 @@
+package com.example.studyapp.task;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.*;
+
+import java.io.IOException;
+import okhttp3.Call;
+import okhttp3.Callback;
+import okhttp3.MediaType;
+import okhttp3.OkHttpClient;
+import okhttp3.Protocol;
+import okhttp3.Request;
+import okhttp3.Response;
+import okhttp3.ResponseBody;
+import okio.Buffer;
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+
+public class TaskUtilTest {
+
+ @Test
+ public void testPostDeviceInfo() throws Exception {
+ OkHttpClient mockClient = mock(OkHttpClient.class);
+ TaskUtil.setHttpClient(mockClient); // 确保 mockClient 被 TaskUtil 使用
+
+ // Mock Call 和 Response
+ Call mockCall = mock(Call.class);
+ Response mockResponse = new Response.Builder()
+ .request(new Request.Builder().url("http://192.168.1.121:5000/device_info_upload").build())
+ .protocol(Protocol.HTTP_1_1)
+ .code(200)
+ .message("OK")
+ .body(ResponseBody.create(MediaType.get("application/json; charset=utf-8"), "Success"))
+ .build();
+
+ // 配置 Mock 行为
+ when(mockClient.newCall(any(Request.class))).thenReturn(mockCall);
+ doAnswer(invocation -> {
+ Callback callback = invocation.getArgument(0);
+ callback.onResponse(mockCall, mockResponse); // 模拟请求成功的回调
+ return null;
+ }).when(mockCall).enqueue(any(Callback.class));
+
+ // 调用测试方法
+ //TaskUtil.postDeviceInfo();
+
+ // 验证 newCall 是否被调用
+ ArgumentCaptor requestCaptor = ArgumentCaptor.forClass(Request.class);
+ verify(mockClient).newCall(requestCaptor.capture()); // 确认调用
+ Request capturedRequest = requestCaptor.getValue();
+
+ // 验证请求内容
+ assertNotNull(capturedRequest);
+ assertEquals("POST", capturedRequest.method());
+ assertEquals("http://192.168.1.121:5000/device_info_upload", capturedRequest.url().toString());
+ assertNotNull(capturedRequest.body());
+
+ // 验证提交数据 JSON
+ Buffer buffer = new Buffer();
+ capturedRequest.body().writeTo(buffer);
+ String body = buffer.readUtf8();
+ assertTrue(body.contains("\"bigoDeviceObject\""));
+ assertTrue(body.contains("\"afDeviceObject\""));
+ }
+
+ @Test
+ public void testPostDeviceInfoDownload_FailedRequest() throws Exception {
+ OkHttpClient mockClient = mock(OkHttpClient.class);
+ Call mockCall = mock(Call.class);
+
+ when(mockClient.newCall(any(Request.class))).thenReturn(mockCall);
+
+ doAnswer(invocation -> {
+ Callback callback = invocation.getArgument(0);
+ callback.onFailure(mockCall, new IOException("Request failed"));
+ return null;
+ }).when(mockCall).enqueue(any(Callback.class));
+
+ //TaskUtil.postDeviceInfo();
+
+ ArgumentCaptor requestCaptor = ArgumentCaptor.forClass(Request.class);
+ verify(mockClient).newCall(requestCaptor.capture());
+ Request capturedRequest = requestCaptor.getValue();
+
+ assertNotNull(capturedRequest);
+ assertEquals("POST", capturedRequest.method());
+ assertEquals("http://192.168.1.121:5000/device_info_upload", capturedRequest.url().toString());
+ assertNotNull(capturedRequest.body());
+
+ // Validate JSON body
+ Buffer buffer = new Buffer();
+ capturedRequest.body().writeTo(buffer);
+ String body = buffer.readUtf8();
+ assertTrue(body.contains("\"bigoDeviceObject\""));
+ assertTrue(body.contains("\"afDeviceObject\""));
+ }
+}
\ No newline at end of file