mirror of
https://github.com/KitsunePie/AppErrorsTracking.git
synced 2025-09-01 16:55:18 +08:00
Merge module and host receiver to new api
This commit is contained in:
@@ -1,78 +0,0 @@
|
||||
/*
|
||||
* AppErrorsTracking - Added more features to app's crash dialog, fixed custom rom deleted dialog, the best experience to Android developer.
|
||||
* Copyright (C) 2019-2022 Fankes Studio(qzmmcn@163.com)
|
||||
* https://github.com/KitsunePie/AppErrorsTracking
|
||||
*
|
||||
* This software is non-free but opensource software: you can redistribute it
|
||||
* and/or modify it under the terms of the GNU Affero General Public License
|
||||
* as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or any later version.
|
||||
*
|
||||
* This software is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* and eula along with this software. If not, see
|
||||
* <https://www.gnu.org/licenses/>
|
||||
*
|
||||
* This file is Created by fankes on 2022/5/12.
|
||||
*/
|
||||
@file:Suppress("MemberVisibilityCanBePrivate")
|
||||
|
||||
package com.fankes.apperrorstracking.const
|
||||
|
||||
import com.fankes.apperrorstracking.BuildConfig
|
||||
import com.fankes.apperrorstracking.bean.AppErrorsInfoBean
|
||||
|
||||
/**
|
||||
* 全局常量
|
||||
*/
|
||||
object Const {
|
||||
|
||||
/** 当前模块的包名 */
|
||||
const val MODULE_PACKAGE_NAME = BuildConfig.APPLICATION_ID
|
||||
|
||||
/** 当前模块的版本名称 */
|
||||
const val MODULE_VERSION_NAME = BuildConfig.VERSION_NAME
|
||||
|
||||
/** 当前模块的版本号 */
|
||||
const val MODULE_VERSION_CODE = BuildConfig.VERSION_CODE
|
||||
|
||||
/** 当前模块的版本校验 */
|
||||
const val MODULE_VERSION_VERIFY = "${MODULE_VERSION_NAME}_${MODULE_VERSION_CODE}_202205141842"
|
||||
|
||||
/** [AppErrorsInfoBean] 传值 */
|
||||
const val EXTRA_APP_ERRORS_INFO = "app_errors_info_extra"
|
||||
|
||||
/** 模块接收广播 */
|
||||
const val ACTION_MODULE_HANDLER_RECEIVER = "module_handler_action"
|
||||
|
||||
/** 宿主接收广播 */
|
||||
const val ACTION_HOST_HANDLER_RECEIVER = "host_handler_action"
|
||||
|
||||
/** 模块与宿主交互数据 */
|
||||
const val KEY_MODULE_HOST_FETCH = "module_host_data_fetch_key"
|
||||
|
||||
/** 校验模块宿主版本一致性 */
|
||||
const val TYPE_MODULE_VERSION_VERIFY = "module_version_verify_type"
|
||||
|
||||
/** 获取 [AppErrorsInfoBean] 数据 */
|
||||
const val TYPE_APP_ERRORS_DATA_GET = "app_errors_data_get_type"
|
||||
|
||||
/** 清空 [AppErrorsInfoBean] 数据 */
|
||||
const val TYPE_APP_ERRORS_DATA_CLEAR = "app_errors_data_clear_type"
|
||||
|
||||
/** 删除指定 [AppErrorsInfoBean] 数据 */
|
||||
const val TYPE_APP_ERRORS_DATA_REMOVE = "app_errors_data_remove_type"
|
||||
|
||||
/** 当前模块的版本校验标签 */
|
||||
const val TAG_MODULE_VERSION_VERIFY = "module_version_verify_tag"
|
||||
|
||||
/** 获取到的 [AppErrorsInfoBean] 数据内容 */
|
||||
const val TAG_APP_ERRORS_DATA_GET_CONTENT = "app_errors_data_get_content_tag"
|
||||
|
||||
/** 指定删除的 [AppErrorsInfoBean] 数据内容 */
|
||||
const val TAG_APP_ERRORS_DATA_REMOVE_CONTENT = "app_errors_data_remove_content_tag"
|
||||
}
|
@@ -24,10 +24,8 @@
|
||||
package com.fankes.apperrorstracking.hook.entity
|
||||
|
||||
import android.app.ApplicationErrorReport
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.IntentFilter
|
||||
import android.content.pm.ApplicationInfo
|
||||
import android.graphics.Color
|
||||
import android.os.Message
|
||||
@@ -41,18 +39,17 @@ import android.widget.TextView
|
||||
import androidx.core.content.res.ResourcesCompat
|
||||
import com.fankes.apperrorstracking.R
|
||||
import com.fankes.apperrorstracking.bean.AppErrorsInfoBean
|
||||
import com.fankes.apperrorstracking.const.Const
|
||||
import com.fankes.apperrorstracking.locale.LocaleString
|
||||
import com.fankes.apperrorstracking.ui.activity.errors.AppErrorsDetailActivity
|
||||
import com.fankes.apperrorstracking.utils.drawable.drawabletoolbox.DrawableBuilder
|
||||
import com.fankes.apperrorstracking.utils.factory.*
|
||||
import com.fankes.apperrorstracking.utils.tool.FrameworkTool
|
||||
import com.highcapable.yukihookapi.hook.bean.VariousClass
|
||||
import com.highcapable.yukihookapi.hook.entity.YukiBaseHooker
|
||||
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.loggerE
|
||||
import com.highcapable.yukihookapi.hook.type.android.ActivityThreadClass
|
||||
import com.highcapable.yukihookapi.hook.type.android.MessageClass
|
||||
|
||||
object FrameworkHooker : YukiBaseHooker() {
|
||||
@@ -87,75 +84,6 @@ object FrameworkHooker : YukiBaseHooker() {
|
||||
/** 已记录的 APP 异常信息数组 - 直到重新启动 */
|
||||
private val appErrorsRecords = arrayListOf<AppErrorsInfoBean>()
|
||||
|
||||
/** 是否已经注册广播 */
|
||||
private var isRegisterReceiver = false
|
||||
|
||||
/** 用户解锁屏幕广播接收器 */
|
||||
private val userPresentReceiver by lazy {
|
||||
object : BroadcastReceiver() {
|
||||
override fun onReceive(context: Context?, intent: Intent?) {
|
||||
/** 解锁后清空已记录的忽略错误 APP */
|
||||
ignoredErrorsIfUnlockApps.clear()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** 语言区域改变广播接收器 */
|
||||
private val localeChangedReceiver by lazy {
|
||||
object : BroadcastReceiver() {
|
||||
override fun onReceive(context: Context?, intent: Intent?) {
|
||||
/** 刷新模块 Resources 缓存 */
|
||||
refreshModuleAppResources()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** 宿主广播接收器 */
|
||||
private val hostHandlerReceiver by lazy {
|
||||
object : BroadcastReceiver() {
|
||||
override fun onReceive(context: Context?, intent: Intent?) {
|
||||
if (intent == null) return
|
||||
intent.getStringExtra(Const.KEY_MODULE_HOST_FETCH)?.also {
|
||||
if (it.isNotBlank()) context?.sendBroadcast(Intent().apply {
|
||||
action = Const.ACTION_MODULE_HANDLER_RECEIVER
|
||||
when (it) {
|
||||
Const.TYPE_MODULE_VERSION_VERIFY -> {
|
||||
putExtra(Const.TAG_MODULE_VERSION_VERIFY, Const.MODULE_VERSION_VERIFY)
|
||||
putExtra(Const.KEY_MODULE_HOST_FETCH, Const.TYPE_MODULE_VERSION_VERIFY)
|
||||
}
|
||||
Const.TYPE_APP_ERRORS_DATA_GET -> {
|
||||
putExtra(Const.TAG_APP_ERRORS_DATA_GET_CONTENT, appErrorsRecords)
|
||||
putExtra(Const.KEY_MODULE_HOST_FETCH, Const.TYPE_APP_ERRORS_DATA_GET)
|
||||
}
|
||||
Const.TYPE_APP_ERRORS_DATA_REMOVE -> {
|
||||
runCatching { intent.getSerializableExtra(Const.TAG_APP_ERRORS_DATA_REMOVE_CONTENT) as? AppErrorsInfoBean? }
|
||||
.getOrNull()?.also { e -> appErrorsRecords.remove(e) }
|
||||
putExtra(Const.KEY_MODULE_HOST_FETCH, Const.TYPE_APP_ERRORS_DATA_REMOVE)
|
||||
}
|
||||
Const.TYPE_APP_ERRORS_DATA_CLEAR -> {
|
||||
appErrorsRecords.clear()
|
||||
putExtra(Const.KEY_MODULE_HOST_FETCH, Const.TYPE_APP_ERRORS_DATA_CLEAR)
|
||||
}
|
||||
else -> {}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 注册广播接收器
|
||||
* @param context 实例
|
||||
*/
|
||||
private fun registerReceiver(context: Context) {
|
||||
if (isRegisterReceiver) return
|
||||
context.registerReceiver(userPresentReceiver, IntentFilter().apply { addAction(Intent.ACTION_USER_PRESENT) })
|
||||
context.registerReceiver(localeChangedReceiver, IntentFilter().apply { addAction(Intent.ACTION_LOCALE_CHANGED) })
|
||||
context.registerReceiver(hostHandlerReceiver, IntentFilter().apply { addAction(Const.ACTION_HOST_HANDLER_RECEIVER) })
|
||||
isRegisterReceiver = true
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取最新的 APP 错误信息
|
||||
* @param packageName 包名
|
||||
@@ -195,17 +123,24 @@ object FrameworkHooker : YukiBaseHooker() {
|
||||
setOnClickListener { it() }
|
||||
}
|
||||
|
||||
override fun onHook() {
|
||||
/** 注入全局监听 */
|
||||
ActivityThreadClass.hook {
|
||||
injectMember {
|
||||
method {
|
||||
name = "currentApplication"
|
||||
emptyParam()
|
||||
}
|
||||
afterHook { result<Context>()?.let { registerReceiver(it) } }
|
||||
}
|
||||
/** 注册 */
|
||||
private fun register() {
|
||||
onAppLifecycle {
|
||||
/** 解锁后清空已记录的忽略错误 APP */
|
||||
registerReceiver(Intent.ACTION_USER_PRESENT) { _, _ -> ignoredErrorsIfUnlockApps.clear() }
|
||||
/** 刷新模块 Resources 缓存 */
|
||||
registerReceiver(Intent.ACTION_LOCALE_CHANGED) { _, _ -> refreshModuleAppResources() }
|
||||
}
|
||||
FrameworkTool.Host.with(instance = this) {
|
||||
onPushAppErrorsInfoData { appErrorsRecords }
|
||||
onRemoveAppErrorsInfoData { appErrorsRecords.remove(it) }
|
||||
onClearAppErrorsInfoData { appErrorsRecords.clear() }
|
||||
}
|
||||
}
|
||||
|
||||
override fun onHook() {
|
||||
/** 注册 */
|
||||
register()
|
||||
/** 干掉原生错误对话框 - 如果有 */
|
||||
ErrorDialogControllerClass.hook {
|
||||
injectMember {
|
||||
@@ -363,19 +298,19 @@ object FrameworkHooker : YukiBaseHooker() {
|
||||
(crashInfo.exceptionClassName.lowercase() == "native crash").also { isNativeCrash ->
|
||||
appErrorsRecords.add(
|
||||
0, AppErrorsInfoBean(
|
||||
packageName = appInfo?.packageName ?: "",
|
||||
packageName = appInfo?.packageName ?: "null",
|
||||
isNativeCrash = isNativeCrash,
|
||||
exceptionClassName = crashInfo.exceptionClassName ?: "",
|
||||
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 ?: ""
|
||||
} else crashInfo.exceptionMessage ?: "",
|
||||
throwFileName = crashInfo.throwFileName ?: "",
|
||||
throwClassName = crashInfo.throwClassName ?: "",
|
||||
throwMethodName = crashInfo.throwMethodName ?: "",
|
||||
?: 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() ?: "",
|
||||
stackTrace = crashInfo.stackTrace?.trim() ?: "null",
|
||||
timestamp = System.currentTimeMillis()
|
||||
)
|
||||
)
|
||||
|
@@ -31,7 +31,6 @@ import androidx.core.view.ViewCompat
|
||||
import androidx.viewbinding.ViewBinding
|
||||
import com.fankes.apperrorstracking.R
|
||||
import com.fankes.apperrorstracking.utils.factory.isNotSystemInDarkMode
|
||||
import com.fankes.apperrorstracking.utils.tool.FrameworkTool
|
||||
import com.highcapable.yukihookapi.hook.factory.method
|
||||
import com.highcapable.yukihookapi.hook.type.android.LayoutInflaterClass
|
||||
import java.lang.reflect.ParameterizedType
|
||||
@@ -64,18 +63,10 @@ abstract class BaseActivity<VB : ViewBinding> : AppCompatActivity() {
|
||||
window?.navigationBarColor = it
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) window?.navigationBarDividerColor = it
|
||||
}
|
||||
/** 注册 */
|
||||
FrameworkTool.registerReceiver(context = this)
|
||||
/** 装载子类 */
|
||||
onCreate()
|
||||
}
|
||||
|
||||
/** 回调 [onCreate] 方法 */
|
||||
abstract fun onCreate()
|
||||
|
||||
override fun onDestroy() {
|
||||
super.onDestroy()
|
||||
/** 取消 */
|
||||
FrameworkTool.unregisterReceiver(context = this)
|
||||
}
|
||||
}
|
@@ -34,7 +34,6 @@ import android.view.WindowManager
|
||||
import androidx.core.view.isGone
|
||||
import com.fankes.apperrorstracking.R
|
||||
import com.fankes.apperrorstracking.bean.AppErrorsInfoBean
|
||||
import com.fankes.apperrorstracking.const.Const
|
||||
import com.fankes.apperrorstracking.databinding.ActivityAppErrorsDetailBinding
|
||||
import com.fankes.apperrorstracking.locale.LocaleString
|
||||
import com.fankes.apperrorstracking.ui.activity.base.BaseActivity
|
||||
@@ -48,6 +47,9 @@ class AppErrorsDetailActivity : BaseActivity<ActivityAppErrorsDetailBinding>() {
|
||||
/** 请求保存文件回调标识 */
|
||||
private const val WRITE_REQUEST_CODE = 0
|
||||
|
||||
/** [AppErrorsInfoBean] 传值 */
|
||||
private const val EXTRA_APP_ERRORS_INFO = "app_errors_info_extra"
|
||||
|
||||
/**
|
||||
* 启动 [AppErrorsDetailActivity]
|
||||
* @param context 实例
|
||||
@@ -55,7 +57,7 @@ class AppErrorsDetailActivity : BaseActivity<ActivityAppErrorsDetailBinding>() {
|
||||
* @param isOutSide 是否从外部启动
|
||||
*/
|
||||
fun start(context: Context, appErrorsInfo: AppErrorsInfoBean, isOutSide: Boolean = false) =
|
||||
context.navigate<AppErrorsDetailActivity>(isOutSide) { putExtra(Const.EXTRA_APP_ERRORS_INFO, appErrorsInfo) }
|
||||
context.navigate<AppErrorsDetailActivity>(isOutSide) { putExtra(EXTRA_APP_ERRORS_INFO, appErrorsInfo) }
|
||||
}
|
||||
|
||||
/** 预导出的异常堆栈 */
|
||||
@@ -86,7 +88,7 @@ class AppErrorsDetailActivity : BaseActivity<ActivityAppErrorsDetailBinding>() {
|
||||
}
|
||||
|
||||
override fun onCreate() {
|
||||
val appErrorsInfo = runCatching { intent?.getSerializableExtra(Const.EXTRA_APP_ERRORS_INFO) as? AppErrorsInfoBean }.getOrNull()
|
||||
val appErrorsInfo = runCatching { intent?.getSerializableExtra(EXTRA_APP_ERRORS_INFO) as? AppErrorsInfoBean }.getOrNull()
|
||||
?: return toastAndFinish()
|
||||
binding.appInfoItem.setOnClickListener { openSelfSetting(appErrorsInfo.packageName) }
|
||||
binding.titleBackIcon.setOnClickListener { onBackPressed() }
|
||||
@@ -144,7 +146,7 @@ class AppErrorsDetailActivity : BaseActivity<ActivityAppErrorsDetailBinding>() {
|
||||
}
|
||||
|
||||
override fun onBackPressed() {
|
||||
intent?.removeExtra(Const.EXTRA_APP_ERRORS_INFO)
|
||||
intent?.removeExtra(EXTRA_APP_ERRORS_INFO)
|
||||
finish()
|
||||
}
|
||||
|
||||
|
@@ -82,7 +82,7 @@ class AppErrorsRecordActivity : BaseActivity<ActivityAppErrorsRecordBinding>() {
|
||||
}
|
||||
}
|
||||
/** 设置列表元素和 Adapter */
|
||||
binding.listView.apply {
|
||||
binding.listView.apply { // 改成 recycleview?
|
||||
adapter = object : BaseAdapter() {
|
||||
|
||||
override fun getCount() = listData.size
|
||||
|
@@ -27,8 +27,8 @@ import android.content.ComponentName
|
||||
import android.content.pm.PackageManager
|
||||
import android.os.Build
|
||||
import androidx.core.view.isVisible
|
||||
import com.fankes.apperrorstracking.BuildConfig
|
||||
import com.fankes.apperrorstracking.R
|
||||
import com.fankes.apperrorstracking.const.Const
|
||||
import com.fankes.apperrorstracking.data.DataConst
|
||||
import com.fankes.apperrorstracking.databinding.ActivityMainBinding
|
||||
import com.fankes.apperrorstracking.locale.LocaleString
|
||||
@@ -44,7 +44,7 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
|
||||
private var isModuleValied = false
|
||||
|
||||
override fun onCreate() {
|
||||
binding.mainTextVersion.text = LocaleString.moduleVersion(Const.MODULE_VERSION_NAME)
|
||||
binding.mainTextVersion.text = LocaleString.moduleVersion(BuildConfig.VERSION_NAME)
|
||||
binding.mainTextSystemVersion.text =
|
||||
LocaleString.systemVersion("${Build.VERSION.RELEASE} (API ${Build.VERSION.SDK_INT}) ${Build.DISPLAY}")
|
||||
binding.hideIconInLauncherSwitch.isChecked = modulePrefs.get(DataConst.ENABLE_HIDE_ICON)
|
||||
@@ -52,7 +52,7 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
|
||||
if (btn.isPressed.not()) return@setOnCheckedChangeListener
|
||||
modulePrefs.put(DataConst.ENABLE_HIDE_ICON, b)
|
||||
packageManager.setComponentEnabledSetting(
|
||||
ComponentName(packageName, "${Const.MODULE_PACKAGE_NAME}.Home"),
|
||||
ComponentName(packageName, "${BuildConfig.APPLICATION_ID}.Home"),
|
||||
if (b) PackageManager.COMPONENT_ENABLED_STATE_DISABLED else PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
|
||||
PackageManager.DONT_KILL_APP
|
||||
)
|
||||
@@ -92,7 +92,7 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
|
||||
super.onResume()
|
||||
/** 刷新模块状态 */
|
||||
refreshModuleStatus()
|
||||
/** 发送广播检查模块激活状态 */
|
||||
/** 检查模块激活状态 */
|
||||
FrameworkTool.checkingActivated(context = this) { isValied ->
|
||||
isModuleValied = isValied
|
||||
refreshModuleStatus()
|
||||
|
@@ -34,8 +34,8 @@ import android.net.Uri
|
||||
import android.provider.Settings
|
||||
import android.widget.Toast
|
||||
import androidx.core.content.res.ResourcesCompat
|
||||
import com.fankes.apperrorstracking.BuildConfig
|
||||
import com.fankes.apperrorstracking.R
|
||||
import com.fankes.apperrorstracking.const.Const
|
||||
import com.fankes.apperrorstracking.locale.LocaleString
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
import com.highcapable.yukihookapi.hook.factory.field
|
||||
@@ -135,14 +135,14 @@ fun Context.snake(msg: String, actionText: String = "", callback: () -> Unit = {
|
||||
*
|
||||
* [T] 为指定的 [Activity]
|
||||
* @param isOutSide 是否从外部启动
|
||||
* @param callback 回调 [Intent] 方法体
|
||||
* @param initiate [Intent] 方法体
|
||||
*/
|
||||
inline fun <reified T : Activity> Context.navigate(isOutSide: Boolean = false, callback: Intent.() -> Unit = {}) = runCatching {
|
||||
inline fun <reified T : Activity> Context.navigate(isOutSide: Boolean = false, initiate: Intent.() -> Unit = {}) = runCatching {
|
||||
startActivity((if (isOutSide) Intent() else Intent(if (this is Service) applicationContext else this, T::class.java)).apply {
|
||||
flags = if (this@navigate !is Activity) Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
|
||||
else Intent.FLAG_ACTIVITY_NEW_TASK
|
||||
if (isOutSide) component = ComponentName(Const.MODULE_PACKAGE_NAME, T::class.java.name)
|
||||
callback(this)
|
||||
if (isOutSide) component = ComponentName(BuildConfig.APPLICATION_ID, T::class.java.name)
|
||||
initiate(this)
|
||||
})
|
||||
}.onFailure { toast(msg = "Start ${T::class.java.name} failed") }
|
||||
|
||||
|
@@ -23,58 +23,80 @@
|
||||
|
||||
package com.fankes.apperrorstracking.utils.tool
|
||||
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.IntentFilter
|
||||
import com.fankes.apperrorstracking.bean.AppErrorsInfoBean
|
||||
import com.fankes.apperrorstracking.const.Const
|
||||
import com.fankes.apperrorstracking.locale.LocaleString
|
||||
import com.fankes.apperrorstracking.utils.factory.execShell
|
||||
import com.fankes.apperrorstracking.utils.factory.isRootAccess
|
||||
import com.fankes.apperrorstracking.utils.factory.showDialog
|
||||
import com.fankes.apperrorstracking.utils.factory.snake
|
||||
import com.highcapable.yukihookapi.hook.log.loggerE
|
||||
import java.io.Serializable
|
||||
import com.highcapable.yukihookapi.hook.factory.dataChannel
|
||||
import com.highcapable.yukihookapi.hook.param.PackageParam
|
||||
import com.highcapable.yukihookapi.hook.xposed.channel.data.ChannelData
|
||||
|
||||
/**
|
||||
* 系统框架控制工具
|
||||
*/
|
||||
object FrameworkTool {
|
||||
|
||||
/** 回调模块激活状态 */
|
||||
private var onModuleActiveStatusCallback: ((Boolean) -> Unit)? = null
|
||||
/** 系统框架包名 */
|
||||
private const val SYSTEM_FRAMEWORK_NAME = "android"
|
||||
|
||||
/** 回调获取的 APP 异常信息 */
|
||||
private var onAppErrorsInfoDataCallback: ((ArrayList<AppErrorsInfoBean>) -> Unit)? = null
|
||||
private const val CALL_APP_ERRORS_DATA_GET = "call_app_errors_data_get"
|
||||
private const val CALL_APP_ERRORS_DATA_REMOVE_RESULT = "call_app_errors_data_remove_result"
|
||||
private const val CALL_APP_ERRORS_DATA_CLEAR = "call_app_errors_data_clear"
|
||||
private const val CALL_APP_ERRORS_DATA_CLEAR_RESULT = "call_app_errors_data_clear_result"
|
||||
|
||||
/** 回调 APP 异常信息是否移除 */
|
||||
private var onRemoveAppErrorsInfoDataCallback: (() -> Unit)? = null
|
||||
private val CALL_APP_ERRORS_DATA_REMOVE = ChannelData<AppErrorsInfoBean>("call_app_errors_data_remove")
|
||||
private val CALL_APP_ERRORS_DATA_GET_RESULT = ChannelData<ArrayList<AppErrorsInfoBean>>("call_app_errors_data_get_result")
|
||||
|
||||
/** 回调 APP 异常信息是否清空 */
|
||||
private var onClearAppErrorsInfoDataCallback: (() -> Unit)? = null
|
||||
/**
|
||||
* 宿主注册监听
|
||||
*/
|
||||
object Host {
|
||||
|
||||
/** 模块广播接收器 */
|
||||
private val moduleHandlerReceiver by lazy {
|
||||
object : BroadcastReceiver() {
|
||||
override fun onReceive(context: Context?, intent: Intent?) {
|
||||
if (intent == null) return
|
||||
runCatching {
|
||||
intent.getStringExtra(Const.KEY_MODULE_HOST_FETCH)?.also {
|
||||
if (it.isNotBlank()) when (it) {
|
||||
Const.TYPE_MODULE_VERSION_VERIFY ->
|
||||
onModuleActiveStatusCallback?.invoke(intent.getStringExtra(Const.TAG_MODULE_VERSION_VERIFY) == Const.MODULE_VERSION_VERIFY)
|
||||
Const.TYPE_APP_ERRORS_DATA_GET -> runCatching {
|
||||
onAppErrorsInfoDataCallback?.invoke(
|
||||
intent.getSerializableExtra(Const.TAG_APP_ERRORS_DATA_GET_CONTENT) as ArrayList<AppErrorsInfoBean>
|
||||
)
|
||||
}.onFailure { onAppErrorsInfoDataCallback?.invoke(arrayListOf()) }
|
||||
Const.TYPE_APP_ERRORS_DATA_REMOVE -> onRemoveAppErrorsInfoDataCallback?.invoke()
|
||||
Const.TYPE_APP_ERRORS_DATA_CLEAR -> onClearAppErrorsInfoDataCallback?.invoke()
|
||||
else -> {}
|
||||
}
|
||||
}
|
||||
}.onFailure { loggerE(msg = "Cannot receiver message, please restart system", e = it) }
|
||||
/** [PackageParam] 实例 */
|
||||
private var instance: PackageParam? = null
|
||||
|
||||
/**
|
||||
* 注册监听
|
||||
* @param instance 实例
|
||||
* @param initiate 实例方法体
|
||||
* @return [Host]
|
||||
*/
|
||||
fun with(instance: PackageParam, initiate: Host.() -> Unit) = apply { this.instance = instance }.apply(initiate)
|
||||
|
||||
/**
|
||||
* 监听发送 APP 异常信息数组
|
||||
* @param result 回调数据
|
||||
*/
|
||||
fun onPushAppErrorsInfoData(result: () -> ArrayList<AppErrorsInfoBean>) {
|
||||
instance?.dataChannel?.with { wait(CALL_APP_ERRORS_DATA_GET) { put(CALL_APP_ERRORS_DATA_GET_RESULT, result()) } }
|
||||
}
|
||||
|
||||
/**
|
||||
* 监听移除指定 APP 异常信息
|
||||
* @param result 回调数据
|
||||
*/
|
||||
fun onRemoveAppErrorsInfoData(result: (AppErrorsInfoBean) -> Unit) {
|
||||
instance?.dataChannel?.with {
|
||||
wait(CALL_APP_ERRORS_DATA_REMOVE) {
|
||||
result(it)
|
||||
put(CALL_APP_ERRORS_DATA_REMOVE_RESULT)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 监听清空 APP 异常信息数组
|
||||
* @param callback 回调
|
||||
*/
|
||||
fun onClearAppErrorsInfoData(callback: () -> Unit) {
|
||||
instance?.dataChannel?.with {
|
||||
wait(CALL_APP_ERRORS_DATA_CLEAR) {
|
||||
callback()
|
||||
put(CALL_APP_ERRORS_DATA_CLEAR_RESULT)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -100,83 +122,47 @@ object FrameworkTool {
|
||||
cancelButton()
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送广播
|
||||
* @param context 实例
|
||||
* @param type 类型
|
||||
* @param key 可选传值
|
||||
* @param value 可选传值
|
||||
*/
|
||||
private fun pushReceiver(context: Context, type: String, key: String = "", value: Any = "") {
|
||||
context.sendBroadcast(Intent().apply {
|
||||
action = Const.ACTION_HOST_HANDLER_RECEIVER
|
||||
putExtra(Const.KEY_MODULE_HOST_FETCH, type)
|
||||
if (key.isNotBlank()) putExtra(
|
||||
key, when (value) {
|
||||
is String -> value
|
||||
is Int -> value
|
||||
is Boolean -> value
|
||||
is Serializable -> value
|
||||
else -> error("value is not allowed")
|
||||
}
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查模块是否激活
|
||||
* @param context 实例
|
||||
* @param it 成功后回调 - ([Boolean] 是否激活)
|
||||
* @param result 成功后回调
|
||||
*/
|
||||
fun checkingActivated(context: Context, it: (Boolean) -> Unit) {
|
||||
onModuleActiveStatusCallback = it
|
||||
pushReceiver(context, Const.TYPE_MODULE_VERSION_VERIFY)
|
||||
}
|
||||
fun checkingActivated(context: Context, result: (Boolean) -> Unit) = context.dataChannel(SYSTEM_FRAMEWORK_NAME).checkingVersionEquals(result)
|
||||
|
||||
/**
|
||||
* 获取 APP 异常信息数组
|
||||
* @param context 实例
|
||||
* @param it 回调数据
|
||||
* @param result 回调数据
|
||||
*/
|
||||
fun fetchAppErrorsInfoData(context: Context, it: (ArrayList<AppErrorsInfoBean>) -> Unit) {
|
||||
onAppErrorsInfoDataCallback = it
|
||||
pushReceiver(context, Const.TYPE_APP_ERRORS_DATA_GET)
|
||||
fun fetchAppErrorsInfoData(context: Context, result: (ArrayList<AppErrorsInfoBean>) -> Unit) {
|
||||
context.dataChannel(SYSTEM_FRAMEWORK_NAME).with {
|
||||
wait(CALL_APP_ERRORS_DATA_GET_RESULT) { result(it) }
|
||||
put(CALL_APP_ERRORS_DATA_GET)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 移除指定 APP 异常信息
|
||||
* @param context 实例
|
||||
* @param appErrorsInfo 指定 APP 异常信息
|
||||
* @param it 成功后回调
|
||||
* @param callback 成功后回调
|
||||
*/
|
||||
fun removeAppErrorsInfoData(context: Context, appErrorsInfo: AppErrorsInfoBean, it: () -> Unit) {
|
||||
onRemoveAppErrorsInfoDataCallback = it
|
||||
pushReceiver(context, Const.TYPE_APP_ERRORS_DATA_REMOVE, Const.TAG_APP_ERRORS_DATA_REMOVE_CONTENT, appErrorsInfo)
|
||||
fun removeAppErrorsInfoData(context: Context, appErrorsInfo: AppErrorsInfoBean, callback: () -> Unit) {
|
||||
context.dataChannel(SYSTEM_FRAMEWORK_NAME).with {
|
||||
wait(CALL_APP_ERRORS_DATA_REMOVE_RESULT) { callback() }
|
||||
put(CALL_APP_ERRORS_DATA_REMOVE, appErrorsInfo)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 清空 APP 异常信息数组
|
||||
* @param context 实例
|
||||
* @param it 成功后回调
|
||||
* @param callback 成功后回调
|
||||
*/
|
||||
fun clearAppErrorsInfoData(context: Context, it: () -> Unit) {
|
||||
onClearAppErrorsInfoDataCallback = it
|
||||
pushReceiver(context, Const.TYPE_APP_ERRORS_DATA_CLEAR)
|
||||
}
|
||||
|
||||
/**
|
||||
* 注册广播
|
||||
* @param context 实例
|
||||
*/
|
||||
fun registerReceiver(context: Context) = runCatching {
|
||||
context.registerReceiver(moduleHandlerReceiver, IntentFilter().apply { addAction(Const.ACTION_MODULE_HANDLER_RECEIVER) })
|
||||
}
|
||||
|
||||
/**
|
||||
* 取消注册
|
||||
* @param context 实例
|
||||
*/
|
||||
fun unregisterReceiver(context: Context) = runCatching {
|
||||
context.unregisterReceiver(moduleHandlerReceiver)
|
||||
fun clearAppErrorsInfoData(context: Context, callback: () -> Unit) {
|
||||
context.dataChannel(SYSTEM_FRAMEWORK_NAME).with {
|
||||
wait(CALL_APP_ERRORS_DATA_CLEAR_RESULT) { callback() }
|
||||
put(CALL_APP_ERRORS_DATA_CLEAR)
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user