Added crossTime and dateTime in AppErrorsInfoBean

This commit is contained in:
2022-06-01 04:04:27 +08:00
parent cf7de4e131
commit 02d5cf2141
12 changed files with 167 additions and 30 deletions

View File

@@ -21,7 +21,10 @@
*/
package com.fankes.apperrorstracking.bean
import android.app.ApplicationErrorReport
import android.os.Build
import com.fankes.apperrorstracking.locale.LocaleString
import com.fankes.apperrorstracking.utils.factory.difference
import java.io.Serializable
import java.text.SimpleDateFormat
import java.util.*
@@ -52,11 +55,56 @@ data class AppErrorsInfoBean(
var timestamp: Long,
) : Serializable {
companion object {
/**
* 从 [ApplicationErrorReport.CrashInfo] 克隆
* @param packageName APP 包名
* @param crashInfo [ApplicationErrorReport.CrashInfo]
* @return [AppErrorsInfoBean]
*/
fun clone(packageName: String?, crashInfo: ApplicationErrorReport.CrashInfo?) =
(crashInfo?.exceptionClassName?.lowercase() == "native crash").let { isNativeCrash ->
AppErrorsInfoBean(
packageName = packageName ?: "null",
isNativeCrash = isNativeCrash,
exceptionClassName = crashInfo?.exceptionClassName ?: "null",
exceptionMessage = if (isNativeCrash) crashInfo?.stackTrace.let {
if (it?.contains(other = "Abort message: '") == true)
runCatching { it.split("Abort message: '")[1].split("'")[0] }.getOrNull()
?: crashInfo?.exceptionMessage ?: "null"
else crashInfo?.exceptionMessage ?: "null"
} else crashInfo?.exceptionMessage ?: "null",
throwFileName = crashInfo?.throwFileName ?: "null",
throwClassName = crashInfo?.throwClassName ?: "null",
throwMethodName = crashInfo?.throwMethodName ?: "null",
throwLineNumber = crashInfo?.throwLineNumber ?: -1,
stackTrace = crashInfo?.stackTrace?.trim() ?: "null",
timestamp = System.currentTimeMillis()
)
}
}
/**
* 获取异常本地化时间
* 获取异常本地化经过时间
* @return [String]
*/
val time get() = SimpleDateFormat.getDateTimeInstance().format(Date(timestamp)) ?: ""
val crossTime
get() = timestamp.difference(
now = LocaleString.momentAgo,
second = LocaleString.secondAgo,
minute = LocaleString.minuteAgo,
hour = LocaleString.hourAgo,
day = LocaleString.dayAgo,
month = LocaleString.monthAgo,
year = LocaleString.yearAgo
)
/**
* 获取异常本地化量化时间
* @return [String]
*/
val dateTime get() = SimpleDateFormat.getDateTimeInstance().format(Date(timestamp)) ?: "DateTime not found"
/**
* 获取异常堆栈模板
@@ -74,7 +122,7 @@ data class AppErrorsInfoBean(
"[API Version]: ${Build.VERSION.SDK_INT}\n" +
"[Package Name]: $packageName\n" +
"[Error Type]: ${if (isNativeCrash) "Native" else "Jvm"}\n" +
"[Crash Time]: $time\n" +
"[Crash Time]: $dateTime\n" +
"[Stack Trace]:\n" +
stackTrace
}

View File

@@ -23,7 +23,6 @@
package com.fankes.apperrorstracking.hook.entity
import android.app.ApplicationErrorReport
import android.content.Context
import android.content.Intent
import android.content.pm.ApplicationInfo
@@ -187,30 +186,8 @@ object FrameworkHooker : YukiBaseHooker() {
afterHook {
/** 当前 APP 信息 */
val appInfo = ProcessRecordClass.clazz.field { name = "info" }.get(args().first().any()).cast<ApplicationInfo>()
/** 当前异常信息 */
args().last().cast<ApplicationErrorReport.CrashInfo>()?.also { crashInfo ->
/** 添加到第一位 */
(crashInfo.exceptionClassName.lowercase() == "native crash").also { isNativeCrash ->
appErrorsRecords.add(
0, AppErrorsInfoBean(
packageName = appInfo?.packageName ?: "null",
isNativeCrash = isNativeCrash,
exceptionClassName = crashInfo.exceptionClassName ?: "null",
exceptionMessage = if (isNativeCrash) crashInfo.stackTrace.let {
if (it.contains(other = "Abort message: '"))
runCatching { it.split("Abort message: '")[1].split("'")[0] }.getOrNull()
?: crashInfo.exceptionMessage ?: "" else crashInfo.exceptionMessage ?: "null"
} else crashInfo.exceptionMessage ?: "null",
throwFileName = crashInfo.throwFileName ?: "null",
throwClassName = crashInfo.throwClassName ?: "null",
throwMethodName = crashInfo.throwMethodName ?: "null",
throwLineNumber = crashInfo.throwLineNumber,
stackTrace = crashInfo.stackTrace?.trim() ?: "null",
timestamp = System.currentTimeMillis()
)
)
}
}
/** 添加当前异常信息到第一位 */
appErrorsRecords.add(0, AppErrorsInfoBean.clone(appInfo?.packageName, args().last().cast()))
}
}
}

View File

@@ -286,4 +286,46 @@ object LocaleString {
/** @string Automatic generated */
fun moduleNotFullyActivated(vararg objArrs: Any) = R.string.module_not_fully_activated.bind(*objArrs)
/** @string Automatic generated */
val momentAgo get() = momentAgo()
/** @string Automatic generated */
fun momentAgo(vararg objArrs: Any) = R.string.moment_ago.bind(*objArrs)
/** @string Automatic generated */
val secondAgo get() = secondAgo()
/** @string Automatic generated */
fun secondAgo(vararg objArrs: Any) = R.string.second_ago.bind(*objArrs)
/** @string Automatic generated */
val minuteAgo get() = minuteAgo()
/** @string Automatic generated */
fun minuteAgo(vararg objArrs: Any) = R.string.minute_ago.bind(*objArrs)
/** @string Automatic generated */
val hourAgo get() = hourAgo()
/** @string Automatic generated */
fun hourAgo(vararg objArrs: Any) = R.string.hour_ago.bind(*objArrs)
/** @string Automatic generated */
val dayAgo get() = dayAgo()
/** @string Automatic generated */
fun dayAgo(vararg objArrs: Any) = R.string.day_ago.bind(*objArrs)
/** @string Automatic generated */
val monthAgo get() = monthAgo()
/** @string Automatic generated */
fun monthAgo(vararg objArrs: Any) = R.string.month_ago.bind(*objArrs)
/** @string Automatic generated */
val yearAgo get() = yearAgo()
/** @string Automatic generated */
fun yearAgo(vararg objArrs: Any) = R.string.year_ago.bind(*objArrs)
}

View File

@@ -89,7 +89,7 @@ class AppErrorsDetailActivity : BaseActivity<ActivityAppErrorsDetailBinding>() {
binding.errorThrowClassText.text = appErrorsInfo.throwClassName
binding.errorThrowMethodText.text = appErrorsInfo.throwMethodName
binding.errorLineNumberText.text = appErrorsInfo.throwLineNumber.toString()
binding.errorRecordTimeText.text = appErrorsInfo.time
binding.errorRecordTimeText.text = appErrorsInfo.dateTime
binding.errorStackText.text = appErrorsInfo.stackTrace
binding.appPanelScrollView.setOnScrollChangeListener { _, _, y, _, _ ->
binding.detailTitleText.text = if (y >= 30.dp(context = this)) appName(appErrorsInfo.packageName) else LocaleString.appName

View File

@@ -102,7 +102,7 @@ class AppErrorsRecordActivity : BaseActivity<ActivityAppErrorsRecordBinding>() {
getItem(position).also {
holder.appIcon.setImageDrawable(appIcon(it.packageName))
holder.appNameText.text = appName(it.packageName)
holder.errorsTimeText.text = it.time
holder.errorsTimeText.text = it.crossTime
holder.errorTypeIcon.setImageResource(if (it.isNativeCrash) R.drawable.ic_cpp else R.drawable.ic_java)
holder.errorTypeText.text = if (it.isNativeCrash) "Native crash" else it.exceptionClassName.let { text ->
if (text.contains(other = ".")) text.split(".").let { e -> e[e.lastIndex] } else text

View File

@@ -111,6 +111,34 @@ fun Context.appIcon(packageName: String) =
.applicationInfo.loadIcon(packageManager)
}.getOrNull() ?: ResourcesCompat.getDrawable(resources, R.drawable.ic_android, null)
/**
* 计算与当前时间戳相差的友好时间
* @param now 刚刚
* @param second 秒前
* @param minute 分钟前
* @param hour 小时前
* @param day 天前
* @param month 月前
* @param year 年前
* @return [String] 友好时间
*/
fun Long.difference(now: String, second: String, minute: String, hour: String, day: String, month: String, year: String) =
((System.currentTimeMillis() - this) / 1000).toInt().let { diff ->
when (diff) {
in 0..10 -> now
in 11..20 -> "10 $second"
in 21..30 -> "20 $second"
in 31..40 -> "30 $second"
in 41..50 -> "40 $second"
in 51..59 -> "50 $second"
in 60..3599 -> "${(diff / 60).coerceAtLeast(1)} $minute"
in 3600..86399 -> "${diff / 3600} $hour"
in 86400..2591999 -> "${diff / 86400} $day"
in 2592000..31103999 -> "${diff / 2592000} $month"
else -> "${diff / 31104000} $year"
}
}
/**
* 弹出 [Toast]
* @param msg 提示内容

View File

@@ -63,4 +63,11 @@
<string name="fast_restart">高速リスタート</string>
<string name="access_root_fail">ルート権限を取得できませんでした</string>
<string name="todo_items">より多くの機能が開発中です</string>
<string name="moment_ago">現在</string>
<string name="second_ago">秒前</string>
<string name="minute_ago">分前</string>
<string name="hour_ago">時間前</string>
<string name="day_ago">日前</string>
<string name="month_ago">月前</string>
<string name="year_ago">年前</string>
</resources>

View File

@@ -63,4 +63,11 @@
<string name="fast_restart">快速重启</string>
<string name="access_root_fail">获取 Root 权限失败</string>
<string name="todo_items">更多功能正在开发</string>
<string name="moment_ago">刚刚</string>
<string name="second_ago">秒前</string>
<string name="minute_ago">分钟前</string>
<string name="hour_ago">小时前</string>
<string name="day_ago">天前</string>
<string name="month_ago">月前</string>
<string name="year_ago">年前</string>
</resources>

View File

@@ -63,4 +63,11 @@
<string name="fast_restart">急速重開</string>
<string name="access_root_fail">取得 Root 权利失败</string>
<string name="todo_items">更多機能正在開發</string>
<string name="moment_ago">剛剛</string>
<string name="second_ago">秒前</string>
<string name="minute_ago">分鐘前</string>
<string name="hour_ago">小時前</string>
<string name="day_ago">天前</string>
<string name="month_ago">月前</string>
<string name="year_ago">年前</string>
</resources>

View File

@@ -63,4 +63,11 @@
<string name="fast_restart">急速重開</string>
<string name="access_root_fail">取得 Root 权利失败</string>
<string name="todo_items">更多機能正在開發</string>
<string name="moment_ago">剛剛</string>
<string name="second_ago">秒前</string>
<string name="minute_ago">分鐘前</string>
<string name="hour_ago">小時前</string>
<string name="day_ago">天前</string>
<string name="month_ago">月前</string>
<string name="year_ago">年前</string>
</resources>

View File

@@ -63,4 +63,11 @@
<string name="fast_restart">急速重開</string>
<string name="access_root_fail">取得 Root 权利失败</string>
<string name="todo_items">更多機能正在開發</string>
<string name="moment_ago">剛剛</string>
<string name="second_ago">秒前</string>
<string name="minute_ago">分鐘前</string>
<string name="hour_ago">小時前</string>
<string name="day_ago">天前</string>
<string name="month_ago">月前</string>
<string name="year_ago">年前</string>
</resources>

View File

@@ -63,4 +63,11 @@
<string name="fast_restart">Fast restart</string>
<string name="access_root_fail">Access Root failed</string>
<string name="todo_items">More features are in development</string>
<string name="moment_ago">moment ago</string>
<string name="second_ago">second ago</string>
<string name="minute_ago">minutes ago</string>
<string name="hour_ago">hour ago</string>
<string name="day_ago">days ago</string>
<string name="month_ago">month ago</string>
<string name="year_ago">year ago</string>
</resources>