Add `TaskUtil` for device and file operations; update `MainActivity` for Android ID handling and permissions
Introduced new `TaskUtil` utility class for device info upload, file compression, and remote operations. Updated `MainActivity` to dynamically fetch and utilize Android ID, added Android 13+ permission handling for `FOREGROUND_SERVICE`. Included Mockito dependencies for unit testing, implemented `TaskUtilTest` for API interaction validation. Adjusted `ChangeDeviceInfoUtil` initialization and fetched properties dynamically. Updated `minSdk` and network security configuration.
This commit is contained in:
parent
984328b7eb
commit
222a2002f9
|
@ -8,7 +8,7 @@ android {
|
||||||
|
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
applicationId "com.example.studyapp"
|
applicationId "com.example.studyapp"
|
||||||
minSdk 24
|
minSdk 23
|
||||||
targetSdk 35
|
targetSdk 35
|
||||||
versionCode 1
|
versionCode 1
|
||||||
versionName "1.0"
|
versionName "1.0"
|
||||||
|
@ -73,4 +73,11 @@ dependencies {
|
||||||
|
|
||||||
// 如果需要 RxJava 支持(可选)
|
// 如果需要 RxJava 支持(可选)
|
||||||
implementation 'com.squareup.retrofit2:adapter-rxjava3:2.9.0'
|
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'
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,6 +20,11 @@
|
||||||
<uses-permission android:name="android.permission.CREATE_USERS" />
|
<uses-permission android:name="android.permission.CREATE_USERS" />
|
||||||
<uses-permission android:name="android.permission.QUERY_USERS" />
|
<uses-permission android:name="android.permission.QUERY_USERS" />
|
||||||
<uses-permission android:name="android.permission.READ_CLIPBOARD_IN_BACKGROUND" />
|
<uses-permission android:name="android.permission.READ_CLIPBOARD_IN_BACKGROUND" />
|
||||||
|
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
|
||||||
|
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
|
||||||
|
<uses-permission android:name="android.permission.CAPTURE_VIDEO_OUTPUT" />
|
||||||
|
<uses-permission android:name="android.permission.MEDIA_PROJECTION" />
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<application
|
<application
|
||||||
|
@ -44,19 +49,12 @@
|
||||||
<category android:name="android.intent.category.LAUNCHER" />
|
<category android:name="android.intent.category.LAUNCHER" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
<service
|
|
||||||
android:name=".proxy.CustomVpnService"
|
|
||||||
android:permission="android.permission.BIND_VPN_SERVICE"
|
|
||||||
android:exported="true">
|
|
||||||
<intent-filter>
|
|
||||||
<action android:name="android.net.VpnService" />
|
|
||||||
</intent-filter>
|
|
||||||
</service>
|
|
||||||
<service
|
<service
|
||||||
android:name=".service.MyAccessibilityService"
|
android:name=".service.MyAccessibilityService"
|
||||||
android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE"
|
android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE"
|
||||||
android:enabled="true"
|
android:enabled="true"
|
||||||
android:exported="false">
|
android:foregroundServiceType="mediaProjection"
|
||||||
|
android:exported="true">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.accessibilityservice.AccessibilityService" />
|
<action android:name="android.accessibilityservice.AccessibilityService" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
|
|
|
@ -2,7 +2,6 @@ package com.example.studyapp;
|
||||||
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.app.AlertDialog;
|
import android.app.AlertDialog;
|
||||||
import android.content.BroadcastReceiver;
|
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
|
@ -31,16 +30,15 @@ import androidx.work.WorkManager;
|
||||||
import com.example.studyapp.autoJS.AutoJsUtil;
|
import com.example.studyapp.autoJS.AutoJsUtil;
|
||||||
import com.example.studyapp.device.ChangeDeviceInfoUtil;
|
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 com.example.studyapp.worker.CheckAccessibilityWorker;
|
||||||
import java.lang.ref.WeakReference;
|
import java.lang.ref.WeakReference;
|
||||||
import java.util.concurrent.ExecutorService;
|
import java.util.concurrent.ExecutorService;
|
||||||
import java.util.concurrent.Executors;
|
|
||||||
import java.util.concurrent.Future;
|
|
||||||
import java.util.concurrent.LinkedBlockingQueue;
|
import java.util.concurrent.LinkedBlockingQueue;
|
||||||
import java.util.concurrent.ThreadPoolExecutor;
|
import java.util.concurrent.ThreadPoolExecutor;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.concurrent.TimeoutException;
|
|
||||||
|
|
||||||
public class MainActivity extends AppCompatActivity {
|
public class MainActivity extends AppCompatActivity {
|
||||||
|
|
||||||
|
@ -69,6 +67,8 @@ public class MainActivity extends AppCompatActivity {
|
||||||
"ge", "ps"
|
"ge", "ps"
|
||||||
};
|
};
|
||||||
|
|
||||||
|
public static String androidId;
|
||||||
|
|
||||||
// 初始化 ExecutorService
|
// 初始化 ExecutorService
|
||||||
private void initializeExecutorService() {
|
private void initializeExecutorService() {
|
||||||
if (executorService == null || executorService.isShutdown()) {
|
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
|
@Override
|
||||||
protected void onCreate(@Nullable Bundle savedInstanceState) {
|
protected void onCreate(@Nullable Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
|
@ -89,6 +113,7 @@ public class MainActivity extends AppCompatActivity {
|
||||||
instance = new WeakReference<>(this);
|
instance = new WeakReference<>(this);
|
||||||
|
|
||||||
initializeExecutorService();
|
initializeExecutorService();
|
||||||
|
getAndroidId(this);
|
||||||
System.setProperty("java.library.path", this.getApplicationInfo().nativeLibraryDir);
|
System.setProperty("java.library.path", this.getApplicationInfo().nativeLibraryDir);
|
||||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) {
|
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) {
|
||||||
// 针对 Android 10 或更低版本检查普通存储权限
|
// 针对 Android 10 或更低版本检查普通存储权限
|
||||||
|
@ -110,6 +135,16 @@ public class MainActivity extends AppCompatActivity {
|
||||||
startActivityForResult(intent, ALLOW_ALL_FILES_ACCESS_PERMISSION_CODE);
|
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)) {
|
if (!isNetworkAvailable(this)) {
|
||||||
Toast.makeText(this, "Network is not available", Toast.LENGTH_SHORT).show();
|
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);
|
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));
|
||||||
} else {
|
} else {
|
||||||
Toast.makeText(this, "Button not found", Toast.LENGTH_SHORT).show();
|
Toast.makeText(this, "Button not found", Toast.LENGTH_SHORT).show();
|
||||||
}
|
}
|
||||||
|
@ -164,7 +199,7 @@ public class MainActivity extends AppCompatActivity {
|
||||||
}
|
}
|
||||||
|
|
||||||
// 初始化 ChangeDeviceInfoUtil
|
// 初始化 ChangeDeviceInfoUtil
|
||||||
ChangeDeviceInfoUtil.initialize("US", 2);
|
ChangeDeviceInfoUtil.initialize("US", 2, this);
|
||||||
// 获取输入框和按钮
|
// 获取输入框和按钮
|
||||||
EditText inputNumber = findViewById(R.id.input_number);
|
EditText inputNumber = findViewById(R.id.input_number);
|
||||||
Button executeButton = findViewById(R.id.execute_button);
|
Button executeButton = findViewById(R.id.execute_button);
|
||||||
|
@ -237,13 +272,13 @@ public class MainActivity extends AppCompatActivity {
|
||||||
AutoJsUtil.flag = true; // 广播状态更新
|
AutoJsUtil.flag = true; // 广播状态更新
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < number; i++) {
|
while (true) {
|
||||||
synchronized (taskLock) {
|
synchronized (taskLock) {
|
||||||
while (!AutoJsUtil.flag) {
|
while (!AutoJsUtil.flag) {
|
||||||
taskLock.wait(30000);
|
taskLock.wait(30000);
|
||||||
}
|
}
|
||||||
Log.d("MainActivity", "任务执行第:" + i);
|
executeSingleLogic();
|
||||||
executeSingleLogic(i);
|
TaskUtil.execSaveTask(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
|
@ -257,14 +292,11 @@ public class MainActivity extends AppCompatActivity {
|
||||||
public static final Object broadcastLock = new Object(); // 广播锁
|
public static final Object broadcastLock = new Object(); // 广播锁
|
||||||
public static final Object taskLock = new Object(); // 任务逻辑锁
|
public static final Object taskLock = new Object(); // 任务逻辑锁
|
||||||
|
|
||||||
public void executeSingleLogic(int i) {
|
public void executeSingleLogic() {
|
||||||
Log.i("MainActivity", "executeSingleLogic: Start execution for index " + i);
|
|
||||||
long startTime = System.currentTimeMillis(); // 开始计时
|
|
||||||
|
|
||||||
Log.i("MainActivity", "executeSingleLogic: Proxy not active, starting VPN");
|
Log.i("MainActivity", "executeSingleLogic: Proxy not active, starting VPN");
|
||||||
startProxyVpn(this);
|
startProxyVpn(this);
|
||||||
|
|
||||||
Log.i("MainActivity", "executeSingleLogic: Switching proxy group to " + proxyNames[i]);
|
|
||||||
try {
|
try {
|
||||||
ClashUtil.switchProxyGroup("GLOBAL", "us", "http://127.0.0.1:6170");
|
ClashUtil.switchProxyGroup("GLOBAL", "us", "http://127.0.0.1:6170");
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
|
@ -273,15 +305,10 @@ public class MainActivity extends AppCompatActivity {
|
||||||
}
|
}
|
||||||
|
|
||||||
Log.i("MainActivity", "executeSingleLogic: Changing device info");
|
Log.i("MainActivity", "executeSingleLogic: Changing device info");
|
||||||
String url = ChangeDeviceInfoUtil.changeDeviceInfo(getPackageName(), this);
|
ChangeDeviceInfoUtil.changeDeviceInfo(getPackageName(), this);
|
||||||
|
|
||||||
Log.i("MainActivity", "executeSingleLogic: Running AutoJs script");
|
Log.i("MainActivity", "executeSingleLogic: Running AutoJs script");
|
||||||
AutoJsUtil.runAutojsScript(this, url);
|
AutoJsUtil.runAutojsScript(this);
|
||||||
|
|
||||||
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");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void startProxyVpn(Context context) {
|
private void startProxyVpn(Context context) {
|
||||||
|
@ -315,8 +342,30 @@ public class MainActivity extends AppCompatActivity {
|
||||||
showPermissionExplanationDialog();
|
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
|
@Override
|
||||||
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
|
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
|
||||||
super.onActivityResult(requestCode, resultCode, data);
|
super.onActivityResult(requestCode, resultCode, data);
|
||||||
|
|
|
@ -3,6 +3,7 @@ package com.example.studyapp.autoJS;
|
||||||
import static androidx.core.content.ContextCompat.startActivity;
|
import static androidx.core.content.ContextCompat.startActivity;
|
||||||
import static com.example.studyapp.MainActivity.broadcastLock;
|
import static com.example.studyapp.MainActivity.broadcastLock;
|
||||||
import static com.example.studyapp.MainActivity.taskLock;
|
import static com.example.studyapp.MainActivity.taskLock;
|
||||||
|
import static com.example.studyapp.task.TaskUtil.infoUpload;
|
||||||
|
|
||||||
import android.Manifest;
|
import android.Manifest;
|
||||||
import android.content.ActivityNotFoundException;
|
import android.content.ActivityNotFoundException;
|
||||||
|
@ -26,6 +27,7 @@ import com.example.studyapp.service.CloudPhoneManageService;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
import retrofit2.Call;
|
import retrofit2.Call;
|
||||||
import retrofit2.Callback;
|
import retrofit2.Callback;
|
||||||
import retrofit2.Response;
|
import retrofit2.Response;
|
||||||
|
@ -38,7 +40,7 @@ public class AutoJsUtil {
|
||||||
public static volatile boolean flag;
|
public static volatile boolean flag;
|
||||||
|
|
||||||
private static int count;
|
private static int count;
|
||||||
public static void runAutojsScript(Context context,String url) {
|
public static void runAutojsScript(Context context) {
|
||||||
// 检查脚本文件
|
// 检查脚本文件
|
||||||
Log.i("AutoJsUtil", "-------脚本运行开始:--------"+ count++ );
|
Log.i("AutoJsUtil", "-------脚本运行开始:--------"+ count++ );
|
||||||
File scriptFile = new File(Environment.getExternalStorageDirectory(), "script/main.js");
|
File scriptFile = new File(Environment.getExternalStorageDirectory(), "script/main.js");
|
||||||
|
@ -58,7 +60,6 @@ public class AutoJsUtil {
|
||||||
Intent intent = new Intent();
|
Intent intent = new Intent();
|
||||||
intent.setClassName("org.autojs.autojs6", "org.autojs.autojs.external.open.RunIntentActivity");
|
intent.setClassName("org.autojs.autojs6", "org.autojs.autojs.external.open.RunIntentActivity");
|
||||||
intent.putExtra("path", scriptFile.getAbsolutePath());
|
intent.putExtra("path", scriptFile.getAbsolutePath());
|
||||||
intent.putExtra("url", url);
|
|
||||||
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||||
try {
|
try {
|
||||||
context.startActivity(intent);
|
context.startActivity(intent);
|
||||||
|
@ -85,6 +86,13 @@ public class AutoJsUtil {
|
||||||
AutoJsUtil.flag = true;
|
AutoJsUtil.flag = true;
|
||||||
}
|
}
|
||||||
synchronized (taskLock) {
|
synchronized (taskLock) {
|
||||||
|
try {
|
||||||
|
infoUpload(context, MainActivity.androidId, scriptResult);
|
||||||
|
} catch (IOException e) {
|
||||||
|
// 例如:可以显示给用户一条错误消息
|
||||||
|
Log.e("AutoJsUtil", "File upload failed: " + e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
taskLock.notifyAll(); // 唤醒任务线程
|
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 AUTOJS_SCRIPT_FINISHED_ACTION = "org.autojs.SCRIPT_FINISHED";
|
||||||
private static final String SCRIPT_RESULT_KEY = "result";
|
private static final String SCRIPT_RESULT_KEY = "package";
|
||||||
private static final Object lock = new Object();
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public static void stopAutojsScript(Context context) {
|
public static void stopAutojsScript(Context context) {
|
||||||
// 停止运行脚本的 Intent
|
// 停止运行脚本的 Intent
|
||||||
|
@ -157,5 +162,4 @@ public class AutoJsUtil {
|
||||||
Log.e("AutoJsUtil", "目标活动未找到: org.autojs.autojs.external.open.StopServiceActivity");
|
Log.e("AutoJsUtil", "目标活动未找到: org.autojs.autojs.external.open.StopServiceActivity");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,24 +2,21 @@ package com.example.studyapp.device;
|
||||||
|
|
||||||
import android.content.ContentResolver;
|
import android.content.ContentResolver;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.net.ConnectivityManager;
|
|
||||||
import android.net.Network;
|
|
||||||
import android.net.NetworkCapabilities;
|
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.text.TextUtils;
|
|
||||||
import android.util.Log;
|
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.HttpUtil;
|
||||||
import com.example.studyapp.utils.ShellUtils;
|
import com.example.studyapp.utils.ShellUtils;
|
||||||
|
|
||||||
import com.google.android.gms.ads.identifier.AdvertisingIdClient;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.lang.reflect.InvocationTargetException;
|
import java.lang.reflect.InvocationTargetException;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.concurrent.ExecutorService;
|
import java.util.concurrent.ExecutorService;
|
||||||
import java.util.concurrent.Executors;
|
import java.util.concurrent.Executors;
|
||||||
import org.json.JSONArray;
|
|
||||||
import org.json.JSONException;
|
import org.json.JSONException;
|
||||||
import org.json.JSONObject;
|
import org.json.JSONObject;
|
||||||
|
|
||||||
|
@ -28,9 +25,9 @@ import java.lang.reflect.Method;
|
||||||
public class ChangeDeviceInfoUtil {
|
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) {
|
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")
|
||||||
|
@ -51,30 +48,65 @@ public class ChangeDeviceInfoUtil {
|
||||||
// 创建一个线程池用于执行网络任务
|
// 创建一个线程池用于执行网络任务
|
||||||
private static final ExecutorService executorService = Executors.newSingleThreadExecutor();
|
private static final ExecutorService executorService = Executors.newSingleThreadExecutor();
|
||||||
|
|
||||||
public static void initialize(String country, int tag) {
|
public static void initialize(String country, int tag, MainActivity mainActivity) {
|
||||||
executorService.submit(() -> {
|
executorService.submit(() -> {
|
||||||
try {
|
try {
|
||||||
String bigoJson = HttpUtil.requestGet(buildBigoUrl(country, tag));
|
// 发起网络请求并捕获可能的异常
|
||||||
String afJson = HttpUtil.requestGet(buildAfUrl(country, tag ));
|
String bigoJson;
|
||||||
|
String afJson;
|
||||||
bigoDeviceObject = new JSONObject(bigoJson).optJSONObject("device");
|
try {
|
||||||
afDeviceObject = new JSONObject(afJson).optJSONObject("device");
|
bigoJson = HttpUtil.requestGet(buildBigoUrl(country, tag));
|
||||||
|
afJson = HttpUtil.requestGet(buildAfUrl(country, tag));
|
||||||
if (bigoDeviceObject == null || afDeviceObject == null) {
|
} catch (IOException ioException) {
|
||||||
throw new JSONException("Device object is missing in the response JSON");
|
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) {
|
} 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) {
|
if (bigoDeviceObject == null || afDeviceObject == null) {
|
||||||
Log.e("ChangeDeviceInfoUtil", "Required device JSON objects are not initialized");
|
Log.e("ChangeDeviceInfoUtil", "Required device JSON objects are not initialized");
|
||||||
|
@ -95,14 +127,31 @@ public class ChangeDeviceInfoUtil {
|
||||||
String resolution = bigoDeviceObject.optString("resolution");
|
String resolution = bigoDeviceObject.optString("resolution");
|
||||||
String vendor = bigoDeviceObject.optString("vendor");
|
String vendor = bigoDeviceObject.optString("vendor");
|
||||||
int batteryScale = bigoDeviceObject.optInt("bat_scale");
|
int batteryScale = bigoDeviceObject.optInt("bat_scale");
|
||||||
//String model = deviceObject.optString("model");
|
// String model = deviceObject.optString("model");
|
||||||
String net = bigoDeviceObject.optString("net");
|
String net = bigoDeviceObject.optString("net");
|
||||||
int dpi = bigoDeviceObject.optInt("dpi");
|
int dpi = bigoDeviceObject.optInt("dpi");
|
||||||
long romFreeExt = bigoDeviceObject.optLong("rom_free_ext");
|
long romFreeExt = bigoDeviceObject.optLong("rom_free_ext");
|
||||||
String dpiF = bigoDeviceObject.optString("dpi_f");
|
String dpiF = bigoDeviceObject.optString("dpi_f");
|
||||||
int cpuCoreNum = bigoDeviceObject.optInt("cpu_core_num");
|
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 advertiserId = afDeviceObject.optString(".advertiserId");
|
||||||
String model = afDeviceObject.optString(".model");
|
String model = afDeviceObject.optString(".model");
|
||||||
String brand = afDeviceObject.optString(".brand");
|
String brand = afDeviceObject.optString(".brand");
|
||||||
|
@ -118,33 +167,93 @@ public class ChangeDeviceInfoUtil {
|
||||||
String langCode = afDeviceObject.optString(".lang_code");
|
String langCode = afDeviceObject.optString(".lang_code");
|
||||||
String cpuAbi = afDeviceObject.optString(".deviceData.cpu_abi");
|
String cpuAbi = afDeviceObject.optString(".deviceData.cpu_abi");
|
||||||
int yDp = afDeviceObject.optInt(".deviceData.dim.ydp");
|
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 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 global_android_id = afDeviceObject.optString(".android_id", "");
|
||||||
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";
|
String anticheck_pkgs = afDeviceObject.optString(".anticheck_pkgs", "");
|
||||||
Map<String, String> params = new HashMap<>();
|
String pm_list_features = afDeviceObject.optString(".pm_list_features", "");
|
||||||
params.put("aff", "12345");
|
String pm_list_libraries = afDeviceObject.optString(".pm_list_libraries", "");
|
||||||
params.put("aff_sub6", "sub6Value");
|
String system_http_agent = afDeviceObject.optString("system.http.agent", "");
|
||||||
params.put("offer_id", "offer123");
|
String webkit_http_agent = afDeviceObject.optString("webkit.http.agent", "");
|
||||||
params.put("adx_bundle_id", "adxBundle123");
|
String com_fk_tools_pkgInfo = afDeviceObject.optString(".pkg_info", "");
|
||||||
params.put("affiliate_id", "affiliateID123");
|
String appsflyerKey = afDeviceObject.optString(".appsflyerKey", "");
|
||||||
params.put("currency", "USD");
|
String appUserId = afDeviceObject.optString(".appUserId", "");
|
||||||
params.put("payout", "5.0");
|
String disk = afDeviceObject.optString(".disk", "");
|
||||||
params.put("transaction_id","");
|
String operator = afDeviceObject.optString(".operator", "");
|
||||||
params.put("ip",HttpUtil.getLocalIpAddress());
|
String cell_mcc = afDeviceObject.optString(".cell.mcc", "");
|
||||||
params.put("aff_sub4", "English");
|
String cell_mnc = afDeviceObject.optString(".cell.mnc", "");
|
||||||
params.put("aff_sub3", "AdvertisingID123");
|
String date1 = afDeviceObject.optString(".date1", "");
|
||||||
|
String date2 = afDeviceObject.optString(".date2", "");
|
||||||
params.put("adx_id", advertiserId);
|
String bootId = afDeviceObject.optString("BootId", "");
|
||||||
params.put("ua",userAgent);
|
|
||||||
params.put("model", model);
|
|
||||||
params.put("os_version", osVer);
|
|
||||||
|
|
||||||
// 自动处理分辨率信息
|
// 自动处理分辨率信息
|
||||||
// int widthPixels = Integer.parseInt(resolution.split("x")[0]);
|
// int widthPixels = Integer.parseInt(resolution.split("x")[0]);
|
||||||
// int heightPixels = Integer.parseInt(resolution.split("x")[1]);
|
// int heightPixels = Integer.parseInt(resolution.split("x")[1]);
|
||||||
|
//
|
||||||
// 更新屏幕显示相关参数
|
// 更新屏幕显示相关参数
|
||||||
// JSONObject displayMetrics = new JSONObject();
|
// JSONObject displayMetrics = new JSONObject();
|
||||||
// displayMetrics.put("widthPixels", widthPixels);
|
// displayMetrics.put("widthPixels", widthPixels);
|
||||||
|
@ -152,7 +261,7 @@ public class ChangeDeviceInfoUtil {
|
||||||
// displayMetrics.put("densityDpi", dpi);
|
// displayMetrics.put("densityDpi", dpi);
|
||||||
// callVCloudSettings_put("screen.device.displayMetrics", displayMetrics.toString(), context);
|
// 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 + ".system_country", systemCountry, context);
|
||||||
callVCloudSettings_put(current_pkg_name + ".sim_country", simCountry, context);
|
callVCloudSettings_put(current_pkg_name + ".sim_country", simCountry, context);
|
||||||
callVCloudSettings_put(current_pkg_name + ".rom_free_in", String.valueOf(romFreeIn), 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 + ".vendor", vendor, context);
|
||||||
callVCloudSettings_put(current_pkg_name + ".battery_scale", String.valueOf(batteryScale), 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 + ".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 + ".net", net, context);
|
||||||
callVCloudSettings_put(current_pkg_name + ".dpi", String.valueOf(dpi), context);
|
callVCloudSettings_put(current_pkg_name + ".dpi", String.valueOf(dpi), context);
|
||||||
callVCloudSettings_put(current_pkg_name + ".rom_free_ext", String.valueOf(romFreeExt), context);
|
callVCloudSettings_put(current_pkg_name + ".rom_free_ext", String.valueOf(romFreeExt), context);
|
||||||
|
@ -177,7 +286,7 @@ public class ChangeDeviceInfoUtil {
|
||||||
// **tz** (时区)
|
// **tz** (时区)
|
||||||
callVCloudSettings_put(current_pkg_name + "_tz", tz, context);
|
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 + ".advertiserId", advertiserId, context);
|
||||||
callVCloudSettings_put(current_pkg_name + ".model", model, context);
|
callVCloudSettings_put(current_pkg_name + ".model", model, context);
|
||||||
callVCloudSettings_put(current_pkg_name + ".brand", brand, context);
|
callVCloudSettings_put(current_pkg_name + ".brand", brand, context);
|
||||||
|
@ -203,74 +312,34 @@ public class ChangeDeviceInfoUtil {
|
||||||
|
|
||||||
if (!ShellUtils.hasRootAccess()) {
|
if (!ShellUtils.hasRootAccess()) {
|
||||||
Log.e("ChangeDeviceInfoUtil", "Root access is required to execute system property changes");
|
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.brand " + ro_product_brand);
|
||||||
ShellUtils.execRootCmd("setprop ro.product.model "+ ro_product_model );
|
ShellUtils.execRootCmd("setprop ro.product.model " + ro_product_model);
|
||||||
ShellUtils.execRootCmd("setprop ro.product.manufacturer "+ro_product_manufacturer );
|
ShellUtils.execRootCmd("setprop ro.product.manufacturer " + ro_product_manufacturer);
|
||||||
ShellUtils.execRootCmd("setprop ro.product.device "+ ro_product_device);
|
ShellUtils.execRootCmd("setprop ro.product.device " + ro_product_device);
|
||||||
ShellUtils.execRootCmd("setprop ro.product.name "+ro_product_name );
|
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.version.incremental " + ro_build_version_incremental);
|
||||||
ShellUtils.execRootCmd("setprop ro.build.fingerprint "+ro_build_fingerprint );
|
ShellUtils.execRootCmd("setprop ro.build.fingerprint " + ro_build_fingerprint);
|
||||||
ShellUtils.execRootCmd("setprop ro.odm.build.fingerprint "+ro_odm_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.product.build.fingerprint " + ro_product_build_fingerprint);
|
||||||
ShellUtils.execRootCmd("setprop ro.system.build.fingerprint "+ro_system_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.system_ext.build.fingerprint " + ro_system_ext_build_fingerprint);
|
||||||
ShellUtils.execRootCmd("setprop ro.vendor.build.fingerprint "+ro_vendor_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.board.platform " + ro_build_platform);
|
||||||
|
|
||||||
// Native.setBootId(bootId);
|
// Native.setBootId(bootId);
|
||||||
// 修改drm id
|
// 修改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
|
// 电量模拟需要大于1000
|
||||||
ShellUtils.execRootCmd("setprop persist.sys.cloud.battery.capacity "+persist_sys_cloud_battery_capacity);
|
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_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.gpu.gl_renderer " + persist_sys_cloud_gpu_gl_renderer);
|
||||||
// 这个值不能随便改 必须是 OpenGL ES %d.%d 这个格式
|
// 这个值不能随便改 必须是 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.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_vendor " + persist_sys_cloud_gpu_egl_vendor);
|
||||||
ShellUtils.execRootCmd("setprop persist.sys.cloud.gpu.egl_version "+persist_sys_cloud_gpu_egl_version);
|
ShellUtils.execRootCmd("setprop persist.sys.cloud.gpu.egl_version " + persist_sys_cloud_gpu_egl_version);
|
||||||
|
|
||||||
// 填充占位符
|
|
||||||
return HttpUtil.fillUrlPlaceholders(url, params);
|
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
Log.e("ChangeDeviceInfoUtil", "Error occurred while changing device info", e);
|
Log.e("ChangeDeviceInfoUtil", "Error occurred while changing device info", e);
|
||||||
throw new RuntimeException("Error occurred in changeDeviceInfo", e);
|
throw new RuntimeException("Error occurred in changeDeviceInfo", e);
|
||||||
|
|
|
@ -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"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
package com.example.studyapp.utils;
|
package com.example.studyapp.proxy;
|
||||||
|
|
||||||
import android.content.BroadcastReceiver;
|
import android.content.BroadcastReceiver;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
@ -10,7 +10,6 @@ import java.io.IOException;
|
||||||
import java.util.concurrent.CountDownLatch;
|
import java.util.concurrent.CountDownLatch;
|
||||||
import okhttp3.Call;
|
import okhttp3.Call;
|
||||||
import okhttp3.Callback;
|
import okhttp3.Callback;
|
||||||
import okhttp3.Credentials;
|
|
||||||
import okhttp3.HttpUrl;
|
import okhttp3.HttpUrl;
|
||||||
import okhttp3.MediaType;
|
import okhttp3.MediaType;
|
||||||
import okhttp3.OkHttpClient;
|
import okhttp3.OkHttpClient;
|
|
@ -1,16 +1,22 @@
|
||||||
package com.example.studyapp.service;
|
package com.example.studyapp.service;
|
||||||
|
|
||||||
|
import android.Manifest;
|
||||||
import android.accessibilityservice.AccessibilityService;
|
import android.accessibilityservice.AccessibilityService;
|
||||||
|
import android.app.Notification;
|
||||||
import android.app.NotificationChannel;
|
import android.app.NotificationChannel;
|
||||||
import android.app.NotificationManager;
|
import android.app.NotificationManager;
|
||||||
import android.app.PendingIntent;
|
import android.app.PendingIntent;
|
||||||
import android.app.Service;
|
import android.app.Service;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
|
import android.content.pm.PackageManager;
|
||||||
|
import android.content.pm.ServiceInfo;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.os.IBinder;
|
import android.os.IBinder;
|
||||||
|
|
||||||
import android.view.accessibility.AccessibilityEvent;
|
import android.view.accessibility.AccessibilityEvent;
|
||||||
|
import android.widget.Toast;
|
||||||
import androidx.core.app.NotificationCompat;
|
import androidx.core.app.NotificationCompat;
|
||||||
|
import androidx.core.content.ContextCompat;
|
||||||
import com.example.studyapp.MainActivity;
|
import com.example.studyapp.MainActivity;
|
||||||
import com.example.studyapp.R;
|
import com.example.studyapp.R;
|
||||||
|
|
||||||
|
@ -35,28 +41,56 @@ public class MyAccessibilityService extends AccessibilityService {
|
||||||
|
|
||||||
private void createNotificationChannel() {
|
private void createNotificationChannel() {
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||||
String channelId = "2";
|
NotificationChannel channel = new NotificationChannel(
|
||||||
String channelName = "Foreground Service";
|
"2",
|
||||||
int importance = NotificationManager.IMPORTANCE_LOW;
|
"无障碍服务",
|
||||||
NotificationChannel channel = new NotificationChannel(channelId, channelName, importance);
|
NotificationManager.IMPORTANCE_LOW
|
||||||
NotificationManager notificationManager = getSystemService(NotificationManager.class);
|
);
|
||||||
if (notificationManager != null) {
|
channel.setDescription("此服务在后台运行,提供无障碍支持。");
|
||||||
notificationManager.createNotificationChannel(channel);
|
NotificationManager manager = getSystemService(NotificationManager.class);
|
||||||
|
if (manager != null) {
|
||||||
|
manager.createNotificationChannel(channel);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void startForegroundService() {
|
private void startForegroundService() {
|
||||||
createNotificationChannel();
|
createNotificationChannel();
|
||||||
|
|
||||||
Intent notificationIntent = new Intent(this, MainActivity.class);
|
Intent notificationIntent = new Intent(this, MainActivity.class);
|
||||||
int pendingIntentFlags = Build.VERSION.SDK_INT >= Build.VERSION_CODES.M ? PendingIntent.FLAG_IMMUTABLE : 0;
|
int pendingIntentFlags = Build.VERSION.SDK_INT >= Build.VERSION_CODES.M ? PendingIntent.FLAG_IMMUTABLE : 0;
|
||||||
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, pendingIntentFlags);
|
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, pendingIntentFlags);
|
||||||
|
|
||||||
NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this, "2")
|
NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this, "2")
|
||||||
.setContentTitle("无障碍服务运行中")
|
.setContentTitle("无障碍服务运行中")
|
||||||
.setContentText("此服务正在持续运行")
|
.setContentText("此服务正在持续运行")
|
||||||
.setSmallIcon(R.drawable.ic_launcher_foreground)
|
.setSmallIcon(R.drawable.ic_launcher_foreground)
|
||||||
.setContentIntent(pendingIntent);
|
.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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
Binary file not shown.
|
@ -11,5 +11,6 @@
|
||||||
<domain includeSubdomains="true">8.211.204.20</domain>
|
<domain includeSubdomains="true">8.211.204.20</domain>
|
||||||
<domain includeSubdomains="true">127.0.0.1</domain>
|
<domain includeSubdomains="true">127.0.0.1</domain>
|
||||||
<domain includeSubdomains="true">8.217.137.25</domain>
|
<domain includeSubdomains="true">8.217.137.25</domain>
|
||||||
|
<domain includeSubdomains="true">47.238.96.231</domain>
|
||||||
</domain-config>
|
</domain-config>
|
||||||
</network-security-config>
|
</network-security-config>
|
||||||
|
|
|
@ -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<Request> 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<Request> 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\""));
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue