pull/1776/head
kunfei 2 years ago
parent 8cad8fe230
commit 2a2e319b6f
  1. 18
      app/src/main/java/io/legado/app/help/ContentProcessor.kt
  2. 107
      app/src/main/java/io/legado/app/help/CrashHandler.kt
  3. 2
      app/src/main/java/io/legado/app/utils/ContextExtensions.kt
  4. 35
      app/src/main/java/io/legado/app/utils/RegexExtensions.kt

@ -8,6 +8,9 @@ import io.legado.app.data.entities.BookChapter
import io.legado.app.data.entities.ReplaceRule import io.legado.app.data.entities.ReplaceRule
import io.legado.app.help.config.AppConfig import io.legado.app.help.config.AppConfig
import io.legado.app.help.config.ReadBookConfig import io.legado.app.help.config.ReadBookConfig
import io.legado.app.utils.RegexTimeoutException
import io.legado.app.utils.msg
import io.legado.app.utils.replace
import io.legado.app.utils.toastOnUi import io.legado.app.utils.toastOnUi
import splitties.init.appCtx import splitties.init.appCtx
import java.lang.ref.WeakReference import java.lang.ref.WeakReference
@ -134,13 +137,22 @@ class ContentProcessor private constructor(
if (item.pattern.isNotEmpty()) { if (item.pattern.isNotEmpty()) {
kotlin.runCatching { kotlin.runCatching {
mContent = if (item.isRegex) { mContent = if (item.isRegex) {
mContent.replace(item.pattern.toRegex(), item.replacement) mContent.replace(item.pattern.toRegex(), item.replacement, 1000L)
} else { } else {
mContent.replace(item.pattern, item.replacement) mContent.replace(item.pattern, item.replacement)
} }
}.onFailure { }.onFailure {
AppLog.put("${item.name}替换出错\n${it.localizedMessage}", it) when (it) {
appCtx.toastOnUi("${item.name}替换出错") is RegexTimeoutException -> {
item.isEnabled = false
appDb.replaceRuleDao.update(item)
return it.msg
}
else -> {
AppLog.put("${item.name}替换出错\n${it.localizedMessage}", it)
appCtx.toastOnUi("${item.name}替换出错")
}
}
} }
} }
} }

@ -9,6 +9,7 @@ import io.legado.app.utils.FileUtils
import io.legado.app.utils.getFile import io.legado.app.utils.getFile
import io.legado.app.utils.longToastOnUi import io.legado.app.utils.longToastOnUi
import io.legado.app.utils.msg import io.legado.app.utils.msg
import splitties.init.appCtx
import java.io.PrintWriter import java.io.PrintWriter
import java.io.StringWriter import java.io.StringWriter
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
@ -26,17 +27,6 @@ class CrashHandler(val context: Context) : Thread.UncaughtExceptionHandler {
*/ */
private var mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler() private var mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler()
/**
* 存储异常和参数信息
*/
private val paramsMap = HashMap<String, String>()
/**
* 格式化时间
*/
@SuppressLint("SimpleDateFormat")
private val format = SimpleDateFormat("yyyy-MM-dd-HH-mm-ss")
init { init {
//设置该CrashHandler为系统默认的 //设置该CrashHandler为系统默认的
Thread.setDefaultUncaughtExceptionHandler(this) Thread.setDefaultUncaughtExceptionHandler(this)
@ -56,62 +46,71 @@ class CrashHandler(val context: Context) : Thread.UncaughtExceptionHandler {
*/ */
private fun handleException(ex: Throwable?) { private fun handleException(ex: Throwable?) {
if (ex == null) return if (ex == null) return
//收集设备参数信息
collectDeviceInfo()
//保存日志文件 //保存日志文件
saveCrashInfo2File(ex) saveCrashInfo2File(ex)
context.longToastOnUi(ex.msg) context.longToastOnUi(ex.msg)
Thread.sleep(3000) Thread.sleep(3000)
} }
/** companion object {
* 收集设备参数信息 /**
*/ * 存储异常和参数信息
private fun collectDeviceInfo() { */
kotlin.runCatching { private val paramsMap by lazy {
//获取系统信息 val map = HashMap<String, String>()
paramsMap["MANUFACTURER"] = Build.MANUFACTURER kotlin.runCatching {
paramsMap["BRAND"] = Build.BRAND //获取系统信息
//获取app版本信息 map["MANUFACTURER"] = Build.MANUFACTURER
AppConst.appInfo.let { map["BRAND"] = Build.BRAND
paramsMap["versionName"] = it.versionName //获取app版本信息
paramsMap["versionCode"] = it.versionCode.toString() AppConst.appInfo.let {
map["versionName"] = it.versionName
map["versionCode"] = it.versionCode.toString()
}
} }
map
} }
}
/** /**
* 保存错误信息到文件中 * 格式化时间
*/ */
private fun saveCrashInfo2File(ex: Throwable) { @SuppressLint("SimpleDateFormat")
val sb = StringBuilder() private val format = SimpleDateFormat("yyyy-MM-dd-HH-mm-ss")
for ((key, value) in paramsMap) {
sb.append(key).append("=").append(value).append("\n")
}
val writer = StringWriter() /**
val printWriter = PrintWriter(writer) * 保存错误信息到文件中
ex.printStackTrace(printWriter) */
var cause: Throwable? = ex.cause fun saveCrashInfo2File(ex: Throwable) {
while (cause != null) { val sb = StringBuilder()
cause.printStackTrace(printWriter) for ((key, value) in paramsMap) {
cause = cause.cause sb.append(key).append("=").append(value).append("\n")
} }
printWriter.close()
val result = writer.toString() val writer = StringWriter()
sb.append(result) val printWriter = PrintWriter(writer)
val timestamp = System.currentTimeMillis() ex.printStackTrace(printWriter)
val time = format.format(Date()) var cause: Throwable? = ex.cause
val fileName = "crash-$time-$timestamp.log" while (cause != null) {
context.externalCacheDir?.let { rootFile -> cause.printStackTrace(printWriter)
rootFile.getFile("crash").listFiles()?.forEach { cause = cause.cause
if (it.lastModified() < System.currentTimeMillis() - TimeUnit.DAYS.toMillis(7)) { }
it.delete() printWriter.close()
val result = writer.toString()
sb.append(result)
val timestamp = System.currentTimeMillis()
val time = format.format(Date())
val fileName = "crash-$time-$timestamp.log"
appCtx.externalCacheDir?.let { rootFile ->
rootFile.getFile("crash").listFiles()?.forEach {
if (it.lastModified() < System.currentTimeMillis() - TimeUnit.DAYS.toMillis(7)) {
it.delete()
}
} }
FileUtils.createFileIfNotExist(rootFile, "crash", fileName)
.writeText(sb.toString())
} }
FileUtils.createFileIfNotExist(rootFile, "crash", fileName)
.writeText(sb.toString())
} }
} }
} }

@ -33,6 +33,7 @@ import splitties.systemservices.clipboardManager
import splitties.systemservices.connectivityManager import splitties.systemservices.connectivityManager
import java.io.File import java.io.File
import java.io.FileOutputStream import java.io.FileOutputStream
import kotlin.system.exitProcess
inline fun <reified A : Activity> Context.startActivity(configIntent: Intent.() -> Unit = {}) { inline fun <reified A : Activity> Context.startActivity(configIntent: Intent.() -> Unit = {}) {
val intent = Intent(this, A::class.java) val intent = Intent(this, A::class.java)
@ -168,6 +169,7 @@ fun Context.restart() {
startActivity(intent) startActivity(intent)
//杀掉以前进程 //杀掉以前进程
Process.killProcess(Process.myPid()) Process.killProcess(Process.myPid())
exitProcess(0)
} }
} }

@ -1,10 +1,37 @@
package io.legado.app.utils package io.legado.app.utils
import io.legado.app.exception.NoStackTraceException
import io.legado.app.help.CrashHandler
import kotlinx.coroutines.suspendCancellableCoroutine import kotlinx.coroutines.suspendCancellableCoroutine
import splitties.init.appCtx
import kotlin.concurrent.thread
import kotlin.coroutines.resume
suspend fun CharSequence.regexReplace(regex: String, replacement: String, timeout: Long): String { suspend fun CharSequence.replace(regex: Regex, replacement: String, timeout: Long): String {
return suspendCancellableCoroutine { return suspendCancellableCoroutine { block ->
val thread = thread {
try {
val result = regex.replace(this, replacement)
block.resume(result)
} catch (e: Exception) {
block.cancel(e)
}
}
mainHandler.postDelayed({
if (thread.isAlive) {
val timeoutMsg = "替换超时,将在3秒后重启应用\n替换规则$regex\n替换内容:${this}"
val exception = RegexTimeoutException(timeoutMsg)
block.cancel(exception)
appCtx.longToastOnUi(timeoutMsg)
CrashHandler.saveCrashInfo2File(exception)
mainHandler.postDelayed({
if (thread.isAlive) {
appCtx.restart()
}
}, 3000)
}
}, timeout)
} }
} }
class RegexTimeoutException(msg: String) : NoStackTraceException(msg)
Loading…
Cancel
Save