1.发布新包
This commit is contained in:
@@ -260,8 +260,7 @@
|
|||||||
android:id="@+id/iv_login_bg"
|
android:id="@+id/iv_login_bg"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="@dimen/dp_42"
|
android:layout_height="@dimen/dp_42"
|
||||||
android:src="@drawable/theme_bg"
|
android:src="@drawable/theme_bg" />
|
||||||
/>
|
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ isBuildModule=false
|
|||||||
android.injected.testOnly=false
|
android.injected.testOnly=false
|
||||||
|
|
||||||
APP_VERSION_NAME=1.2.7
|
APP_VERSION_NAME=1.2.7
|
||||||
APP_VERSION_CODE=180
|
APP_VERSION_CODE=181
|
||||||
|
|
||||||
org.gradle.jvm.toolchain.useLegacyAdapters=false
|
org.gradle.jvm.toolchain.useLegacyAdapters=false
|
||||||
#org.gradle.java.home=C\:\\Users\\qx\\.jdks\\ms-17.0.15
|
#org.gradle.java.home=C\:\\Users\\qx\\.jdks\\ms-17.0.15
|
||||||
|
|||||||
@@ -108,7 +108,7 @@ public class RetrofitClient {
|
|||||||
sslContext.init(null, new TrustManager[]{trustAllCert}, new SecureRandom());
|
sslContext.init(null, new TrustManager[]{trustAllCert}, new SecureRandom());
|
||||||
|
|
||||||
final OkHttpClient client = new OkHttpClient.Builder()
|
final OkHttpClient client = new OkHttpClient.Builder()
|
||||||
// .addInterceptor(new LoggerInterceptor("HttpLog", true))
|
// .addInterceptor(new LogInterceptor())
|
||||||
.addInterceptor(new DataLoggingInterceptor(new DataLogger()))
|
.addInterceptor(new DataLoggingInterceptor(new DataLogger()))
|
||||||
.addInterceptor(new AccessTokenInterceptor(headers))
|
.addInterceptor(new AccessTokenInterceptor(headers))
|
||||||
.proxy(Proxy.NO_PROXY)
|
.proxy(Proxy.NO_PROXY)
|
||||||
|
|||||||
@@ -867,7 +867,7 @@ public class AgoraManager {
|
|||||||
VD_360x360,
|
VD_360x360,
|
||||||
FRAME_RATE_FPS_15,
|
FRAME_RATE_FPS_15,
|
||||||
STANDARD_BITRATE,
|
STANDARD_BITRATE,
|
||||||
ORIENTATION_MODE_FIXED_PORTRAIT
|
ORIENTATION_MODE_ADAPTIVE
|
||||||
));
|
));
|
||||||
rtcEngine.startScreenCapture(screenCaptureParameters);
|
rtcEngine.startScreenCapture(screenCaptureParameters);
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,276 @@
|
|||||||
|
package com.xscm.moduleutil.utils.logger;
|
||||||
|
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.charset.Charset;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
import okhttp3.Interceptor;
|
||||||
|
import okhttp3.MediaType;
|
||||||
|
import okhttp3.Request;
|
||||||
|
import okhttp3.RequestBody;
|
||||||
|
import okhttp3.Response;
|
||||||
|
import okhttp3.ResponseBody;
|
||||||
|
import okhttp3.internal.http.HttpHeaders;
|
||||||
|
import okio.Buffer;
|
||||||
|
import okio.BufferedSource;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* OkHttp 日志拦截器,用于打印请求和响应详情
|
||||||
|
*/
|
||||||
|
public class LogInterceptor implements Interceptor {
|
||||||
|
private static final String TAG = "NetworkLog";
|
||||||
|
private static final Charset UTF8 = StandardCharsets.UTF_8;
|
||||||
|
|
||||||
|
// 日志开关(可根据debug/release环境动态设置)
|
||||||
|
private boolean isLogEnabled = true;
|
||||||
|
// 是否打印请求体
|
||||||
|
private boolean logRequestBody = true;
|
||||||
|
// 是否打印响应体
|
||||||
|
|
||||||
|
private boolean logResponseBody = true;
|
||||||
|
// 最大日志长度(避免过大的响应体导致日志刷屏)
|
||||||
|
private int maxLogLength = 2048;
|
||||||
|
|
||||||
|
public LogInterceptor() {
|
||||||
|
}
|
||||||
|
|
||||||
|
// 配置方法
|
||||||
|
public LogInterceptor setLogEnabled(boolean enabled) {
|
||||||
|
isLogEnabled = enabled;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LogInterceptor setLogRequestBody(boolean logRequestBody) {
|
||||||
|
this.logRequestBody = logRequestBody;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LogInterceptor setLogResponseBody(boolean logResponseBody) {
|
||||||
|
this.logResponseBody = logResponseBody;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LogInterceptor setMaxLogLength(int maxLogLength) {
|
||||||
|
this.maxLogLength = maxLogLength;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@Override
|
||||||
|
public Response intercept(@NonNull Chain chain) throws IOException {
|
||||||
|
if (!isLogEnabled) {
|
||||||
|
return chain.proceed(chain.request());
|
||||||
|
}
|
||||||
|
|
||||||
|
Request request = chain.request();
|
||||||
|
// 打印请求日志
|
||||||
|
logRequest(request);
|
||||||
|
|
||||||
|
// 记录请求开始时间,用于计算耗时
|
||||||
|
long startNs = System.nanoTime();
|
||||||
|
Response response;
|
||||||
|
try {
|
||||||
|
response = chain.proceed(request);
|
||||||
|
} catch (Exception e) {
|
||||||
|
// 打印请求异常
|
||||||
|
Log.e(TAG, "请求失败: " + e.getMessage());
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
// 计算请求耗时
|
||||||
|
long tookMs = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startNs);
|
||||||
|
|
||||||
|
// 打印响应日志
|
||||||
|
logResponse(response, tookMs);
|
||||||
|
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 打印请求日志
|
||||||
|
*/
|
||||||
|
private void logRequest(Request request) {
|
||||||
|
try {
|
||||||
|
StringBuilder log = new StringBuilder();
|
||||||
|
log.append("\n==================== 请求开始 ====================\n");
|
||||||
|
|
||||||
|
// 请求行: 方法 + URL
|
||||||
|
log.append(String.format("方法: %s URL: %s\n", request.method(), request.url()));
|
||||||
|
|
||||||
|
// 请求头
|
||||||
|
log.append("请求头:\n");
|
||||||
|
for (String name : request.headers().names()) {
|
||||||
|
// 脱敏敏感头信息(如Authorization、Cookie等)
|
||||||
|
String value = isSensitiveHeader(name) ? "***" : request.headers().get(name);
|
||||||
|
log.append(String.format(" %s: %s\n", name, value));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 请求体
|
||||||
|
if (logRequestBody && request.body() != null) {
|
||||||
|
RequestBody requestBody = request.body();
|
||||||
|
if (requestBody.contentLength() > 0) {
|
||||||
|
log.append("请求体:\n");
|
||||||
|
|
||||||
|
// 复制请求体(避免原请求体被消耗)
|
||||||
|
Buffer buffer = new Buffer();
|
||||||
|
requestBody.writeTo(buffer);
|
||||||
|
Charset charset = UTF8;
|
||||||
|
MediaType contentType = requestBody.contentType();
|
||||||
|
if (contentType != null) {
|
||||||
|
charset = contentType.charset(UTF8);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 读取请求体内容
|
||||||
|
String body = buffer.readString(charset);
|
||||||
|
// 格式化JSON(如果是JSON类型)
|
||||||
|
if (isJson(contentType)) {
|
||||||
|
body = formatJson(body);
|
||||||
|
}
|
||||||
|
// 截断过长的日志
|
||||||
|
log.append(truncateLog(body)).append("\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
log.append("==================== 请求结束 ====================\n");
|
||||||
|
Log.d(TAG, log.toString());
|
||||||
|
} catch (Exception e) {
|
||||||
|
Log.e(TAG, "打印请求日志失败: " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 打印响应日志
|
||||||
|
*/
|
||||||
|
private void logResponse(Response response, long tookMs) {
|
||||||
|
try {
|
||||||
|
StringBuilder log = new StringBuilder();
|
||||||
|
log.append("\n==================== 响应开始 ====================\n");
|
||||||
|
|
||||||
|
// 响应行: 状态码 + 消息 + 耗时
|
||||||
|
log.append(String.format("状态码: %d 消息: %s 耗时: %dms\n",
|
||||||
|
response.code(), response.message(), tookMs));
|
||||||
|
|
||||||
|
// 响应头
|
||||||
|
log.append("响应头:\n");
|
||||||
|
for (String name : response.headers().names()) {
|
||||||
|
log.append(String.format(" %s: %s\n", name, response.headers().get(name)));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 响应体
|
||||||
|
if (logResponseBody && HttpHeaders.hasBody(response)) {
|
||||||
|
ResponseBody responseBody = response.body();
|
||||||
|
if (responseBody != null) {
|
||||||
|
BufferedSource source = responseBody.source();
|
||||||
|
source.request(Long.MAX_VALUE); // 读取整个响应体
|
||||||
|
Buffer buffer = source.buffer();
|
||||||
|
|
||||||
|
Charset charset = UTF8;
|
||||||
|
MediaType contentType = responseBody.contentType();
|
||||||
|
if (contentType != null) {
|
||||||
|
charset = contentType.charset(UTF8);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 读取响应体内容
|
||||||
|
String body = buffer.clone().readString(charset);
|
||||||
|
// 格式化JSON
|
||||||
|
if (isJson(contentType)) {
|
||||||
|
body = formatJson(body);
|
||||||
|
}
|
||||||
|
// 截断过长的日志
|
||||||
|
log.append("响应体:\n").append(truncateLog(body)).append("\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
log.append("==================== 响应结束 ====================\n");
|
||||||
|
Log.d(TAG, log.toString());
|
||||||
|
} catch (Exception e) {
|
||||||
|
Log.e(TAG, "打印响应日志失败: " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断是否为JSON类型
|
||||||
|
*/
|
||||||
|
private boolean isJson(MediaType mediaType) {
|
||||||
|
if (mediaType == null) return false;
|
||||||
|
return mediaType.type().equals("application") &&
|
||||||
|
mediaType.subtype().equals("json");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 格式化JSON字符串(增强可读性)
|
||||||
|
*/
|
||||||
|
private String formatJson(String json) {
|
||||||
|
try {
|
||||||
|
// 简单格式化(可根据需要使用更复杂的JSON格式化库)
|
||||||
|
StringBuilder formatted = new StringBuilder();
|
||||||
|
int indent = 0;
|
||||||
|
boolean inQuotes = false;
|
||||||
|
char lastChar = ' ';
|
||||||
|
|
||||||
|
for (char c : json.toCharArray()) {
|
||||||
|
if (c == '"' && lastChar != '\\') {
|
||||||
|
inQuotes = !inQuotes;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!inQuotes) {
|
||||||
|
switch (c) {
|
||||||
|
case '{':
|
||||||
|
case '[':
|
||||||
|
formatted.append(c).append("\n");
|
||||||
|
indent += 4;
|
||||||
|
formatted.append(" ".repeat(indent));
|
||||||
|
break;
|
||||||
|
case '}':
|
||||||
|
case ']':
|
||||||
|
formatted.append("\n");
|
||||||
|
indent -= 4;
|
||||||
|
formatted.append(" ".repeat(indent)).append(c);
|
||||||
|
break;
|
||||||
|
case ',':
|
||||||
|
formatted.append(c).append("\n").append(" ".repeat(indent));
|
||||||
|
break;
|
||||||
|
case ':':
|
||||||
|
formatted.append(" : ");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
formatted.append(c);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
formatted.append(c);
|
||||||
|
}
|
||||||
|
lastChar = c;
|
||||||
|
}
|
||||||
|
return formatted.toString();
|
||||||
|
} catch (Exception e) {
|
||||||
|
// 格式化失败时返回原始字符串
|
||||||
|
return json;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 截断过长的日志
|
||||||
|
*/
|
||||||
|
private String truncateLog(String log) {
|
||||||
|
if (log.length() <= maxLogLength) {
|
||||||
|
return log;
|
||||||
|
}
|
||||||
|
return log.substring(0, maxLogLength) + "\n...[日志过长,已截断]...";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断是否为敏感头信息(需要脱敏)
|
||||||
|
*/
|
||||||
|
private boolean isSensitiveHeader(String headerName) {
|
||||||
|
String lowerHeader = headerName.toLowerCase();
|
||||||
|
return lowerHeader.contains("authorization") ||
|
||||||
|
lowerHeader.contains("cookie") ||
|
||||||
|
lowerHeader.contains("token") ||
|
||||||
|
lowerHeader.contains("secret");
|
||||||
|
}
|
||||||
|
}
|
||||||
Binary file not shown.
|
Before Width: | Height: | Size: 55 KiB |
@@ -173,6 +173,7 @@
|
|||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/tv_relation"
|
android:id="@+id/tv_relation"
|
||||||
|
android:gravity="center"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="@dimen/dp_18"
|
android:layout_height="@dimen/dp_18"
|
||||||
android:layout_marginTop="@dimen/dp_1"
|
android:layout_marginTop="@dimen/dp_1"
|
||||||
@@ -198,6 +199,7 @@
|
|||||||
app:layout_constraintTop_toTopOf="parent" />
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
|
android:gravity="center"
|
||||||
android:id="@+id/tv_gift"
|
android:id="@+id/tv_gift"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="@dimen/dp_18"
|
android:layout_height="@dimen/dp_18"
|
||||||
@@ -223,6 +225,7 @@
|
|||||||
app:layout_constraintTop_toTopOf="parent" />
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
|
|
||||||
android:id="@+id/tv_timetg"
|
android:id="@+id/tv_timetg"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="@dimen/dp_18"
|
android:layout_height="@dimen/dp_18"
|
||||||
|
|||||||
Reference in New Issue
Block a user