屏蔽ptt

This commit is contained in:
fengge 2026-04-19 14:02:11 +08:00
parent 2eaba957d0
commit 0e5883d0de
2 changed files with 61 additions and 31 deletions

View File

@ -13,21 +13,20 @@ class MyApplication : Application() {
}
override fun onCreate() {
// 第一步:先初始化日志,哪怕后面的代码崩了,这里的初始化也完成了
LogManager.init(this)
super.onCreate()
instance = this
// Initialize Timber and File Logging
LogManager.init(this)
try {
// Initialize PTT Module
PTTMyApplication.init(this)
Timber.tag("MyApplication").i("PTT Module init sequence finished")
} catch (e: Throwable) {
// Catch UnsatisfiedLinkError or other PTT init failures
Timber.tag("MyApplication").e(e, "PTT Module failed to start (Expected on non-ARM simulators)")
}
Timber.tag("MyApplication").i("Application onCreate - Logging system ready")
Timber.tag("MyApplication").i("=== Application Starting ===")
// try {
// // 第二步:异步或保护性初始化 PTT
// PTTMyApplication.init(this)
// Timber.tag("MyApplication").i("PTT Module init sequence finished")
// } catch (e: Throwable) {
// Timber.tag("MyApplication").e(e, "PTT Module CRASH during init")
// }
}
}

View File

@ -6,28 +6,65 @@ import okhttp3.*
import okhttp3.MediaType.Companion.toMediaTypeOrNull
import okhttp3.RequestBody.Companion.asRequestBody
import timber.log.Timber
import java.io.File
import java.io.FileInputStream
import java.io.FileOutputStream
import java.io.FileWriter
import java.io.IOException
import java.io.*
import java.text.SimpleDateFormat
import java.util.*
import java.util.concurrent.Executors
import java.util.zip.ZipEntry
import java.util.zip.ZipOutputStream
import kotlin.system.exitProcess
object LogManager {
private val executor = Executors.newSingleThreadExecutor()
private const val MAX_DAYS = 15
private val client = OkHttpClient()
private var logDir: File? = null
fun init(context: Context) {
Timber.plant(Timber.DebugTree())
val logDir = File(context.getExternalFilesDir(null), "logs")
if (!logDir.exists()) logDir.mkdirs()
cleanOldLogs(logDir)
Timber.plant(FileLoggingTree(logDir))
try {
logDir = File(context.getExternalFilesDir(null), "logs")
if (logDir?.exists() == false) logDir?.mkdirs()
// 立即清理旧日志
logDir?.let { cleanOldLogs(it) }
// 挂载文件日志树
logDir?.let { Timber.plant(FileLoggingTree(it)) }
// 【核心增强】接管全局异常,确保崩溃信息能写进文件
setupCrashHandler()
Timber.tag("LogManager").i("Logging system initialized and CrashHandler attached")
} catch (e: Exception) {
android.util.Log.e("LogManager", "Init failed", e)
}
}
private fun setupCrashHandler() {
val defaultHandler = Thread.getDefaultUncaughtExceptionHandler()
Thread.setDefaultUncaughtExceptionHandler { thread, throwable ->
// 强制同步写入崩溃日志
val timestamp = SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS", Locale.getDefault()).format(Date())
val crashInfo = "\n\n=== FATAL CRASH ===\n" +
"Time: $timestamp\n" +
"Thread: ${thread.name}\n" +
"Stacktrace:\n${throwable.stackTraceToString()}\n" +
"====================\n\n"
logDir?.let { dir ->
val logFile = File(dir, SimpleDateFormat("yyyy-MM-dd", Locale.getDefault()).format(Date()) + ".log")
try {
FileOutputStream(logFile, true).use { it.write(crashInfo.toByteArray()) }
} catch (e: Exception) {
android.util.Log.e("LogManager", "Failed to write crash log", e)
}
}
// 交还给系统处理(弹出“应用已停止”对话框)
defaultHandler?.uncaughtException(thread, throwable) ?: exitProcess(1)
}
}
private fun cleanOldLogs(logDir: File) {
@ -46,12 +83,12 @@ object LogManager {
}
fun zipLogs(context: Context): String? {
val logDir = File(context.getExternalFilesDir(null), "logs")
if (!logDir.exists() || logDir.listFiles().isNullOrEmpty()) return null
val dir = logDir ?: return null
if (!dir.exists() || dir.listFiles().isNullOrEmpty()) return null
val zipFile = File(context.getExternalFilesDir(null), "logs_${System.currentTimeMillis()}.zip")
return try {
ZipOutputStream(FileOutputStream(zipFile)).use { zos ->
logDir.listFiles()?.forEach { file ->
dir.listFiles()?.forEach { file ->
if (file.isFile && file.name.endsWith(".log")) {
zos.putNextEntry(ZipEntry(file.name))
FileInputStream(file).use { it.copyTo(zos) }
@ -66,9 +103,6 @@ object LogManager {
}
}
/**
* 上传日志到服务器
*/
fun uploadLogs(context: Context, callback: (Boolean, String) -> Unit) {
executor.execute {
val zipPath = zipLogs(context)
@ -80,8 +114,6 @@ object LogManager {
val file = File(zipPath)
val serverUrl = AppConfig.getServerUrl(context)
val uploadUrl = "$serverUrl/api/attachment/upload"
// 使用固定的 Token (根据用户提供)
val bearerToken = "eyJraWQiOiJzLXYxIiwidHlwIjoiSldUIiwiYWxnIjoiSFMyNTYifQ.eyJzdWIiOiJhZG1pbiIsInR5cCI6ImFjY2VzcyIsImV4cCI6MTc3NjQ5MDczNSwianRpIjoiMjYzNjljYzQtYzJiMy00YTg0LWFiYTMtZDU4NmNiZDRmMmM0IiwiZmdwIjoiY2FhNzYzOTI4YWRhYWZiYjgzMjE3NjExYmVjYTc3ZjMiLCJraWQiOiJzLXYxIn0.AyuzNAe-R_GOBC65STH5qpHkmmUngX8rMBPI4CdIIhk"
val requestBody = MultipartBody.Builder()
@ -99,7 +131,6 @@ object LogManager {
client.newCall(request).execute().use { response ->
if (response.isSuccessful) {
callback(true, "上传成功")
// 上传成功后删除临时 zip 文件
file.delete()
} else {
callback(false, "服务器返回错误: ${response.code}")