mirror of
https://github.com/KitsunePie/AppErrorsTracking.git
synced 2025-09-01 16:55:18 +08:00
Added crossTime and dateTime in AppErrorsInfoBean
This commit is contained in:
@@ -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
|
||||
}
|
@@ -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()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -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)
|
||||
}
|
@@ -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
|
||||
|
@@ -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
|
||||
|
@@ -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 提示内容
|
||||
|
@@ -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>
|
@@ -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>
|
@@ -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>
|
@@ -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>
|
@@ -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>
|
@@ -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>
|
Reference in New Issue
Block a user