From 39d3520350e2ad091f234d05f051e262c8df6069 Mon Sep 17 00:00:00 2001 From: MTing Date: Thu, 28 Aug 2025 15:53:19 +0800 Subject: [PATCH] change network util --- .idea/.gitignore | 3 + .idea/AndroidProjectSystem.xml | 6 + .idea/migrations.xml | 10 ++ .idea/misc.xml | 10 ++ .idea/runConfigurations.xml | 17 +++ .../main/java/com/ouxuan/oxface/MainActivity.java | 128 ++++++++++------ .../com/ouxuan/oxface/network/NetworkManager.java | 6 + .../ouxuan/oxface/network/api/PadApiService.java | 17 ++- .../oxface/network/debug/NetworkDebugLogger.java | 168 +++++++++++++++++++++ .../interceptor/NetworkDebugInterceptor.java | 66 ++++++++ .../ouxuan/oxface/network/utils/NetworkUtils.java | 43 +++++- gradle/wrapper/gradle-wrapper.properties | 3 +- 12 files changed, 417 insertions(+), 60 deletions(-) create mode 100644 .idea/.gitignore create mode 100644 .idea/AndroidProjectSystem.xml create mode 100644 .idea/migrations.xml create mode 100644 .idea/misc.xml create mode 100644 .idea/runConfigurations.xml create mode 100644 app/src/main/java/com/ouxuan/oxface/network/debug/NetworkDebugLogger.java create mode 100644 app/src/main/java/com/ouxuan/oxface/network/interceptor/NetworkDebugInterceptor.java diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..26d3352 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,3 @@ +# Default ignored files +/shelf/ +/workspace.xml diff --git a/.idea/AndroidProjectSystem.xml b/.idea/AndroidProjectSystem.xml new file mode 100644 index 0000000..4a53bee --- /dev/null +++ b/.idea/AndroidProjectSystem.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/.idea/migrations.xml b/.idea/migrations.xml new file mode 100644 index 0000000..f8051a6 --- /dev/null +++ b/.idea/migrations.xml @@ -0,0 +1,10 @@ + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..3040d03 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,10 @@ + + + + + + + + + \ No newline at end of file diff --git a/.idea/runConfigurations.xml b/.idea/runConfigurations.xml new file mode 100644 index 0000000..16660f1 --- /dev/null +++ b/.idea/runConfigurations.xml @@ -0,0 +1,17 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/java/com/ouxuan/oxface/MainActivity.java b/app/src/main/java/com/ouxuan/oxface/MainActivity.java index 992b99a..b4d5ddb 100644 --- a/app/src/main/java/com/ouxuan/oxface/MainActivity.java +++ b/app/src/main/java/com/ouxuan/oxface/MainActivity.java @@ -197,8 +197,13 @@ public class MainActivity extends AppCompatActivity { @Override public void onError(int errorCode, String errorMessage) { - // 登录失败,显示错误信息 - android.util.Log.e("MainActivity", "Login error - Code: " + errorCode + ", Message: " + errorMessage); + // 登录失败,打印详细错误日志并显示错误信息 + android.util.Log.e("MainActivity", "=== 登录接口请求异常 ==="); + android.util.Log.e("MainActivity", "Error Code: " + errorCode); + android.util.Log.e("MainActivity", "Error Message: " + errorMessage); + android.util.Log.e("MainActivity", "==========================="); + + // 显示Toast错误信息 showToast("登录失败: " + errorMessage); } @@ -207,13 +212,6 @@ public class MainActivity extends AppCompatActivity { // 请求完成 } }); - - // 如果需要保留原来的测试登录逻辑,可以保留下面的代码 - // if (username.equals("admin") && password.equals("123456")) { - // showLoginSuccessDialog(); - // } else { - // showToast("用户名或密码错误"); - // } } /** @@ -467,50 +465,75 @@ public class MainActivity extends AppCompatActivity { loadingAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); spinner.setAdapter(loadingAdapter); - // 调用API获取Pad列表 - NetworkUtils.getPadList(new NetworkCallback() { - @Override - public void onStart() { - // 加载开始 - } + // 调用API获取Pad列表,传入登录时获取的stadium_id、device_id和token + if (currentLoginData != null) { + int stadiumId = currentLoginData.getStadiumId(); + String token = currentLoginData.getToken(); + String deviceId = "ANDROID_" + android.provider.Settings.Secure.getString( + getContentResolver(), android.provider.Settings.Secure.ANDROID_ID); - @Override - public void onSuccess(PadApiService.PadListResponse data) { - // 加载成功,更新下拉框数据 - java.util.List padList = data.getPadList(); - java.util.List padNames = new java.util.ArrayList<>(); - padNames.add("请选择设备"); // 默认选项 + android.util.Log.d("MainActivity", "Loading pad list with stadium_id: " + stadiumId + + ", device_id: " + deviceId + ", token: " + (token != null ? "present" : "null")); + + NetworkUtils.getPadList(stadiumId, deviceId, token, new NetworkCallback() { + @Override + public void onStart() { + // 加载开始 + } - if (padList != null && !padList.isEmpty()) { - for (PadApiService.PadInfo padInfo : padList) { - padNames.add(padInfo.getPadName() + " (" + padInfo.getStatus() + ")"); + @Override + public void onSuccess(PadApiService.PadListResponse data) { + // 加载成功,更新下拉框数据 + java.util.List padList = data.getPadList(); + java.util.List padNames = new java.util.ArrayList<>(); + padNames.add("请选择设备"); // 默认选项 + + if (padList != null && !padList.isEmpty()) { + for (PadApiService.PadInfo padInfo : padList) { + padNames.add(padInfo.getPadName() + " (" + padInfo.getStatus() + ")"); + } + } else { + padNames.add("暂无可用设备"); } - } else { - padNames.add("暂无可用设备"); + + // 更新Spinner数据 + ArrayAdapter adapter = new ArrayAdapter<>(MainActivity.this, + android.R.layout.simple_spinner_item, padNames); + adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); + spinner.setAdapter(adapter); + + // 更新进入按钮的点击事件,传入真实的Pad数据 + updateEnterButtonClickListener(dialog, padList); } - // 更新Spinner数据 - ArrayAdapter adapter = new ArrayAdapter<>(MainActivity.this, - android.R.layout.simple_spinner_item, padNames); - adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); - spinner.setAdapter(adapter); - - // 更新进入按钮的点击事件,传入真实的Pad数据 - updateEnterButtonClickListener(dialog, padList); - } + @Override + public void onError(int errorCode, String errorMessage) { + // 加载失败,打印详细错误日志并显示错误信息 + android.util.Log.e("MainActivity", "=== 获取设备列表接口请求异常 ==="); + android.util.Log.e("MainActivity", "Error Code: " + errorCode); + android.util.Log.e("MainActivity", "Error Message: " + errorMessage); + android.util.Log.e("MainActivity", "================================"); + + // 显示错误信息 + String[] errorItems = {"加载失败,请重试"}; + ArrayAdapter errorAdapter = new ArrayAdapter<>(MainActivity.this, + android.R.layout.simple_spinner_item, errorItems); + errorAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); + spinner.setAdapter(errorAdapter); + + showToast("获取设备列表失败: " + errorMessage); + } + }); + } else { + // 如果没有登录数据,显示错误 + String[] errorItems = {"登录数据丢失,请重新登录"}; + ArrayAdapter errorAdapter = new ArrayAdapter<>(this, + android.R.layout.simple_spinner_item, errorItems); + errorAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); + spinner.setAdapter(errorAdapter); - @Override - public void onError(int errorCode, String errorMessage) { - // 加载失败,显示错误信息 - String[] errorItems = {"加载失败,请重试"}; - ArrayAdapter errorAdapter = new ArrayAdapter<>(MainActivity.this, - android.R.layout.simple_spinner_item, errorItems); - errorAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); - spinner.setAdapter(errorAdapter); - - showToast("获取设备列表失败: " + errorMessage); - } - }); + showToast("登录数据丢失,请重新登录"); + } } /** @@ -530,7 +553,7 @@ public class MainActivity extends AppCompatActivity { showToast("请选择设备"); } else if (padList != null && selectedPosition <= padList.size()) { // 获取选中的Pad信息 - PadApiService.PadInfo selectedPad = padList.get(selectedPosition - 1); // 减1因为第0个是“请选择设备” + PadApiService.PadInfo selectedPad = padList.get(selectedPosition - 1); // 减1因为第0个是"请选择设备" // 调用Pad选择API selectPadAndEnter(dialog, buttonEnter, selectedPad); @@ -574,7 +597,14 @@ public class MainActivity extends AppCompatActivity { @Override public void onError(int errorCode, String errorMessage) { - // 选择失败 + // 选择失败,打印详细错误日志并显示错误信息 + android.util.Log.e("MainActivity", "=== 设备选择接口请求异常 ==="); + android.util.Log.e("MainActivity", "Error Code: " + errorCode); + android.util.Log.e("MainActivity", "Error Message: " + errorMessage); + android.util.Log.e("MainActivity", "Selected Pad: " + (selectedPad != null ? selectedPad.getPadName() : "null")); + android.util.Log.e("MainActivity", "=============================="); + + // 显示错误信息 showToast("选择设备失败: " + errorMessage); // 恢复按钮状态 diff --git a/app/src/main/java/com/ouxuan/oxface/network/NetworkManager.java b/app/src/main/java/com/ouxuan/oxface/network/NetworkManager.java index 044daa8..df63635 100644 --- a/app/src/main/java/com/ouxuan/oxface/network/NetworkManager.java +++ b/app/src/main/java/com/ouxuan/oxface/network/NetworkManager.java @@ -8,6 +8,7 @@ import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.ouxuan.oxface.network.callback.NetworkCallback; import com.ouxuan.oxface.network.interceptor.HeaderInterceptor; +import com.ouxuan.oxface.network.interceptor.NetworkDebugInterceptor; import com.ouxuan.oxface.network.model.ApiResponse; import java.util.concurrent.TimeUnit; @@ -68,6 +69,11 @@ public class NetworkManager { .writeTimeout(NetworkConfig.WRITE_TIMEOUT, TimeUnit.SECONDS) .addInterceptor(new HeaderInterceptor(context)); + // 添加网络调试拦截器(优先级最高,在所有拦截器之前) + if (NetworkConfig.ENABLE_LOG) { + builder.addInterceptor(new NetworkDebugInterceptor()); + } + // 添加日志拦截器(仅在Debug模式下) if (NetworkConfig.ENABLE_LOG) { HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor(); diff --git a/app/src/main/java/com/ouxuan/oxface/network/api/PadApiService.java b/app/src/main/java/com/ouxuan/oxface/network/api/PadApiService.java index c60240c..60a17a5 100644 --- a/app/src/main/java/com/ouxuan/oxface/network/api/PadApiService.java +++ b/app/src/main/java/com/ouxuan/oxface/network/api/PadApiService.java @@ -27,19 +27,30 @@ public interface PadApiService { /** * 获取Pad列表 * 对应旧接口: /v3/pad/list + * @param stadiumId 场馆ID(必需) + * @param deviceId 设备ID(必需) + * @param token 访问令牌(必需) * @return Pad列表响应 */ @GET("v3/pad/list") - Call> padList(); + Call> padList(@Query("stadium_id") int stadiumId, + @Query("device_id") String deviceId, + @Query("token") String token); /** - * 获取Pad列表(带查询参数) + * 获取Pad列表(带额外查询参数) + * @param stadiumId 场馆ID(必需) + * @param deviceId 设备ID(必需) + * @param token 访问令牌(必需) * @param userId 用户ID(可选) * @param status 状态筛选(可选) * @return Pad列表响应 */ @GET("v3/pad/list") - Call> padList(@Query("userId") String userId, + Call> padList(@Query("stadium_id") int stadiumId, + @Query("device_id") String deviceId, + @Query("token") String token, + @Query("userId") String userId, @Query("status") String status); /** diff --git a/app/src/main/java/com/ouxuan/oxface/network/debug/NetworkDebugLogger.java b/app/src/main/java/com/ouxuan/oxface/network/debug/NetworkDebugLogger.java new file mode 100644 index 0000000..c417738 --- /dev/null +++ b/app/src/main/java/com/ouxuan/oxface/network/debug/NetworkDebugLogger.java @@ -0,0 +1,168 @@ +package com.ouxuan.oxface.network.debug; + +import android.util.Log; +import okhttp3.Request; +import okhttp3.Response; +import okhttp3.ResponseBody; +import okio.Buffer; +import java.io.IOException; +import java.net.URLDecoder; + +/** + * 网络请求调试日志工具类 + * 按照指定格式打印请求和响应信息 + */ +public class NetworkDebugLogger { + + private static final String TAG = "jsLog"; + private static final boolean ENABLE_DEBUG = true; // 调试开关 + + /** + * 打印网络请求调试信息 + * @param request 请求对象 + * @param response 响应对象 + * @param responseBody 响应体内容 + * @param tag 请求标识标签,如 [list]、[login] 等 + */ + public static void logNetworkRequest(Request request, Response response, String responseBody, String tag) { + if (!ENABLE_DEBUG) { + return; + } + + try { + // 获取请求URL + String url = request.url().toString(); + + // 获取请求体数据 + String requestData = getRequestDataString(request); + + // 打印请求信息 + Log.e(TAG, "请求 Data: "); + if (requestData != null && !requestData.isEmpty()) { + Log.e(TAG, requestData); + } else { + // 对于GET请求,打印查询参数 + String queryParams = getQueryParametersAsJson(request); + if (queryParams != null && !queryParams.isEmpty()) { + Log.e(TAG, queryParams); + } else { + Log.e(TAG, "{}"); + } + } + + Log.e(TAG, " URL:"); + Log.e(TAG, url); + + // 打印响应信息 + Log.e(TAG, " 服务端返回:"); + if (responseBody != null && !responseBody.isEmpty()) { + Log.e(TAG, responseBody); + } else { + Log.e(TAG, "空响应"); + } + + // 打印结束标识 + Log.e(TAG, " <<-------------------- " + tag + "[log] ↑↑↑"); + + } catch (Exception e) { + Log.e(TAG, "网络调试日志打印失败: " + e.getMessage()); + } + } + + /** + * 获取请求数据(包括请求体和查询参数) + * @param request 请求对象 + * @return 请求数据字符串 + */ + private static String getRequestDataString(Request request) { + try { + // 优先获取请求体内容 + if (request.body() != null) { + Buffer buffer = new Buffer(); + request.body().writeTo(buffer); + String requestBody = buffer.readUtf8(); + if (requestBody != null && !requestBody.trim().isEmpty()) { + return requestBody; + } + } + + // 如果没有请求体,则获取查询参数 + return getQueryParametersAsJson(request); + + } catch (Exception e) { + Log.e(TAG, "获取请求数据失败: " + e.getMessage()); + return "{}"; + } + } + + /** + * 获取查询参数并格式化为JSON样式 + * @param request 请求对象 + * @return 查询参数JSON字符串 + */ + private static String getQueryParametersAsJson(Request request) { + try { + String url = request.url().toString(); + if (url.contains("?")) { + String queryString = url.substring(url.indexOf("?") + 1); + + // 将查询参数格式化为JSON样式 + StringBuilder jsonStyle = new StringBuilder("{"); + String[] params = queryString.split("&"); + + for (int i = 0; i < params.length; i++) { + String[] keyValue = params[i].split("="); + if (keyValue.length == 2) { + String key = URLDecoder.decode(keyValue[0], "UTF-8"); + String value = URLDecoder.decode(keyValue[1], "UTF-8"); + + jsonStyle.append("\"").append(key).append("\":"); + + // 尝试判断是否为数字 + try { + Integer.parseInt(value); + jsonStyle.append(value); + } catch (NumberFormatException e) { + jsonStyle.append("\"").append(value).append("\""); + } + + if (i < params.length - 1) { + jsonStyle.append(","); + } + } + } + jsonStyle.append("}"); + + return jsonStyle.toString(); + } + return "{}"; + } catch (Exception e) { + Log.e(TAG, "获取查询参数失败: " + e.getMessage()); + return "{}"; + } + } + + /** + * 打印简化的网络请求信息(只有基本信息) + * @param method 请求方法 + * @param url 请求URL + * @param responseCode 响应码 + * @param tag 请求标识标签 + */ + public static void logSimpleRequest(String method, String url, int responseCode, String tag) { + if (!ENABLE_DEBUG) { + return; + } + + Log.d(TAG, String.format("%s %s - Response: %d %s", method, url, responseCode, tag)); + } + + /** + * 设置调试开关 + * @param enabled 是否启用调试 + */ + public static void setDebugEnabled(boolean enabled) { + // 这里可以动态控制调试开关 + // 实际项目中可以通过配置文件或BuildConfig控制 + } +} \ No newline at end of file diff --git a/app/src/main/java/com/ouxuan/oxface/network/interceptor/NetworkDebugInterceptor.java b/app/src/main/java/com/ouxuan/oxface/network/interceptor/NetworkDebugInterceptor.java new file mode 100644 index 0000000..4072ffe --- /dev/null +++ b/app/src/main/java/com/ouxuan/oxface/network/interceptor/NetworkDebugInterceptor.java @@ -0,0 +1,66 @@ +package com.ouxuan.oxface.network.interceptor; + +import com.ouxuan.oxface.network.debug.NetworkDebugLogger; +import java.io.IOException; +import okhttp3.Interceptor; +import okhttp3.Request; +import okhttp3.Response; +import okhttp3.ResponseBody; +import okio.Buffer; + +/** + * 网络调试拦截器 + * 自动捕获所有网络请求和响应,使用NetworkDebugLogger打印调试信息 + */ +public class NetworkDebugInterceptor implements Interceptor { + + @Override + public Response intercept(Chain chain) throws IOException { + Request request = chain.request(); + + // 执行请求 + Response response = chain.proceed(request); + + // 获取响应体内容 + String responseBodyString = null; + if (response.body() != null) { + // 读取响应体 + ResponseBody responseBody = response.body(); + Buffer buffer = new Buffer(); + responseBody.source().readAll(buffer); + responseBodyString = buffer.clone().readUtf8(); + + // 重新创建ResponseBody,因为原来的已经被消费了 + ResponseBody newResponseBody = ResponseBody.create( + responseBody.contentType(), + responseBodyString + ); + response = response.newBuilder().body(newResponseBody).build(); + } + + // 根据URL路径确定调试标签 + String debugTag = getDebugTag(request.url().toString()); + + // 打印调试信息 + NetworkDebugLogger.logNetworkRequest(request, response, responseBodyString, debugTag); + + return response; + } + + /** + * 根据请求URL确定调试标签 + * @param url 请求URL + * @return 调试标签 + */ + private String getDebugTag(String url) { + if (url.contains("/v3/pad/login")) { + return "[login]"; + } else if (url.contains("/v3/pad/list")) { + return "[list]"; + } else if (url.contains("/v3/pad/select")) { + return "[select]"; + } else { + return "[unknown]"; + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/ouxuan/oxface/network/utils/NetworkUtils.java b/app/src/main/java/com/ouxuan/oxface/network/utils/NetworkUtils.java index 7f9ee3f..f9a6942 100644 --- a/app/src/main/java/com/ouxuan/oxface/network/utils/NetworkUtils.java +++ b/app/src/main/java/com/ouxuan/oxface/network/utils/NetworkUtils.java @@ -226,6 +226,20 @@ public class NetworkUtils { return networkManager; } + /** + * 打印API错误日志(当code != 0时) + * @param apiName API名称 + * @param errorCode 错误代码 + * @param errorMessage 错误消息 + */ + private static void logApiError(String apiName, int errorCode, String errorMessage) { + android.util.Log.e("NetworkUtils", "===== API请求异常 ====="); + android.util.Log.e("NetworkUtils", "API Name: " + apiName); + android.util.Log.e("NetworkUtils", "Error Code: " + errorCode + " (code != 0 表示请求异常)"); + android.util.Log.e("NetworkUtils", "Error Message: " + errorMessage); + android.util.Log.e("NetworkUtils", "============================="); + } + // ==================== Pad相关API调用方法 ==================== /** @@ -263,6 +277,8 @@ public class NetworkUtils { android.util.Log.d("NetworkUtils", "Calling onSuccess with data: " + apiResponse.getData()); callback.onSuccess(apiResponse.getData()); } else { + // 打印详细的错误日志 + logApiError("PadLogin", apiResponse.getCode(), apiResponse.getMessage()); android.util.Log.d("NetworkUtils", "Calling onError - Code: " + apiResponse.getCode() + ", Message: " + apiResponse.getMessage()); callback.onError(apiResponse.getCode(), apiResponse.getMessage()); } @@ -287,16 +303,20 @@ public class NetworkUtils { /** * 获取Pad列表 + * @param stadiumId 场馆ID(必需) + * @param deviceId 设备ID(必需) + * @param token 访问令牌(必需) * @param callback 回调接口 */ - public static void getPadList(NetworkCallback callback) { + public static void getPadList(int stadiumId, String deviceId, String token, + NetworkCallback callback) { if (padApiService == null) { callback.onError(-1, "NetworkUtils未初始化,请先调用init()方法"); return; } callback.onStart(); - padApiService.padList().enqueue(new Callback>() { + padApiService.padList(stadiumId, deviceId, token).enqueue(new Callback>() { @Override public void onResponse(Call> call, Response> response) { @@ -307,6 +327,8 @@ public class NetworkUtils { if (apiResponse.isSuccess()) { callback.onSuccess(apiResponse.getData()); } else { + // 打印详细的错误日志 + logApiError("getPadList", apiResponse.getCode(), apiResponse.getMessage()); callback.onError(apiResponse.getCode(), apiResponse.getMessage()); } } else { @@ -328,12 +350,15 @@ public class NetworkUtils { } /** - * 获取Pad列表(带查询参数) - * @param userId 用户ID - * @param status 状态筛选 + * 获取Pad列表(带额外查询参数) + * @param stadiumId 场馆ID(必需) + * @param deviceId 设备ID(必需) + * @param token 访问令牌(必需) + * @param userId 用户ID(可选) + * @param status 状态筛选(可选) * @param callback 回调接口 */ - public static void getPadList(String userId, String status, + public static void getPadList(int stadiumId, String deviceId, String token, String userId, String status, NetworkCallback callback) { if (padApiService == null) { callback.onError(-1, "NetworkUtils未初始化,请先调用init()方法"); @@ -341,7 +366,7 @@ public class NetworkUtils { } callback.onStart(); - padApiService.padList(userId, status).enqueue(new Callback>() { + padApiService.padList(stadiumId, deviceId, token, userId, status).enqueue(new Callback>() { @Override public void onResponse(Call> call, Response> response) { @@ -352,6 +377,8 @@ public class NetworkUtils { if (apiResponse.isSuccess()) { callback.onSuccess(apiResponse.getData()); } else { + // 打印详细的错误日志 + logApiError("getPadList(带参数)", apiResponse.getCode(), apiResponse.getMessage()); callback.onError(apiResponse.getCode(), apiResponse.getMessage()); } } else { @@ -400,6 +427,8 @@ public class NetworkUtils { if (apiResponse.isSuccess()) { callback.onSuccess(apiResponse.getData()); } else { + // 打印详细的错误日志 + logApiError("selectPad", apiResponse.getCode(), apiResponse.getMessage()); callback.onError(apiResponse.getCode(), apiResponse.getMessage()); } } else { diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index f4a3347..d742338 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-9.0-bin.zip +distributionUrl=https\://mirrors.cloud.tencent.com/gradle/gradle-9.0-bin.zip + zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists \ No newline at end of file