瀏覽代碼

1.新增log日志记录
2.新增广播接收用于进程通讯

JaycePC 6 月之前
父節點
當前提交
7fe20cbaec

+ 2 - 0
app/build.gradle

@@ -60,5 +60,7 @@ dependencies {
     implementation 'com.github.AnyChart:AnyChart-Android:1.1.5'
     //noinspection UseTomlInstead
     implementation 'com.squareup.okhttp3:okhttp:4.12.0'
+    //noinspection UseTomlInstead
+    implementation("com.squareup.okhttp3:logging-interceptor:4.12.0")
 
 }

+ 10 - 0
app/src/main/AndroidManifest.xml

@@ -11,6 +11,7 @@
     <uses-permission android:name="android.permission.DOWNLOAD_WITHOUT_NOTIFICATION" />
 
     <application
+        android:name=".app.App"
         android:allowBackup="true"
         android:dataExtractionRules="@xml/data_extraction_rules"
         android:fullBackupContent="@xml/backup_rules"
@@ -22,6 +23,15 @@
         android:supportsRtl="true"
         android:theme="@style/Theme.Update"
         tools:targetApi="31">
+        <receiver
+            android:name=".broadcast.ProcessReceiver"
+            android:exported="true"
+            tools:ignore="ExportedReceiver">
+            <intent-filter>
+                <action android:name="XN_ACTION" />
+            </intent-filter>
+        </receiver>
+
         <activity
             android:name=".SettingActivity"
             android:exported="false" />

+ 70 - 3
app/src/main/java/xn/update/MainActivity.java

@@ -4,20 +4,26 @@ import android.annotation.SuppressLint;
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.os.Bundle;
+import android.text.TextUtils;
+import android.util.Log;
 
 import androidx.activity.EdgeToEdge;
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 import androidx.appcompat.app.AppCompatActivity;
 import androidx.core.graphics.Insets;
+import androidx.core.util.Pair;
 import androidx.core.view.ViewCompat;
 import androidx.core.view.WindowInsetsCompat;
 
 import com.blankj.utilcode.util.ActivityUtils;
 import com.blankj.utilcode.util.AppUtils;
 import com.blankj.utilcode.util.LogUtils;
+import com.blankj.utilcode.util.NetworkUtils;
 import com.blankj.utilcode.util.SPUtils;
+import com.blankj.utilcode.util.ThreadUtils;
 import com.hikvision.dmb.display.InfoDisplayApi;
+import com.hikvision.dmb.network.InfoNetworkApi;
 import com.hikvision.dmb.system.InfoSystemApi;
 import com.hikvision.dmb.util.InfoUtilApi;
 import com.hjq.permissions.OnPermissionCallback;
@@ -26,9 +32,15 @@ import com.hjq.permissions.XXPermissions;
 import com.lxj.xpopup.XPopup;
 import com.lxj.xpopup.impl.InputConfirmPopupView;
 
+import org.json.JSONObject;
+
 import java.util.List;
+import java.util.concurrent.ThreadLocalRandom;
+import java.util.concurrent.TimeUnit;
 
+import okhttp3.Response;
 import xn.update.databinding.ActivityMainBinding;
+import xn.update.http.HttpTool;
 
 public class MainActivity extends AppCompatActivity {
     private ActivityMainBinding binding;
@@ -37,12 +49,14 @@ public class MainActivity extends AppCompatActivity {
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
-
+        // 先启动主应用
+        Tool.INSTANCE.startMasterApp();
         InfoSystemApi.openAdb();
         InfoDisplayApi.setStatusBarEnable(false);
         InfoDisplayApi.setNavigationBarEnable(false);
         InfoUtilApi.setUsbSwitch(false);
         SPUtils.getInstance().put("isRoot", 0 == InfoUtilApi.getRoot());
+        SPUtils.getInstance().put("IP", InfoNetworkApi.getEthernetConfig().ipAddress);
 
         EdgeToEdge.enable(this);
         binding = ActivityMainBinding.inflate(getLayoutInflater());
@@ -80,13 +94,12 @@ public class MainActivity extends AppCompatActivity {
         XXPermissions.with(this)
                 .permission(Permission.READ_EXTERNAL_STORAGE)
                 .permission(Permission.WRITE_EXTERNAL_STORAGE)
-                // 通知栏权限
                 .permission(Permission.NOTIFICATION_SERVICE)
                 .request(new OnPermissionCallback() {
                     @Override
                     public void onGranted(@NonNull List<String> permissions, boolean allGranted) {
                         if (allGranted) {
-                            LogUtils.d("所有权限已获取");
+                            terminalAuth();
                         } else {
                             new XPopup.Builder(MainActivity.this)
                                     .dismissOnBackPressed(false)
@@ -119,6 +132,60 @@ public class MainActivity extends AppCompatActivity {
                 });
     }
 
+    ThreadUtils.SimpleTask<Boolean> simpleTask = new ThreadUtils.SimpleTask<Boolean>() {
+        @Override
+        public Boolean doInBackground() throws Throwable {
+            return NetworkUtils.isAvailableByPing(Tool.INSTANCE.getBaseUrl().host());
+        }
+
+        @Override
+        public void onSuccess(Boolean result) {
+            if (result) {
+                binding.tipsTV.setText("鉴权中...");
+                ThreadUtils.executeByCached(new ThreadUtils.SimpleTask<Pair<Boolean, String>>() {
+                    @Override
+                    public Pair<Boolean, String> doInBackground() throws Throwable {
+                        try {
+                            SPUtils.getInstance().put("TerminalAuth", "");
+                            Response response = HttpTool.INSTANCE.terminalAuth();
+                            if (response.isSuccessful()) {
+                                String json = response.body().string();
+                                JSONObject jsonObject = new JSONObject(json);
+                                int code = jsonObject.getInt("code");
+                                if (200 == code) {
+                                    String data = jsonObject.getString("data");
+                                    SPUtils.getInstance().put("TerminalAuth", TextUtils.isEmpty(data) ? "" : data);
+                                    return Pair.create(true, "");
+                                } else {
+                                    return Pair.create(false, jsonObject.getString("message"));
+                                }
+                            }
+                        } catch (Exception e) {
+                            LogUtils.e(Log.getStackTraceString(e));
+                        }
+                        return Pair.create(false, "鉴权异常,请联系管理员!");
+                    }
+
+                    @Override
+                    public void onSuccess(Pair<Boolean, String> result) {
+                        if (result.first) {
+                            binding.tipsTV.setText(result.second);
+                            ThreadUtils.cancel(simpleTask);
+                        } else {
+                            binding.tipsTV.setText(result.second);
+                        }
+                    }
+                });
+            } else {
+                binding.tipsTV.setText("无法连接到服务器,请联系管理员!");
+            }
+        }
+    };
+
+    private void terminalAuth() {
+        ThreadUtils.executeByCachedAtFixRate(simpleTask, ThreadLocalRandom.current().nextInt(10, 20), TimeUnit.SECONDS);
+    }
+
     @SuppressLint("MissingSuperCall")
     @Override
     public void onBackPressed() {

+ 6 - 1
app/src/main/java/xn/update/SettingActivity.java

@@ -71,7 +71,11 @@ public class SettingActivity extends AppCompatActivity {
             // 启动文件管理
             binding.fileBrowserBT.setOnClickListener(v -> Tool.INSTANCE.openFileBrowser());
             // 重启设备
-            binding.rebootBT.setOnClickListener(v -> InfoSystemApi.reboot());
+            binding.rebootBT.setOnClickListener(v -> {
+                        InfoSystemApi.reboot();
+                        SPUtils.getInstance().put("isDebug", false);
+                    }
+            );
             // 系统设置
             binding.settingBT.setOnClickListener(v -> {
                 Tool.INSTANCE.openSetting();
@@ -94,6 +98,7 @@ public class SettingActivity extends AppCompatActivity {
 
     private void save() {
         finish();
+        SPUtils.getInstance().put("isDebug", false);
         Tool.INSTANCE.openApp("com.dlc.xn.eboard");
     }
 }

+ 114 - 25
app/src/main/java/xn/update/TimeTickReceiver.java

@@ -7,18 +7,30 @@ import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.net.Uri;
+import android.os.AsyncTask;
 import android.os.Environment;
 import android.util.Log;
 
+import com.blankj.utilcode.util.ActivityUtils;
 import com.blankj.utilcode.util.AppUtils;
 import com.blankj.utilcode.util.FileUtils;
 import com.blankj.utilcode.util.GsonUtils;
 import com.blankj.utilcode.util.LogUtils;
+import com.blankj.utilcode.util.SPUtils;
+import com.blankj.utilcode.util.ShellUtils;
 import com.blankj.utilcode.util.ThreadUtils;
 
+import org.json.JSONException;
+
+import java.io.BufferedReader;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
 import java.util.List;
 
-import xn.update.http.bean.UpdateTask;
+import okhttp3.Response;
+import xn.update.http.HttpTool;
+import xn.update.http.bean.response.UpdateTask;
 
 public class TimeTickReceiver extends BroadcastReceiver {
     private volatile boolean isRunning = false;
@@ -28,11 +40,13 @@ public class TimeTickReceiver extends BroadcastReceiver {
     @SuppressLint("SdCardPath")
     private final String apkPath = "/sdcard/Download/apk/";
     private final String apkName = "app.apk";
+    private UpdateTask.Task task;
 
     @Override
     public void onReceive(Context context, Intent intent) {
+        LogUtils.d("分钟", isRunning, ActivityUtils.getActivityList());
         // 空闲中
-        if (!isRunning && !AppUtils.isAppDebug()) {
+        if (!isRunning) {
             if (null == downloadManager) {
                 downloadManager = (DownloadManager) context.getApplicationContext().getSystemService(Context.DOWNLOAD_SERVICE);
                 downloadApkReceiver = new BroadcastReceiver() {
@@ -40,9 +54,41 @@ public class TimeTickReceiver extends BroadcastReceiver {
                     public void onReceive(Context context, Intent intent) {
                         long id = intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, -1);
                         if (downloadId == id) {
-                            Tool.INSTANCE.cmd("pm install -d -g " + apkPath + apkName);
-                            Tool.INSTANCE.openApp("com.dlc.xn.eboard");
-//                            isRunning = false;
+                            if (null != task) {
+                                AsyncTask.execute(() -> {
+                                    try {
+                                        HttpTool.INSTANCE.updateCallBack(task.getTaskId(), task.getDeviceCode(), true, false);
+                                    } catch (IOException | JSONException e) {
+                                        LogUtils.e(Log.getStackTraceString(e));
+                                    }
+                                });
+                                if (task.getStartLaunchPackage().equals(AppUtils.getAppPackageName())) {
+                                    AsyncTask.execute(() -> {
+                                        try {
+                                            HttpTool.INSTANCE.updateCallBack(task.getTaskId(), task.getDeviceCode(), true, true);
+                                            Tool.INSTANCE.cmd("pm install -d -g " + apkPath + apkName);
+                                            Tool.INSTANCE.openApp(task.getStartLaunchPackage());
+                                        } catch (IOException | JSONException e) {
+                                            LogUtils.e(Log.getStackTraceString(e));
+                                        }
+                                    });
+                                } else {
+                                    ShellUtils.CommandResult commandResult = ShellUtils.execCmd("pm install -d -g " + apkPath + apkName, true);
+                                    if (commandResult.result == 0) {
+                                        AsyncTask.execute(() -> {
+                                            try {
+                                                HttpTool.INSTANCE.updateCallBack(task.getTaskId(), task.getDeviceCode(), true, true);
+                                            } catch (IOException | JSONException e) {
+                                                LogUtils.e(Log.getStackTraceString(e));
+                                            }
+                                        });
+                                        Tool.INSTANCE.startMasterApp();
+                                    } else {
+                                        LogUtils.e(commandResult.errorMsg);
+                                    }
+                                }
+                            }
+                            isRunning = false;
                         }
                     }
                 };
@@ -53,37 +99,80 @@ public class TimeTickReceiver extends BroadcastReceiver {
                 public Boolean doInBackground() throws Throwable {
                     isRunning = true;
                     try {
-                        String json = "{\"code\":200,\"message\":\"操作成功\",\"data\":[{\"deviceCode\":\"EBOARD_FE2567751\",\"apkUrl\":\"http://192.168.1.8/api/statics/bigFile/20241206/22e4d366-2df8-4a19-8002-d11b205a1ba3.apk\",\"versionName\":\"1.3\",\"startLaunchPackage\":\"com.dlc.xn.eboard\",\"isForceUpdate\":false}]}";
-                        UpdateTask updateTask = GsonUtils.fromJson(json, UpdateTask.class);
-                        if (updateTask.getCode() == 200) {
-                            List<UpdateTask.Task> updateTaskData = updateTask.getData();
-                            if (null != updateTaskData && !updateTaskData.isEmpty()) {
-                                UpdateTask.Task task = updateTaskData.get(0);
-                                FileUtils.createOrExistsDir(apkPath);
-                                FileUtils.deleteAllInDir(apkPath);
-                                DownloadManager.Request request = new DownloadManager.Request(Uri.parse(task.getApkUrl()));
-                                request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, "apk/" + apkName);
-                                request.setMimeType("application/vnd.android.package-archive");
-                                request.setVisibleInDownloadsUi(false);
-                                request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_HIDDEN);
-                                context.registerReceiver(downloadApkReceiver, new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE));
-                                downloadId = downloadManager.enqueue(request);
-                                return true;
+                        Response response = HttpTool.INSTANCE.update();
+                        if (response.isSuccessful()) {
+                            String json = response.body().string();
+                            UpdateTask updateTask = GsonUtils.fromJson(json, UpdateTask.class);
+                            if (updateTask.getCode() == 200) {
+                                List<UpdateTask.Task> updateTaskData = updateTask.getData();
+                                if (null != updateTaskData && !updateTaskData.isEmpty()) {
+                                    task = updateTaskData.get(0);
+                                    FileUtils.createOrExistsDir(apkPath);
+                                    FileUtils.deleteAllInDir(apkPath);
+                                    if (!AppUtils.getAppPackageName().equals(task.getStartLaunchPackage())) {
+                                        SPUtils.getInstance().put("masterApp", task.getStartLaunchPackage());
+                                    }
+                                    DownloadManager.Request request = new DownloadManager.Request(Uri.parse(task.getApkUrl()));
+                                    request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, "apk/" + apkName);
+                                    request.setMimeType("application/vnd.android.package-archive");
+                                    request.setVisibleInDownloadsUi(false);
+                                    request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_HIDDEN);
+                                    context.registerReceiver(downloadApkReceiver, new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE));
+                                    downloadId = downloadManager.enqueue(request);
+                                    return true;
+                                }
+                            } else {
+                                LogUtils.e(updateTask.getMessage());
                             }
-                        } else {
-                            LogUtils.e(updateTask.getMessage());
                         }
                     } catch (Exception e) {
                         LogUtils.e(Log.getStackTraceString(e));
                     }
+                    isRunning = false;
                     return false;
                 }
 
                 @Override
                 public void onSuccess(Boolean result) {
-                    if (!result) {
-                        isRunning = false;
+                }
+            });
+
+        }
+
+        if (!SPUtils.getInstance().getBoolean("isDebug")) {
+            ThreadUtils.executeByCached(new ThreadUtils.SimpleTask<Object>() {
+                @Override
+                public Object doInBackground() throws Throwable {
+                    try {
+                        ShellUtils.CommandResult commandResult = ShellUtils.execCmd("dumpsys activity activities", true);
+                        BufferedReader reader = new BufferedReader(new InputStreamReader(new ByteArrayInputStream(commandResult.successMsg.getBytes())));
+                        String line;
+                        while ((line = reader.readLine()) != null) {
+                            if (line.contains("mResumedActivity") || line.contains("mCurrentFocus")) {
+                                String[] itemArray = line.split(" ", -1);
+                                for (String item : itemArray) {
+                                    if (item.contains("/")) {
+                                        String packageName = item.substring(0, item.indexOf("/"));
+                                        if (!"com.dlc.xn.eboard".equals(packageName)) {
+                                            LogUtils.d("定时拉起主应用");
+                                            Tool.INSTANCE.stopApp("com.dlc.xn.eboard");
+                                            Tool.INSTANCE.startMasterApp();
+                                        }
+                                        break;
+                                    }
+                                }
+                                break;
+                            }
+                        }
+                    } catch (Exception e) {
+                        LogUtils.e(Log.getStackTraceString(e));
                     }
+                    return null;
+                }
+
+                @Override
+                public void onSuccess(Object result) {
+
                 }
             });
         }

+ 24 - 0
app/src/main/java/xn/update/Tool.java

@@ -2,8 +2,12 @@ package xn.update;
 
 import com.blankj.utilcode.util.AppUtils;
 import com.blankj.utilcode.util.LogUtils;
+import com.blankj.utilcode.util.SPUtils;
+import com.blankj.utilcode.util.ShellUtils;
 import com.hikvision.dmb.system.InfoSystemApi;
 
+import okhttp3.HttpUrl;
+
 public enum Tool {
     INSTANCE;
 
@@ -28,8 +32,28 @@ public enum Tool {
         InfoSystemApi.execCommand("monkey -p " + packageName + " -c android.intent.category.LAUNCHER 1");
     }
 
+    public ShellUtils.CommandResult stopApp(String packageName) {
+        return ShellUtils.execCmd("am force-stop " + packageName, true);
+    }
+
+    public void startMasterApp() {
+        openApp(SPUtils.getInstance().getString("masterApp", "com.dlc.xn.eboard"));
+    }
+
     public int cmd(String cmd) {
         LogUtils.d(cmd);
         return InfoSystemApi.execCommand(cmd);
     }
+
+    public String getSerialNumber() {
+        return "EBOARD_" + InfoSystemApi.getSerialNumber();
+    }
+
+    public HttpUrl getBaseUrl() {
+        if (AppUtils.isAppDebug()) {
+            return HttpUrl.get("http://192.168.1.8/api/");
+        } else {
+            return HttpUrl.get("http://172.16.0.65/api/");
+        }
+    }
 }

+ 0 - 53
app/src/main/java/xn/update/UpdateBean.java

@@ -1,53 +0,0 @@
-package xn.update;
-
-public class UpdateBean {
-    /**
-     * apk地址
-     */
-    private String apkUrl;
-    /**
-     * 是否更新
-     */
-    private boolean isUpdate;
-    /**
-     * 是否强制更新
-     */
-    private boolean isForceUpdate;
-    /**
-     * 启动页路径,例:com.xxx/com.xxx.Activity
-     */
-    private String startLaunchActivity;
-
-
-    public String getApkUrl() {
-        return apkUrl;
-    }
-
-    public void setApkUrl(String apkUrl) {
-        this.apkUrl = apkUrl;
-    }
-
-    public boolean isUpdate() {
-        return isUpdate;
-    }
-
-    public void setUpdate(boolean update) {
-        isUpdate = update;
-    }
-
-    public boolean isForceUpdate() {
-        return isForceUpdate;
-    }
-
-    public void setForceUpdate(boolean forceUpdate) {
-        isForceUpdate = forceUpdate;
-    }
-
-    public String getStartLaunchActivity() {
-        return startLaunchActivity;
-    }
-
-    public void setStartLaunchActivity(String startLaunchActivity) {
-        this.startLaunchActivity = startLaunchActivity;
-    }
-}

+ 46 - 0
app/src/main/java/xn/update/app/App.java

@@ -0,0 +1,46 @@
+package xn.update.app;
+
+import android.annotation.SuppressLint;
+import android.app.Application;
+
+import com.blankj.utilcode.util.AppUtils;
+import com.blankj.utilcode.util.CrashUtils;
+import com.blankj.utilcode.util.FileUtils;
+import com.blankj.utilcode.util.LogUtils;
+
+import xn.update.Tool;
+
+public class App extends Application {
+    @Override
+    @SuppressLint("SdCardPath")
+    public void onCreate() {
+        super.onCreate();
+        String logPath = "/sdcard/logs/";
+        String crashPath = "/sdcard/logs/crash/";
+        // log文件存储地址
+        FileUtils.createOrExistsDir(logPath);
+        FileUtils.createOrExistsDir(crashPath);
+        CrashUtils.init(crashPath, crashInfo -> {
+            LogUtils.e(crashInfo);
+            Tool.INSTANCE.reStartApp();
+        });
+        LogUtils.Config config = LogUtils.getConfig();
+        // log开关控制
+        config.setLogSwitch(true);
+        // log控制台开关
+        config.setConsoleSwitch(true);
+        // logTag
+        config.setGlobalTag("Jayce");
+        // log头部信息开关
+        config.setLogHeadSwitch(true);
+        // log文件开关
+        config.setLog2FileSwitch(true);
+        config.setDir(logPath);
+        // log文件前缀
+        config.setFilePrefix(AppUtils.getAppName());
+        // log边框开关
+        config.setBorderSwitch(true);
+        // log文件保存天数
+        config.setSaveDays(30);
+    }
+}

+ 19 - 0
app/src/main/java/xn/update/broadcast/ProcessReceiver.java

@@ -0,0 +1,19 @@
+package xn.update.broadcast;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+
+import com.blankj.utilcode.util.AppUtils;
+import com.blankj.utilcode.util.LogUtils;
+import com.blankj.utilcode.util.SPUtils;
+
+public class ProcessReceiver extends BroadcastReceiver {
+    @Override
+    public void onReceive(Context context, Intent intent) {
+        // 其他应用发送过来的信息
+        if (!AppUtils.getAppPackageName().equals(intent.getPackage())) {
+            SPUtils.getInstance().put("isDebug", intent.getBooleanExtra("isDebug", false));
+        }
+    }
+}

+ 42 - 1
app/src/main/java/xn/update/http/HttpTool.java

@@ -1,10 +1,51 @@
 package xn.update.http;
 
 
-import okhttp3.OkHttpClient;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.io.IOException;
+
+import okhttp3.Response;
+import xn.update.Tool;
 
 public enum HttpTool {
     INSTANCE;
 
+    public Response terminalAuth() throws IOException, JSONException {
+        JSONObject jsonObject = new JSONObject();
+        jsonObject.put("deviceCode", Tool.INSTANCE.getSerialNumber());
+        return OkHttpUtils.INSTANCE.postSync(Tool.INSTANCE.getBaseUrl() + "terminal/authorize", jsonObject.toString());
+    }
+
+    public Response update() throws IOException, JSONException {
+        JSONObject jsonObject = new JSONObject();
+        jsonObject.put("deviceCode", Tool.INSTANCE.getSerialNumber());
+        return OkHttpUtils.INSTANCE.postSync(Tool.INSTANCE.getBaseUrl() + "terminal/upgrade/device/task", jsonObject.toString());
+    }
+
+    public Response updateCallBack(String taskId, String deviceCode, boolean isDownload, boolean isInstall) throws IOException, JSONException {
+        JSONObject jsonObject = new JSONObject();
+        jsonObject.put("taskId", taskId);
+        jsonObject.put("deviceCode", deviceCode);
+        if (isDownload) {
+            jsonObject.put("status", "downloaded");
+        }
+        if (isInstall) {
+            jsonObject.put("status", "success");
+        }
+        return OkHttpUtils.INSTANCE.postSync(Tool.INSTANCE.getBaseUrl() + "terminal/upgrade/device/callback", jsonObject.toString());
+    }
+
+    /**
+     * category    1:系统参数 2:公共配置
+     * configType  1:基础配置 2: 管控一体机 3:化学品终端 4:小程序配置 5:开发配置 6:首页配置
+     */
+    public Response getConfig() throws JSONException, IOException {
+        JSONObject jsonObject = new JSONObject();
+        jsonObject.put("category", 2);
+        jsonObject.put("configType", 5);
+        return OkHttpUtils.INSTANCE.postSync(Tool.INSTANCE.getBaseUrl() + "terminal/sys/config/info/getConfigByType", jsonObject.toString());
+    }
 
 }

+ 61 - 0
app/src/main/java/xn/update/http/LogInterceptor.java

@@ -0,0 +1,61 @@
+package xn.update.http;
+
+import android.text.TextUtils;
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+
+import com.blankj.utilcode.util.GsonUtils;
+import com.blankj.utilcode.util.LogUtils;
+import com.blankj.utilcode.util.SPUtils;
+
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+
+import okhttp3.Interceptor;
+import okhttp3.Request;
+import okhttp3.Response;
+import okhttp3.ResponseBody;
+import okio.Buffer;
+import okio.BufferedSource;
+import xn.update.Tool;
+
+public class LogInterceptor implements Interceptor {
+    @NonNull
+    @Override
+    public Response intercept(@NonNull Chain chain) throws IOException {
+        try {
+            Request oldRequest = chain.request();
+            Request.Builder newRequestBuilder = oldRequest.newBuilder();
+            String terminalAuth = SPUtils.getInstance().getString("TerminalAuth", "");
+            if (null != terminalAuth && !TextUtils.isEmpty(terminalAuth)) {
+                newRequestBuilder.header("TerminalAuth", "Bearer " + terminalAuth);
+            }
+            newRequestBuilder.header("SN", Tool.INSTANCE.getSerialNumber());
+            newRequestBuilder.header("IP", SPUtils.getInstance().getString("IP", "127.0.0.1"));
+
+            Request newRequest = newRequestBuilder.build();
+            // 记录请求报文
+            String requestLog = "--> " + newRequest.method() + " " + newRequest.url() + "\n"
+                    + newRequest.headers() + "\n"
+                    + (newRequest.body() != null ? GsonUtils.toJson(newRequest.body()) : ""); // 请求体可能为空
+            LogUtils.d(requestLog);
+
+            Response response = chain.proceed(newRequest);
+            ResponseBody responseBody = response.body();
+            BufferedSource source = responseBody.source();
+            source.request(Long.MAX_VALUE);
+            Buffer buffer = source.getBuffer();
+            String responseBodyString = buffer.clone().readString(StandardCharsets.UTF_8);
+            // 记录响应报文
+            String responseLog = "<-- " + response.code() + " " + response.message() + " " + response.request().url() + "\n"
+                    + response.headers() + "\n"
+                    + (response.body() != null ? responseBodyString : ""); // 响应体可能为空
+            LogUtils.d(responseLog);
+            return response.newBuilder().body(ResponseBody.create(responseBody.contentType(), responseBodyString)).build();
+        } catch (Exception e) {
+            LogUtils.e(Log.getStackTraceString(e));
+        }
+        return chain.proceed(chain.request());
+    }
+}

+ 9 - 6
app/src/main/java/xn/update/http/OkHttpUtils.java

@@ -8,17 +8,20 @@ import okhttp3.OkHttpClient;
 import okhttp3.Request;
 import okhttp3.RequestBody;
 import okhttp3.Response;
+import xn.update.http.bean.AllLogInterceptor;
 
-public class OkHttpUtils {
-
-    private static final OkHttpClient client = new OkHttpClient();
-    private static final MediaType JSON = MediaType.parse("application/json; charset=utf-8");
+public enum OkHttpUtils {
+    INSTANCE;
+    private final OkHttpClient client = new OkHttpClient.Builder()
+            .addInterceptor(new AllLogInterceptor())
+            .build();
+    private final MediaType JSON = MediaType.parse("application/json; charset=utf-8");
 
     private OkHttpUtils() {
     }
 
     // 同步 GET 请求
-    public static Response getSync(String url) throws IOException {
+    public Response getSync(String url) throws IOException {
         Request request = new Request.Builder()
                 .url(url)
                 .build();
@@ -27,7 +30,7 @@ public class OkHttpUtils {
     }
 
     // 同步 POST 请求
-    public static Response postSync(String url, String json) throws IOException {
+    public Response postSync(String url, String json) throws IOException {
         RequestBody body = RequestBody.create(JSON, json);
         Request request = new Request.Builder()
                 .url(url)

+ 80 - 0
app/src/main/java/xn/update/http/bean/AllLogInterceptor.java

@@ -0,0 +1,80 @@
+package xn.update.http.bean;
+
+import android.text.TextUtils;
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+
+import com.blankj.utilcode.util.LogUtils;
+import com.blankj.utilcode.util.SPUtils;
+
+import java.io.IOException;
+import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
+
+import okhttp3.Interceptor;
+import okhttp3.Request;
+import okhttp3.RequestBody;
+import okhttp3.Response;
+import okhttp3.ResponseBody;
+import okio.Buffer;
+import okio.BufferedSource;
+import xn.update.Tool;
+
+public class AllLogInterceptor implements Interceptor {
+    @NonNull
+    @Override
+    public Response intercept(@NonNull Chain chain) throws IOException {
+        try {
+            Request request = chain.request();
+            Request.Builder newRequestBuilder = request.newBuilder();
+            String terminalAuth = SPUtils.getInstance().getString("TerminalAuth", "");
+            if (null != terminalAuth && !TextUtils.isEmpty(terminalAuth)) {
+                newRequestBuilder.header("TerminalAuth", "Bearer " + terminalAuth);
+            }
+            newRequestBuilder.header("SN", Tool.INSTANCE.getSerialNumber());
+            newRequestBuilder.header("IP", SPUtils.getInstance().getString("IP", "127.0.0.1"));
+            request = newRequestBuilder.build();
+            long t1 = System.nanoTime();
+            // 记录请求信息
+            StringBuilder requestLog = new StringBuilder();
+            requestLog.append("--> ").append(request.method()).append(" ").append(request.url()).append("\n");
+            requestLog.append(request.headers()).append("\n");
+            // 记录请求体
+            RequestBody requestBody = request.body();
+            if (requestBody != null) {
+                Buffer buffer = new Buffer();
+                requestBody.writeTo(buffer);
+                Charset charset = requestBody.contentType() != null ? requestBody.contentType().charset(StandardCharsets.UTF_8) : StandardCharsets.UTF_8;
+                requestLog.append(buffer.readString(charset)).append("\n");
+            }
+            // 打印请求信息
+            LogUtils.d(requestLog);
+            // 执行请求
+            Response response = chain.proceed(request);
+            long t2 = System.nanoTime();
+            // 记录响应信息
+            StringBuilder responseLog = new StringBuilder();
+            responseLog.append("<-- ").append(response.code()).append(" ").append(response.message()).append(" ").append(response.request().url()).append(" (").append((t2 - t1) / 1e6d).append("ms)\n\n");
+//            responseLog.append(response.headers()).append("\n");
+            // 记录响应体
+            ResponseBody responseBody = response.body();
+            if (responseBody != null) {
+                BufferedSource source = responseBody.source();
+                source.request(Long.MAX_VALUE); // Buffer the entire body.
+                Buffer buffer = source.getBuffer();
+                Charset charset = responseBody.contentType() != null ? responseBody.contentType().charset(StandardCharsets.UTF_8) : StandardCharsets.UTF_8;
+                responseLog.append(buffer.clone().readString(charset)).append("\n"); // 使用 clone() 避免消耗响应体
+                response = response.newBuilder()
+                        .body(ResponseBody.create(responseBody.contentType(), buffer.size(), buffer))
+                        .build();
+            }
+            // 打印响应信息
+            LogUtils.d(responseLog);
+            return response;
+        } catch (Exception e) {
+            LogUtils.e(Log.getStackTraceString(e));
+        }
+        return chain.proceed(chain.request());
+    }
+}

+ 16 - 4
app/src/main/java/xn/update/http/bean/UpdateTask.java

@@ -1,18 +1,20 @@
-package xn.update.http.bean;
+package xn.update.http.bean.response;
 
+import java.util.ArrayList;
 import java.util.List;
 
 public class UpdateTask {
 
+
     /**
      * code : 200
      * message : 操作成功
-     * data : [{"deviceCode":"EBOARD_FE2567751","apkUrl":"http://192.168.1.8/api/statics/bigFile/20241206/22e4d366-2df8-4a19-8002-d11b205a1ba3.apk","versionName":"1.3","startLaunchPackage":"com.dlc.xn.eboard","isForceUpdate":false}]
+     * data : [{"taskId":"1866732769045250050","deviceCode":"EBOARD_FG5320499","apkUrl":"http://192.168.1.8/api/statics/bigFile/20241206/22e4d366-2df8-4a19-8002-d11b205a1ba3.apk","versionName":"1.3","startLaunchPackage":"com.dlc.xn.eboard","isForceUpdate":false}]
      */
 
     private int code;
     private String message;
-    private List<Task> data;
+    private List<Task> data = new ArrayList<>();
 
     public int getCode() {
         return code;
@@ -40,19 +42,29 @@ public class UpdateTask {
 
     public static class Task {
         /**
-         * deviceCode : EBOARD_FE2567751
+         * taskId : 1866732769045250050
+         * deviceCode : EBOARD_FG5320499
          * apkUrl : http://192.168.1.8/api/statics/bigFile/20241206/22e4d366-2df8-4a19-8002-d11b205a1ba3.apk
          * versionName : 1.3
          * startLaunchPackage : com.dlc.xn.eboard
          * isForceUpdate : false
          */
 
+        private String taskId;
         private String deviceCode;
         private String apkUrl;
         private String versionName;
         private String startLaunchPackage;
         private boolean isForceUpdate;
 
+        public String getTaskId() {
+            return taskId;
+        }
+
+        public void setTaskId(String taskId) {
+            this.taskId = taskId;
+        }
+
         public String getDeviceCode() {
             return deviceCode;
         }

+ 10 - 0
app/src/main/res/layout/activity_main.xml

@@ -15,6 +15,16 @@
         android:src="@mipmap/logo" />
 
     <TextView
+        android:id="@+id/tips_TV"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_below="@id/logo_IV"
+        android:layout_centerHorizontal="true"
+        android:layout_marginTop="20dp"
+        android:text="鉴权异常"
+        android:textColor="@color/black" />
+
+    <TextView
         android:id="@+id/version_name_TV"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"