mirror of
https://github.com/KitsunePie/AppErrorsTracking.git
synced 2025-09-04 10:15:18 +08:00
refactor: migrate and update to YukiHookAPI 1.3.0
This commit is contained in:
@@ -84,7 +84,8 @@ androidComponents {
|
|||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation(com.fankes.projectpromote.project.promote)
|
implementation(com.fankes.projectpromote.project.promote)
|
||||||
implementation(com.highcapable.yukireflection.api)
|
implementation(com.highcapable.kavaref.kavaref.core)
|
||||||
|
implementation(com.highcapable.kavaref.kavaref.extension)
|
||||||
implementation(androidx.core.core.ktx)
|
implementation(androidx.core.core.ktx)
|
||||||
implementation(androidx.appcompat.appcompat)
|
implementation(androidx.appcompat.appcompat)
|
||||||
implementation(com.google.android.material.material)
|
implementation(com.google.android.material.material)
|
||||||
|
@@ -19,21 +19,20 @@
|
|||||||
*
|
*
|
||||||
* This file is created by fankes on 2022/5/10.
|
* This file is created by fankes on 2022/5/10.
|
||||||
*/
|
*/
|
||||||
@file:Suppress("DEPRECATION")
|
|
||||||
|
|
||||||
package com.fankes.apperrorsdemo.ui.activity.base
|
package com.fankes.apperrorsdemo.ui.activity.base
|
||||||
|
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
import android.view.LayoutInflater
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import androidx.core.content.res.ResourcesCompat
|
import androidx.core.content.res.ResourcesCompat
|
||||||
import androidx.core.view.WindowCompat
|
import androidx.core.view.WindowCompat
|
||||||
import androidx.viewbinding.ViewBinding
|
import androidx.viewbinding.ViewBinding
|
||||||
import com.fankes.apperrorsdemo.R
|
import com.fankes.apperrorsdemo.R
|
||||||
import com.fankes.apperrorsdemo.utils.factory.isNotSystemInDarkMode
|
import com.fankes.apperrorsdemo.utils.factory.isNotSystemInDarkMode
|
||||||
import com.highcapable.yukireflection.factory.current
|
import com.highcapable.kavaref.KavaRef.Companion.resolve
|
||||||
import com.highcapable.yukireflection.factory.method
|
import com.highcapable.kavaref.extension.genericSuperclassTypeArguments
|
||||||
import com.highcapable.yukireflection.type.android.LayoutInflaterClass
|
import com.highcapable.kavaref.extension.toClassOrNull
|
||||||
|
|
||||||
abstract class BaseActivity<VB : ViewBinding> : AppCompatActivity() {
|
abstract class BaseActivity<VB : ViewBinding> : AppCompatActivity() {
|
||||||
|
|
||||||
@@ -42,10 +41,11 @@ abstract class BaseActivity<VB : ViewBinding> : AppCompatActivity() {
|
|||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
binding = current().generic()?.argument()?.method {
|
val bindingClass = javaClass.genericSuperclassTypeArguments().firstOrNull()?.toClassOrNull()
|
||||||
|
binding = bindingClass?.resolve()?.optional()?.firstMethodOrNull {
|
||||||
name = "inflate"
|
name = "inflate"
|
||||||
param(LayoutInflaterClass)
|
parameters(LayoutInflater::class)
|
||||||
}?.get()?.invoke<VB>(layoutInflater) ?: error("binding failed")
|
}?.invoke<VB>(layoutInflater) ?: error("binding failed")
|
||||||
if (Build.VERSION.SDK_INT >= 35) binding.root.fitsSystemWindows = true
|
if (Build.VERSION.SDK_INT >= 35) binding.root.fitsSystemWindows = true
|
||||||
setContentView(binding.root)
|
setContentView(binding.root)
|
||||||
/** 隐藏系统的标题栏 */
|
/** 隐藏系统的标题栏 */
|
||||||
@@ -55,6 +55,7 @@ abstract class BaseActivity<VB : ViewBinding> : AppCompatActivity() {
|
|||||||
isAppearanceLightStatusBars = isNotSystemInDarkMode
|
isAppearanceLightStatusBars = isNotSystemInDarkMode
|
||||||
isAppearanceLightNavigationBars = isNotSystemInDarkMode
|
isAppearanceLightNavigationBars = isNotSystemInDarkMode
|
||||||
}
|
}
|
||||||
|
@Suppress("DEPRECATION")
|
||||||
ResourcesCompat.getColor(resources, R.color.colorThemeBackground, null).also {
|
ResourcesCompat.getColor(resources, R.color.colorThemeBackground, null).also {
|
||||||
window?.statusBarColor = it
|
window?.statusBarColor = it
|
||||||
window?.navigationBarColor = it
|
window?.navigationBarColor = it
|
||||||
|
@@ -22,7 +22,7 @@ repositories:
|
|||||||
plugins:
|
plugins:
|
||||||
com.android.application:
|
com.android.application:
|
||||||
alias: android-application
|
alias: android-application
|
||||||
version: 8.9.0
|
version: 8.9.3
|
||||||
org.jetbrains.kotlin.android:
|
org.jetbrains.kotlin.android:
|
||||||
alias: kotlin-android
|
alias: kotlin-android
|
||||||
version: 2.1.10
|
version: 2.1.10
|
||||||
@@ -46,12 +46,14 @@ libraries:
|
|||||||
rovo89-xposed-api
|
rovo89-xposed-api
|
||||||
com.highcapable.yukihookapi:
|
com.highcapable.yukihookapi:
|
||||||
api:
|
api:
|
||||||
version: 1.2.1
|
version: 1.3.0
|
||||||
ksp-xposed:
|
ksp-xposed:
|
||||||
version-ref: <this>::api
|
version-ref: <this>::api
|
||||||
com.highcapable.yukireflection:
|
com.highcapable.kavaref:
|
||||||
api:
|
kavaref-core:
|
||||||
version: 1.0.3
|
version: 1.0.0
|
||||||
|
kavaref-extension:
|
||||||
|
version: 1.0.0
|
||||||
com.microsoft.appcenter:
|
com.microsoft.appcenter:
|
||||||
appcenter-analytics:
|
appcenter-analytics:
|
||||||
version: 5.0.6
|
version: 5.0.6
|
||||||
@@ -69,13 +71,13 @@ libraries:
|
|||||||
version: 2.12.1
|
version: 2.12.1
|
||||||
com.squareup.okhttp3:
|
com.squareup.okhttp3:
|
||||||
okhttp:
|
okhttp:
|
||||||
version: 5.0.0-alpha.14
|
version: 5.0.0-alpha.16
|
||||||
androidx.core:
|
androidx.core:
|
||||||
core-ktx:
|
core-ktx:
|
||||||
version: 1.15.0
|
version: 1.16.0
|
||||||
androidx.appcompat:
|
androidx.appcompat:
|
||||||
appcompat:
|
appcompat:
|
||||||
version: 1.7.0
|
version: 1.7.1
|
||||||
com.google.android.material:
|
com.google.android.material:
|
||||||
material:
|
material:
|
||||||
version: 1.12.0
|
version: 1.12.0
|
||||||
|
@@ -82,6 +82,8 @@ dependencies {
|
|||||||
compileOnly(de.robv.android.xposed.api)
|
compileOnly(de.robv.android.xposed.api)
|
||||||
implementation(com.highcapable.yukihookapi.api)
|
implementation(com.highcapable.yukihookapi.api)
|
||||||
ksp(com.highcapable.yukihookapi.ksp.xposed)
|
ksp(com.highcapable.yukihookapi.ksp.xposed)
|
||||||
|
implementation(com.highcapable.kavaref.kavaref.core)
|
||||||
|
implementation(com.highcapable.kavaref.kavaref.extension)
|
||||||
implementation(com.fankes.projectpromote.project.promote)
|
implementation(com.fankes.projectpromote.project.promote)
|
||||||
implementation(com.microsoft.appcenter.appcenter.analytics)
|
implementation(com.microsoft.appcenter.appcenter.analytics)
|
||||||
implementation(com.microsoft.appcenter.appcenter.crashes)
|
implementation(com.microsoft.appcenter.appcenter.crashes)
|
||||||
|
@@ -30,6 +30,7 @@ import android.content.Intent
|
|||||||
import android.content.pm.ApplicationInfo
|
import android.content.pm.ApplicationInfo
|
||||||
import android.content.pm.PackageInfo
|
import android.content.pm.PackageInfo
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
|
import android.os.Bundle
|
||||||
import android.os.Message
|
import android.os.Message
|
||||||
import android.os.SystemClock
|
import android.os.SystemClock
|
||||||
import android.util.ArrayMap
|
import android.util.ArrayMap
|
||||||
@@ -58,16 +59,10 @@ import com.fankes.apperrorstracking.utils.factory.toArrayList
|
|||||||
import com.fankes.apperrorstracking.utils.factory.toast
|
import com.fankes.apperrorstracking.utils.factory.toast
|
||||||
import com.fankes.apperrorstracking.utils.tool.FrameworkTool
|
import com.fankes.apperrorstracking.utils.tool.FrameworkTool
|
||||||
import com.fankes.apperrorstracking.wrapper.BuildConfigWrapper
|
import com.fankes.apperrorstracking.wrapper.BuildConfigWrapper
|
||||||
import com.highcapable.yukihookapi.hook.bean.VariousClass
|
import com.highcapable.kavaref.KavaRef.Companion.resolve
|
||||||
|
import com.highcapable.kavaref.extension.VariousClass
|
||||||
import com.highcapable.yukihookapi.hook.entity.YukiBaseHooker
|
import com.highcapable.yukihookapi.hook.entity.YukiBaseHooker
|
||||||
import com.highcapable.yukihookapi.hook.factory.constructor
|
|
||||||
import com.highcapable.yukihookapi.hook.factory.field
|
|
||||||
import com.highcapable.yukihookapi.hook.factory.hasMethod
|
|
||||||
import com.highcapable.yukihookapi.hook.factory.method
|
|
||||||
import com.highcapable.yukihookapi.hook.log.YLog
|
import com.highcapable.yukihookapi.hook.log.YLog
|
||||||
import com.highcapable.yukihookapi.hook.type.android.BundleClass
|
|
||||||
import com.highcapable.yukihookapi.hook.type.android.MessageClass
|
|
||||||
import com.highcapable.yukihookapi.hook.type.java.BooleanType
|
|
||||||
|
|
||||||
object FrameworkHooker : YukiBaseHooker() {
|
object FrameworkHooker : YukiBaseHooker() {
|
||||||
|
|
||||||
@@ -110,40 +105,73 @@ object FrameworkHooker : YukiBaseHooker() {
|
|||||||
* 获取当前包列表实例
|
* 获取当前包列表实例
|
||||||
* @return [Any] or null
|
* @return [Any] or null
|
||||||
*/
|
*/
|
||||||
private val pkgList = if (ProcessRecordClass.hasMethod { name = "getPkgList"; emptyParam() })
|
private val pkgList by lazy {
|
||||||
ProcessRecordClass.method { name = "getPkgList"; emptyParam() }.get(proc).call()
|
ProcessRecordClass.resolve().optional(silent = true)
|
||||||
else ProcessRecordClass.field { name { it.endsWith("pkgList", true) } }.get(proc).any()
|
.firstMethodOrNull {
|
||||||
|
name = "getPkgList"
|
||||||
|
emptyParameters()
|
||||||
|
}?.of(proc)?.invoke()
|
||||||
|
?: ProcessRecordClass.resolve().optional(silent = true)
|
||||||
|
.firstFieldOrNull {
|
||||||
|
name { it.endsWith("pkgList", true) }
|
||||||
|
}?.of(proc)?.get()
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取当前包列表数组大小
|
* 获取当前包列表数组大小
|
||||||
* @return [Int]
|
* @return [Int]
|
||||||
*/
|
*/
|
||||||
private val pkgListSize = PackageListClass?.method { name = "size"; emptyParam() }?.get(pkgList)?.int()
|
private val pkgListSize by lazy {
|
||||||
?: ProcessRecordClass.field { name = "pkgList" }.get(proc).cast<ArrayMap<*, *>>()?.size ?: -1
|
PackageListClass?.resolve()?.optional(silent = true)
|
||||||
|
?.firstMethodOrNull {
|
||||||
|
name = "size"
|
||||||
|
emptyParameters()
|
||||||
|
}?.of(pkgList)?.invoke()
|
||||||
|
?: ProcessRecordClass.resolve().optional(silent = true)
|
||||||
|
.firstFieldOrNull { name = "pkgList" }
|
||||||
|
?.of(proc)?.get<ArrayMap<*, *>>()?.size ?: -1
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取当前 pid 信息
|
* 获取当前 pid 信息
|
||||||
* @return [Int]
|
* @return [Int]
|
||||||
*/
|
*/
|
||||||
val pid = ProcessRecordClass.field { name { it == "mPid" || it == "pid" } }.get(proc).int()
|
val pid by lazy {
|
||||||
|
ProcessRecordClass.resolve().optional()
|
||||||
|
.firstFieldOrNull {
|
||||||
|
name { it == "mPid" || it == "pid" }
|
||||||
|
}?.of(proc)?.get<Int>() ?: 0
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取当前用户 ID 信息
|
* 获取当前用户 ID 信息
|
||||||
* @return [Int]
|
* @return [Int]
|
||||||
*/
|
*/
|
||||||
val userId = ProcessRecordClass.field { name = "userId" }.get(proc).int()
|
val userId by lazy {
|
||||||
|
ProcessRecordClass.resolve().optional()
|
||||||
|
.firstFieldOrNull { name = "userId" }
|
||||||
|
?.of(proc)?.get<Int>() ?: 0
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取当前 APP 信息
|
* 获取当前 APP 信息
|
||||||
* @return [ApplicationInfo] or null
|
* @return [ApplicationInfo] or null
|
||||||
*/
|
*/
|
||||||
val appInfo = ProcessRecordClass.field { name = "info" }.get(proc).cast<ApplicationInfo>()
|
val appInfo by lazy {
|
||||||
|
ProcessRecordClass.resolve().optional()
|
||||||
|
.firstFieldOrNull { name = "info" }
|
||||||
|
?.of(proc)?.get<ApplicationInfo>()
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取当前进程名称
|
* 获取当前进程名称
|
||||||
* @return [String]
|
* @return [String]
|
||||||
*/
|
*/
|
||||||
val processName = ProcessRecordClass.field { name = "processName" }.get(proc).string()
|
val processName by lazy {
|
||||||
|
ProcessRecordClass.resolve().optional()
|
||||||
|
.firstFieldOrNull { name = "processName" }
|
||||||
|
?.of(proc)?.get<String>() ?: ""
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取当前 APP、进程 包名
|
* 获取当前 APP、进程 包名
|
||||||
@@ -167,17 +195,25 @@ object FrameworkHooker : YukiBaseHooker() {
|
|||||||
* 获取当前进程是否为后台进程
|
* 获取当前进程是否为后台进程
|
||||||
* @return [Boolean]
|
* @return [Boolean]
|
||||||
*/
|
*/
|
||||||
val isBackgroundProcess = UserControllerClass
|
val isBackgroundProcess by lazy {
|
||||||
.method { name { it == "getCurrentProfileIds" || it == "getCurrentProfileIdsLocked" } }
|
UserControllerClass.resolve().optional()
|
||||||
.get(ActivityManagerServiceClass?.field { name = "mUserController" }
|
.firstMethodOrNull { name { it == "getCurrentProfileIds" || it == "getCurrentProfileIdsLocked" } }
|
||||||
?.get(AppErrorsClass.field { name = "mService" }.get(errors).any())?.any())
|
?.of(ActivityManagerServiceClass?.resolve()?.optional()?.firstFieldOrNull { name = "mUserController" }
|
||||||
.invoke<IntArray>()?.takeIf { it.isNotEmpty() }?.any { it != userId } ?: false
|
?.of(AppErrorsClass.resolve().optional().firstFieldOrNull { name = "mService" }?.of(errors)?.get())?.getQuietly())
|
||||||
|
?.invokeQuietly<IntArray>()?.takeIf { it.isNotEmpty() }?.any { it != userId } ?: false
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取当前进程是否短时内重复崩溃
|
* 获取当前进程是否短时内重复崩溃
|
||||||
* @return [Boolean]
|
* @return [Boolean]
|
||||||
*/
|
*/
|
||||||
val isRepeatingCrash = resultData?.let { AppErrorDialog_DataClass.field { name = "repeating" }.get(it).boolean() } ?: false
|
val isRepeatingCrash by lazy {
|
||||||
|
resultData?.let {
|
||||||
|
AppErrorDialog_DataClass.resolve().optional()
|
||||||
|
.firstFieldOrNull { name = "repeating" }
|
||||||
|
?.of(it)?.get<Boolean>() == true
|
||||||
|
} ?: false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 注册生命周期 */
|
/** 注册生命周期 */
|
||||||
@@ -376,60 +412,56 @@ object FrameworkHooker : YukiBaseHooker() {
|
|||||||
/** 注册生命周期 */
|
/** 注册生命周期 */
|
||||||
registerLifecycle()
|
registerLifecycle()
|
||||||
/** 干掉原生错误对话框 - 如果有 */
|
/** 干掉原生错误对话框 - 如果有 */
|
||||||
ErrorDialogControllerClass?.apply {
|
ErrorDialogControllerClass?.resolve()?.optional(silent = true)?.apply {
|
||||||
if (hasMethod { name = "hasCrashDialogs"; emptyParam() }) {
|
val hasCrashDialogs = firstMethodOrNull {
|
||||||
method {
|
name = "hasCrashDialogs"
|
||||||
name = "hasCrashDialogs"
|
emptyParameters()
|
||||||
emptyParam()
|
}?.hook()?.replaceToTrue() != null
|
||||||
}.hook().replaceToTrue()
|
if (!hasCrashDialogs)
|
||||||
|
firstConstructorOrNull {
|
||||||
} else {
|
parameterCount = 1
|
||||||
constructor {
|
}?.hook()?.after {
|
||||||
paramCount = 1
|
firstFieldOrNull { name = "mCrashDialogs" }?.of(instance)?.set(emptyList<Any>())
|
||||||
}.hook().after {
|
|
||||||
field { name = "mCrashDialogs" }.get(instance).set(emptyList<Any>())
|
|
||||||
}
|
}
|
||||||
}
|
firstMethodOrNull {
|
||||||
|
|
||||||
method {
|
|
||||||
name = "showCrashDialogs"
|
name = "showCrashDialogs"
|
||||||
paramCount = 1
|
parameterCount = 1
|
||||||
}.hook().intercept()
|
}?.hook()?.intercept()
|
||||||
}
|
}
|
||||||
/** 干掉原生错误对话框 - API 30 以下 */
|
/** 干掉原生错误对话框 - API 30 以下 */
|
||||||
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.Q) {
|
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.Q) {
|
||||||
ActivityTaskManagerService_LocalServiceClass?.method {
|
ActivityTaskManagerService_LocalServiceClass?.resolve()?.optional()?.firstMethodOrNull {
|
||||||
name = "canShowErrorDialogs"
|
name = "canShowErrorDialogs"
|
||||||
emptyParam()
|
emptyParameters()
|
||||||
}?.ignored()?.hook()?.replaceToFalse()
|
}?.hook()?.replaceToFalse()
|
||||||
ActivityManagerServiceClass?.method {
|
ActivityManagerServiceClass?.resolve()?.optional()?.firstMethodOrNull {
|
||||||
name = "canShowErrorDialogs"
|
name = "canShowErrorDialogs"
|
||||||
emptyParam()
|
emptyParameters()
|
||||||
}?.ignored()?.hook()?.replaceToFalse()
|
}?.hook()?.replaceToFalse()
|
||||||
}
|
}
|
||||||
/** 干掉原生错误对话框 - 如果上述方法全部失效则直接结束对话框 */
|
/** 干掉原生错误对话框 - 如果上述方法全部失效则直接结束对话框 */
|
||||||
AppErrorDialogClass.apply {
|
AppErrorDialogClass.resolve().optional(silent = true).apply {
|
||||||
method {
|
firstMethodOrNull {
|
||||||
name = "onCreate"
|
name = "onCreate"
|
||||||
param(BundleClass)
|
parameters(Bundle::class)
|
||||||
}.ignored().hook().after { instance<Dialog>().cancel() }
|
}?.hook()?.after { instance<Dialog>().cancel() }
|
||||||
method {
|
firstMethodOrNull {
|
||||||
name = "onStart"
|
name = "onStart"
|
||||||
emptyParam()
|
emptyParameters()
|
||||||
}.ignored().hook().after { instance<Dialog>().cancel() }
|
}?.hook()?.after { instance<Dialog>().cancel() }
|
||||||
}
|
}
|
||||||
/** 注入自定义错误对话框 */
|
/** 注入自定义错误对话框 */
|
||||||
AppErrorsClass.apply {
|
AppErrorsClass.resolve().optional().apply {
|
||||||
when {
|
when {
|
||||||
Build.VERSION.SDK_INT > Build.VERSION_CODES.R -> {
|
Build.VERSION.SDK_INT > Build.VERSION_CODES.R -> {
|
||||||
method {
|
firstMethodOrNull {
|
||||||
name = "handleAppCrashLSPB"
|
name = "handleAppCrashLSPB"
|
||||||
paramCount = 6
|
parameterCount = 6
|
||||||
}.hook().after {
|
}?.hook()?.after {
|
||||||
/** 如果为用户终止则不展示异常 */
|
/** 如果为用户终止则不展示异常 */
|
||||||
if (args(index = 1).string() == "user-terminated") return@after
|
if (args(index = 1).string() == "user-terminated") return@after
|
||||||
/** 当前实例 */
|
/** 当前实例 */
|
||||||
val context = appContext ?: field { name = "mContext" }.get(instance).cast<Context>() ?: return@after
|
val context = appContext ?: firstFieldOrNull { name = "mContext" }?.of(instance)?.get<Context>() ?: return@after
|
||||||
|
|
||||||
/** 当前进程信息 */
|
/** 当前进程信息 */
|
||||||
val proc = args().first().any() ?: return@after YLog.warn("Received but got null ProcessRecord (Show UI failed)")
|
val proc = args().first().any() ?: return@after YLog.warn("Received but got null ProcessRecord (Show UI failed)")
|
||||||
@@ -441,29 +473,29 @@ object FrameworkHooker : YukiBaseHooker() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else -> {
|
else -> {
|
||||||
method {
|
firstMethodOrNull {
|
||||||
name = "handleShowAppErrorUi"
|
name = "handleShowAppErrorUi"
|
||||||
param(MessageClass)
|
parameters(Message::class)
|
||||||
}.hook().after {
|
}?.hook()?.after {
|
||||||
/** 当前实例 */
|
/** 当前实例 */
|
||||||
val context = appContext ?: field { name = "mContext" }.get(instance).cast<Context>() ?: return@after
|
val context = appContext ?: firstFieldOrNull { name = "mContext" }?.of(instance)?.get<Context>() ?: return@after
|
||||||
|
|
||||||
/** 当前错误数据 */
|
/** 当前错误数据 */
|
||||||
val resultData = args().first().cast<Message>()?.obj
|
val resultData = args().first().cast<Message>()?.obj
|
||||||
|
|
||||||
/** 当前进程信息 */
|
/** 当前进程信息 */
|
||||||
val proc = AppErrorDialog_DataClass.field { name = "proc" }.get(resultData).any()
|
val proc = AppErrorDialog_DataClass.resolve().optional().firstFieldOrNull { name = "proc" }?.of(resultData)?.get()
|
||||||
/** 创建 APP 进程异常数据类 */
|
/** 创建 APP 进程异常数据类 */
|
||||||
AppErrorsProcessData(instance, proc, resultData).handleShowAppErrorUi(context)
|
AppErrorsProcessData(instance, proc, resultData).handleShowAppErrorUi(context)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
method {
|
firstMethodOrNull {
|
||||||
name = "handleAppCrashInActivityController"
|
name = "handleAppCrashInActivityController"
|
||||||
returnType = BooleanType
|
returnType = Boolean::class
|
||||||
}.hook().after {
|
}?.hook()?.after {
|
||||||
/** 当前实例 */
|
/** 当前实例 */
|
||||||
val context = appContext ?: field { name = "mContext" }.get(instance).cast<Context>() ?: return@after
|
val context = appContext ?: firstFieldOrNull { name = "mContext" }?.of(instance)?.get<Context>() ?: return@after
|
||||||
|
|
||||||
/** 当前进程信息 */
|
/** 当前进程信息 */
|
||||||
val proc = args().first().any() ?: return@after YLog.warn("Received but got null ProcessRecord")
|
val proc = args().first().any() ?: return@after YLog.warn("Received but got null ProcessRecord")
|
||||||
|
@@ -19,14 +19,13 @@
|
|||||||
*
|
*
|
||||||
* This file is created by fankes on 2022/5/7.
|
* This file is created by fankes on 2022/5/7.
|
||||||
*/
|
*/
|
||||||
@file:Suppress("DEPRECATION")
|
|
||||||
|
|
||||||
package com.fankes.apperrorstracking.ui.activity.base
|
package com.fankes.apperrorstracking.ui.activity.base
|
||||||
|
|
||||||
import android.app.ActivityManager
|
import android.app.ActivityManager
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
import android.view.LayoutInflater
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import androidx.core.content.res.ResourcesCompat
|
import androidx.core.content.res.ResourcesCompat
|
||||||
import androidx.core.view.WindowCompat
|
import androidx.core.view.WindowCompat
|
||||||
@@ -34,9 +33,9 @@ import androidx.viewbinding.ViewBinding
|
|||||||
import com.fankes.apperrorstracking.R
|
import com.fankes.apperrorstracking.R
|
||||||
import com.fankes.apperrorstracking.utils.factory.isNotSystemInDarkMode
|
import com.fankes.apperrorstracking.utils.factory.isNotSystemInDarkMode
|
||||||
import com.fankes.apperrorstracking.utils.factory.toast
|
import com.fankes.apperrorstracking.utils.factory.toast
|
||||||
import com.highcapable.yukihookapi.hook.factory.current
|
import com.highcapable.kavaref.KavaRef.Companion.resolve
|
||||||
import com.highcapable.yukihookapi.hook.factory.method
|
import com.highcapable.kavaref.extension.genericSuperclassTypeArguments
|
||||||
import com.highcapable.yukihookapi.hook.type.android.LayoutInflaterClass
|
import com.highcapable.kavaref.extension.toClassOrNull
|
||||||
|
|
||||||
abstract class BaseActivity<VB : ViewBinding> : AppCompatActivity() {
|
abstract class BaseActivity<VB : ViewBinding> : AppCompatActivity() {
|
||||||
|
|
||||||
@@ -45,10 +44,11 @@ abstract class BaseActivity<VB : ViewBinding> : AppCompatActivity() {
|
|||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
binding = current().generic()?.argument()?.method {
|
val bindingClass = javaClass.genericSuperclassTypeArguments().firstOrNull()?.toClassOrNull()
|
||||||
|
binding = bindingClass?.resolve()?.optional()?.firstMethodOrNull {
|
||||||
name = "inflate"
|
name = "inflate"
|
||||||
param(LayoutInflaterClass)
|
parameters(LayoutInflater::class)
|
||||||
}?.get()?.invoke<VB>(layoutInflater) ?: error("binding failed")
|
}?.invoke<VB>(layoutInflater) ?: error("binding failed")
|
||||||
if (Build.VERSION.SDK_INT >= 35) binding.root.fitsSystemWindows = true
|
if (Build.VERSION.SDK_INT >= 35) binding.root.fitsSystemWindows = true
|
||||||
setContentView(binding.root)
|
setContentView(binding.root)
|
||||||
/** 隐藏系统的标题栏 */
|
/** 隐藏系统的标题栏 */
|
||||||
@@ -58,6 +58,7 @@ abstract class BaseActivity<VB : ViewBinding> : AppCompatActivity() {
|
|||||||
isAppearanceLightStatusBars = isNotSystemInDarkMode
|
isAppearanceLightStatusBars = isNotSystemInDarkMode
|
||||||
isAppearanceLightNavigationBars = isNotSystemInDarkMode
|
isAppearanceLightNavigationBars = isNotSystemInDarkMode
|
||||||
}
|
}
|
||||||
|
@Suppress("DEPRECATION")
|
||||||
ResourcesCompat.getColor(resources, R.color.colorThemeBackground, null).also {
|
ResourcesCompat.getColor(resources, R.color.colorThemeBackground, null).also {
|
||||||
window?.statusBarColor = it
|
window?.statusBarColor = it
|
||||||
window?.navigationBarColor = it
|
window?.navigationBarColor = it
|
||||||
|
@@ -19,6 +19,8 @@
|
|||||||
*
|
*
|
||||||
* This file is created by fankes on 2022/6/3.
|
* This file is created by fankes on 2022/6/3.
|
||||||
*/
|
*/
|
||||||
|
@file:Suppress("DEPRECATION")
|
||||||
|
|
||||||
package com.fankes.apperrorstracking.utils.factory
|
package com.fankes.apperrorstracking.utils.factory
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
|
@@ -19,7 +19,7 @@
|
|||||||
*
|
*
|
||||||
* This file is created by fankes on 2022/5/12.
|
* This file is created by fankes on 2022/5/12.
|
||||||
*/
|
*/
|
||||||
@file:Suppress("unused")
|
@file:Suppress("unused", "DEPRECATION")
|
||||||
|
|
||||||
package com.fankes.apperrorstracking.utils.factory
|
package com.fankes.apperrorstracking.utils.factory
|
||||||
|
|
||||||
|
@@ -19,7 +19,7 @@
|
|||||||
*
|
*
|
||||||
* This file is created by fankes on 2022/5/7.
|
* This file is created by fankes on 2022/5/7.
|
||||||
*/
|
*/
|
||||||
@file:Suppress("unused", "NotificationPermission")
|
@file:Suppress("unused", "NotificationPermission", "DEPRECATION")
|
||||||
|
|
||||||
package com.fankes.apperrorstracking.utils.factory
|
package com.fankes.apperrorstracking.utils.factory
|
||||||
|
|
||||||
|
@@ -776,6 +776,35 @@
|
|||||||
android:textColor="@color/colorTextGray"
|
android:textColor="@color/colorTextGray"
|
||||||
android:textSize="11sp" />
|
android:textSize="11sp" />
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginLeft="15dp"
|
||||||
|
android:layout_marginRight="15dp"
|
||||||
|
android:layout_marginBottom="10dp"
|
||||||
|
android:background="@drawable/bg_permotion_round"
|
||||||
|
android:gravity="center|start"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:padding="10dp">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:layout_width="35dp"
|
||||||
|
android:layout_height="35dp"
|
||||||
|
android:layout_marginEnd="10dp"
|
||||||
|
android:src="@mipmap/ic_kavaref" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:autoLink="web"
|
||||||
|
android:ellipsize="end"
|
||||||
|
android:lineSpacingExtra="6dp"
|
||||||
|
android:maxLines="2"
|
||||||
|
android:text="@string/about_module_extension"
|
||||||
|
android:textColor="@color/colorTextGray"
|
||||||
|
android:textSize="11sp" />
|
||||||
|
</LinearLayout>
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
</androidx.core.widget.NestedScrollView>
|
</androidx.core.widget.NestedScrollView>
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
BIN
module-app/src/main/res/mipmap-xxhdpi/ic_kavaref.png
Normal file
BIN
module-app/src/main/res/mipmap-xxhdpi/ic_kavaref.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 17 KiB |
@@ -157,4 +157,5 @@
|
|||||||
<string name="stack_trace_share_system_build_id">システムビルド ID</string>
|
<string name="stack_trace_share_system_build_id">システムビルド ID</string>
|
||||||
<string name="stack_trace_share_package_name">アプリのパッケージ名</string>
|
<string name="stack_trace_share_package_name">アプリのパッケージ名</string>
|
||||||
<string name="stack_trace_share_other">その他の要件</string>
|
<string name="stack_trace_share_other">その他の要件</string>
|
||||||
|
<string name="about_module_extension">このモジュールは KavaRef を搭載しています。\n詳細はこちら https://github.com/HighCapable/KavaRef</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
@@ -159,4 +159,5 @@
|
|||||||
<string name="stack_trace_share_other">其它必要信息</string>
|
<string name="stack_trace_share_other">其它必要信息</string>
|
||||||
<string name="share_with_file">以文件方式分享异常堆栈</string>
|
<string name="share_with_file">以文件方式分享异常堆栈</string>
|
||||||
<string name="share_with_file_tip">使用文件的方式代替文本分享异常堆栈</string>
|
<string name="share_with_file_tip">使用文件的方式代替文本分享异常堆栈</string>
|
||||||
|
<string name="about_module_extension">此模块使用 KavaRef 强力驱动。\n了解更多 https://github.com/HighCapable/KavaRef</string>
|
||||||
</resources>
|
</resources>
|
@@ -155,4 +155,5 @@
|
|||||||
<string name="stack_trace_share_system_build_id">系統建置 ID</string>
|
<string name="stack_trace_share_system_build_id">系統建置 ID</string>
|
||||||
<string name="stack_trace_share_package_name">應用程式包名稱</string>
|
<string name="stack_trace_share_package_name">應用程式包名稱</string>
|
||||||
<string name="stack_trace_share_other">其它必要資訊</string>
|
<string name="stack_trace_share_other">其它必要資訊</string>
|
||||||
|
<string name="about_module_extension">此模組使用 KavaRef 強力驅動。\n了解更多 https://github.com/HighCapable/KavaRef</string>
|
||||||
</resources>
|
</resources>
|
@@ -155,4 +155,5 @@
|
|||||||
<string name="stack_trace_share_system_build_id">系統建置 ID</string>
|
<string name="stack_trace_share_system_build_id">系統建置 ID</string>
|
||||||
<string name="stack_trace_share_package_name">應用程式包名稱</string>
|
<string name="stack_trace_share_package_name">應用程式包名稱</string>
|
||||||
<string name="stack_trace_share_other">其它必要資訊</string>
|
<string name="stack_trace_share_other">其它必要資訊</string>
|
||||||
|
<string name="about_module_extension">此模組使用 KavaRef 強力驅動。\n了解更多 https://github.com/HighCapable/KavaRef</string>
|
||||||
</resources>
|
</resources>
|
@@ -155,4 +155,5 @@
|
|||||||
<string name="stack_trace_share_system_build_id">系統建置 ID</string>
|
<string name="stack_trace_share_system_build_id">系統建置 ID</string>
|
||||||
<string name="stack_trace_share_package_name">應用程式包名稱</string>
|
<string name="stack_trace_share_package_name">應用程式包名稱</string>
|
||||||
<string name="stack_trace_share_other">其它必要資訊</string>
|
<string name="stack_trace_share_other">其它必要資訊</string>
|
||||||
|
<string name="about_module_extension">此模組使用 KavaRef 強力驅動。\n瞭解更多 https://github.com/HighCapable/KavaRef</string>
|
||||||
</resources>
|
</resources>
|
@@ -162,4 +162,5 @@
|
|||||||
<string name="stack_trace_share_other">Other Requirement</string>
|
<string name="stack_trace_share_other">Other Requirement</string>
|
||||||
<string name="share_with_file">Share errors stacktrace with file</string>
|
<string name="share_with_file">Share errors stacktrace with file</string>
|
||||||
<string name="share_with_file_tip">Share errors stacktrace using files instead of text</string>
|
<string name="share_with_file_tip">Share errors stacktrace using files instead of text</string>
|
||||||
|
<string name="about_module_extension">This Xposed Module is powered by KavaRef.\nLearn more https://github.com/HighCapable/KavaRef</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
Reference in New Issue
Block a user