Merge module and host receiver to new api

This commit is contained in:
2022-06-01 00:33:10 +08:00
parent bc4813e106
commit 16d3543696
8 changed files with 119 additions and 283 deletions

View File

@@ -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"
}

View File

@@ -24,10 +24,8 @@
package com.fankes.apperrorstracking.hook.entity package com.fankes.apperrorstracking.hook.entity
import android.app.ApplicationErrorReport import android.app.ApplicationErrorReport
import android.content.BroadcastReceiver
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.content.IntentFilter
import android.content.pm.ApplicationInfo import android.content.pm.ApplicationInfo
import android.graphics.Color import android.graphics.Color
import android.os.Message import android.os.Message
@@ -41,18 +39,17 @@ import android.widget.TextView
import androidx.core.content.res.ResourcesCompat import androidx.core.content.res.ResourcesCompat
import com.fankes.apperrorstracking.R import com.fankes.apperrorstracking.R
import com.fankes.apperrorstracking.bean.AppErrorsInfoBean import com.fankes.apperrorstracking.bean.AppErrorsInfoBean
import com.fankes.apperrorstracking.const.Const
import com.fankes.apperrorstracking.locale.LocaleString import com.fankes.apperrorstracking.locale.LocaleString
import com.fankes.apperrorstracking.ui.activity.errors.AppErrorsDetailActivity import com.fankes.apperrorstracking.ui.activity.errors.AppErrorsDetailActivity
import com.fankes.apperrorstracking.utils.drawable.drawabletoolbox.DrawableBuilder import com.fankes.apperrorstracking.utils.drawable.drawabletoolbox.DrawableBuilder
import com.fankes.apperrorstracking.utils.factory.* 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.bean.VariousClass
import com.highcapable.yukihookapi.hook.entity.YukiBaseHooker import com.highcapable.yukihookapi.hook.entity.YukiBaseHooker
import com.highcapable.yukihookapi.hook.factory.field import com.highcapable.yukihookapi.hook.factory.field
import com.highcapable.yukihookapi.hook.factory.hasMethod import com.highcapable.yukihookapi.hook.factory.hasMethod
import com.highcapable.yukihookapi.hook.factory.method import com.highcapable.yukihookapi.hook.factory.method
import com.highcapable.yukihookapi.hook.log.loggerE import com.highcapable.yukihookapi.hook.log.loggerE
import com.highcapable.yukihookapi.hook.type.android.ActivityThreadClass
import com.highcapable.yukihookapi.hook.type.android.MessageClass import com.highcapable.yukihookapi.hook.type.android.MessageClass
object FrameworkHooker : YukiBaseHooker() { object FrameworkHooker : YukiBaseHooker() {
@@ -87,75 +84,6 @@ object FrameworkHooker : YukiBaseHooker() {
/** 已记录的 APP 异常信息数组 - 直到重新启动 */ /** 已记录的 APP 异常信息数组 - 直到重新启动 */
private val appErrorsRecords = arrayListOf<AppErrorsInfoBean>() 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 错误信息 * 获取最新的 APP 错误信息
* @param packageName 包名 * @param packageName 包名
@@ -195,17 +123,24 @@ object FrameworkHooker : YukiBaseHooker() {
setOnClickListener { it() } setOnClickListener { it() }
} }
override fun onHook() { /** 注册 */
/** 注入全局监听 */ private fun register() {
ActivityThreadClass.hook { onAppLifecycle {
injectMember { /** 解锁后清空已记录的忽略错误 APP */
method { registerReceiver(Intent.ACTION_USER_PRESENT) { _, _ -> ignoredErrorsIfUnlockApps.clear() }
name = "currentApplication" /** 刷新模块 Resources 缓存 */
emptyParam() registerReceiver(Intent.ACTION_LOCALE_CHANGED) { _, _ -> refreshModuleAppResources() }
}
afterHook { result<Context>()?.let { registerReceiver(it) } }
}
} }
FrameworkTool.Host.with(instance = this) {
onPushAppErrorsInfoData { appErrorsRecords }
onRemoveAppErrorsInfoData { appErrorsRecords.remove(it) }
onClearAppErrorsInfoData { appErrorsRecords.clear() }
}
}
override fun onHook() {
/** 注册 */
register()
/** 干掉原生错误对话框 - 如果有 */ /** 干掉原生错误对话框 - 如果有 */
ErrorDialogControllerClass.hook { ErrorDialogControllerClass.hook {
injectMember { injectMember {
@@ -363,19 +298,19 @@ object FrameworkHooker : YukiBaseHooker() {
(crashInfo.exceptionClassName.lowercase() == "native crash").also { isNativeCrash -> (crashInfo.exceptionClassName.lowercase() == "native crash").also { isNativeCrash ->
appErrorsRecords.add( appErrorsRecords.add(
0, AppErrorsInfoBean( 0, AppErrorsInfoBean(
packageName = appInfo?.packageName ?: "", packageName = appInfo?.packageName ?: "null",
isNativeCrash = isNativeCrash, isNativeCrash = isNativeCrash,
exceptionClassName = crashInfo.exceptionClassName ?: "", exceptionClassName = crashInfo.exceptionClassName ?: "null",
exceptionMessage = if (isNativeCrash) crashInfo.stackTrace.let { exceptionMessage = if (isNativeCrash) crashInfo.stackTrace.let {
if (it.contains(other = "Abort message: '")) if (it.contains(other = "Abort message: '"))
runCatching { it.split("Abort message: '")[1].split("'")[0] }.getOrNull() runCatching { it.split("Abort message: '")[1].split("'")[0] }.getOrNull()
?: crashInfo.exceptionMessage ?: "" else crashInfo.exceptionMessage ?: "" ?: crashInfo.exceptionMessage ?: "" else crashInfo.exceptionMessage ?: "null"
} else crashInfo.exceptionMessage ?: "", } else crashInfo.exceptionMessage ?: "null",
throwFileName = crashInfo.throwFileName ?: "", throwFileName = crashInfo.throwFileName ?: "null",
throwClassName = crashInfo.throwClassName ?: "", throwClassName = crashInfo.throwClassName ?: "null",
throwMethodName = crashInfo.throwMethodName ?: "", throwMethodName = crashInfo.throwMethodName ?: "null",
throwLineNumber = crashInfo.throwLineNumber, throwLineNumber = crashInfo.throwLineNumber,
stackTrace = crashInfo.stackTrace?.trim() ?: "", stackTrace = crashInfo.stackTrace?.trim() ?: "null",
timestamp = System.currentTimeMillis() timestamp = System.currentTimeMillis()
) )
) )

View File

@@ -31,7 +31,6 @@ import androidx.core.view.ViewCompat
import androidx.viewbinding.ViewBinding 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.tool.FrameworkTool
import com.highcapable.yukihookapi.hook.factory.method import com.highcapable.yukihookapi.hook.factory.method
import com.highcapable.yukihookapi.hook.type.android.LayoutInflaterClass import com.highcapable.yukihookapi.hook.type.android.LayoutInflaterClass
import java.lang.reflect.ParameterizedType import java.lang.reflect.ParameterizedType
@@ -64,18 +63,10 @@ abstract class BaseActivity<VB : ViewBinding> : AppCompatActivity() {
window?.navigationBarColor = it window?.navigationBarColor = it
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) window?.navigationBarDividerColor = it if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) window?.navigationBarDividerColor = it
} }
/** 注册 */
FrameworkTool.registerReceiver(context = this)
/** 装载子类 */ /** 装载子类 */
onCreate() onCreate()
} }
/** 回调 [onCreate] 方法 */ /** 回调 [onCreate] 方法 */
abstract fun onCreate() abstract fun onCreate()
override fun onDestroy() {
super.onDestroy()
/** 取消 */
FrameworkTool.unregisterReceiver(context = this)
}
} }

View File

@@ -34,7 +34,6 @@ import android.view.WindowManager
import androidx.core.view.isGone import androidx.core.view.isGone
import com.fankes.apperrorstracking.R import com.fankes.apperrorstracking.R
import com.fankes.apperrorstracking.bean.AppErrorsInfoBean import com.fankes.apperrorstracking.bean.AppErrorsInfoBean
import com.fankes.apperrorstracking.const.Const
import com.fankes.apperrorstracking.databinding.ActivityAppErrorsDetailBinding import com.fankes.apperrorstracking.databinding.ActivityAppErrorsDetailBinding
import com.fankes.apperrorstracking.locale.LocaleString import com.fankes.apperrorstracking.locale.LocaleString
import com.fankes.apperrorstracking.ui.activity.base.BaseActivity import com.fankes.apperrorstracking.ui.activity.base.BaseActivity
@@ -48,6 +47,9 @@ class AppErrorsDetailActivity : BaseActivity<ActivityAppErrorsDetailBinding>() {
/** 请求保存文件回调标识 */ /** 请求保存文件回调标识 */
private const val WRITE_REQUEST_CODE = 0 private const val WRITE_REQUEST_CODE = 0
/** [AppErrorsInfoBean] 传值 */
private const val EXTRA_APP_ERRORS_INFO = "app_errors_info_extra"
/** /**
* 启动 [AppErrorsDetailActivity] * 启动 [AppErrorsDetailActivity]
* @param context 实例 * @param context 实例
@@ -55,7 +57,7 @@ class AppErrorsDetailActivity : BaseActivity<ActivityAppErrorsDetailBinding>() {
* @param isOutSide 是否从外部启动 * @param isOutSide 是否从外部启动
*/ */
fun start(context: Context, appErrorsInfo: AppErrorsInfoBean, isOutSide: Boolean = false) = 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() { 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() ?: return toastAndFinish()
binding.appInfoItem.setOnClickListener { openSelfSetting(appErrorsInfo.packageName) } binding.appInfoItem.setOnClickListener { openSelfSetting(appErrorsInfo.packageName) }
binding.titleBackIcon.setOnClickListener { onBackPressed() } binding.titleBackIcon.setOnClickListener { onBackPressed() }
@@ -144,7 +146,7 @@ class AppErrorsDetailActivity : BaseActivity<ActivityAppErrorsDetailBinding>() {
} }
override fun onBackPressed() { override fun onBackPressed() {
intent?.removeExtra(Const.EXTRA_APP_ERRORS_INFO) intent?.removeExtra(EXTRA_APP_ERRORS_INFO)
finish() finish()
} }

View File

@@ -82,7 +82,7 @@ class AppErrorsRecordActivity : BaseActivity<ActivityAppErrorsRecordBinding>() {
} }
} }
/** 设置列表元素和 Adapter */ /** 设置列表元素和 Adapter */
binding.listView.apply { binding.listView.apply { // 改成 recycleview?
adapter = object : BaseAdapter() { adapter = object : BaseAdapter() {
override fun getCount() = listData.size override fun getCount() = listData.size

View File

@@ -27,8 +27,8 @@ import android.content.ComponentName
import android.content.pm.PackageManager import android.content.pm.PackageManager
import android.os.Build import android.os.Build
import androidx.core.view.isVisible import androidx.core.view.isVisible
import com.fankes.apperrorstracking.BuildConfig
import com.fankes.apperrorstracking.R import com.fankes.apperrorstracking.R
import com.fankes.apperrorstracking.const.Const
import com.fankes.apperrorstracking.data.DataConst import com.fankes.apperrorstracking.data.DataConst
import com.fankes.apperrorstracking.databinding.ActivityMainBinding import com.fankes.apperrorstracking.databinding.ActivityMainBinding
import com.fankes.apperrorstracking.locale.LocaleString import com.fankes.apperrorstracking.locale.LocaleString
@@ -44,7 +44,7 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
private var isModuleValied = false private var isModuleValied = false
override fun onCreate() { override fun onCreate() {
binding.mainTextVersion.text = LocaleString.moduleVersion(Const.MODULE_VERSION_NAME) binding.mainTextVersion.text = LocaleString.moduleVersion(BuildConfig.VERSION_NAME)
binding.mainTextSystemVersion.text = binding.mainTextSystemVersion.text =
LocaleString.systemVersion("${Build.VERSION.RELEASE} (API ${Build.VERSION.SDK_INT}) ${Build.DISPLAY}") LocaleString.systemVersion("${Build.VERSION.RELEASE} (API ${Build.VERSION.SDK_INT}) ${Build.DISPLAY}")
binding.hideIconInLauncherSwitch.isChecked = modulePrefs.get(DataConst.ENABLE_HIDE_ICON) binding.hideIconInLauncherSwitch.isChecked = modulePrefs.get(DataConst.ENABLE_HIDE_ICON)
@@ -52,7 +52,7 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
if (btn.isPressed.not()) return@setOnCheckedChangeListener if (btn.isPressed.not()) return@setOnCheckedChangeListener
modulePrefs.put(DataConst.ENABLE_HIDE_ICON, b) modulePrefs.put(DataConst.ENABLE_HIDE_ICON, b)
packageManager.setComponentEnabledSetting( 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, if (b) PackageManager.COMPONENT_ENABLED_STATE_DISABLED else PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
PackageManager.DONT_KILL_APP PackageManager.DONT_KILL_APP
) )
@@ -92,7 +92,7 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
super.onResume() super.onResume()
/** 刷新模块状态 */ /** 刷新模块状态 */
refreshModuleStatus() refreshModuleStatus()
/** 发送广播检查模块激活状态 */ /** 检查模块激活状态 */
FrameworkTool.checkingActivated(context = this) { isValied -> FrameworkTool.checkingActivated(context = this) { isValied ->
isModuleValied = isValied isModuleValied = isValied
refreshModuleStatus() refreshModuleStatus()

View File

@@ -34,8 +34,8 @@ import android.net.Uri
import android.provider.Settings import android.provider.Settings
import android.widget.Toast import android.widget.Toast
import androidx.core.content.res.ResourcesCompat import androidx.core.content.res.ResourcesCompat
import com.fankes.apperrorstracking.BuildConfig
import com.fankes.apperrorstracking.R import com.fankes.apperrorstracking.R
import com.fankes.apperrorstracking.const.Const
import com.fankes.apperrorstracking.locale.LocaleString import com.fankes.apperrorstracking.locale.LocaleString
import com.google.android.material.snackbar.Snackbar import com.google.android.material.snackbar.Snackbar
import com.highcapable.yukihookapi.hook.factory.field import com.highcapable.yukihookapi.hook.factory.field
@@ -135,14 +135,14 @@ fun Context.snake(msg: String, actionText: String = "", callback: () -> Unit = {
* *
* [T] 为指定的 [Activity] * [T] 为指定的 [Activity]
* @param isOutSide 是否从外部启动 * @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 { 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 flags = if (this@navigate !is Activity) Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
else Intent.FLAG_ACTIVITY_NEW_TASK else Intent.FLAG_ACTIVITY_NEW_TASK
if (isOutSide) component = ComponentName(Const.MODULE_PACKAGE_NAME, T::class.java.name) if (isOutSide) component = ComponentName(BuildConfig.APPLICATION_ID, T::class.java.name)
callback(this) initiate(this)
}) })
}.onFailure { toast(msg = "Start ${T::class.java.name} failed") } }.onFailure { toast(msg = "Start ${T::class.java.name} failed") }

View File

@@ -23,58 +23,80 @@
package com.fankes.apperrorstracking.utils.tool package com.fankes.apperrorstracking.utils.tool
import android.content.BroadcastReceiver
import android.content.Context import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import com.fankes.apperrorstracking.bean.AppErrorsInfoBean import com.fankes.apperrorstracking.bean.AppErrorsInfoBean
import com.fankes.apperrorstracking.const.Const
import com.fankes.apperrorstracking.locale.LocaleString import com.fankes.apperrorstracking.locale.LocaleString
import com.fankes.apperrorstracking.utils.factory.execShell import com.fankes.apperrorstracking.utils.factory.execShell
import com.fankes.apperrorstracking.utils.factory.isRootAccess import com.fankes.apperrorstracking.utils.factory.isRootAccess
import com.fankes.apperrorstracking.utils.factory.showDialog import com.fankes.apperrorstracking.utils.factory.showDialog
import com.fankes.apperrorstracking.utils.factory.snake import com.fankes.apperrorstracking.utils.factory.snake
import com.highcapable.yukihookapi.hook.log.loggerE import com.highcapable.yukihookapi.hook.factory.dataChannel
import java.io.Serializable import com.highcapable.yukihookapi.hook.param.PackageParam
import com.highcapable.yukihookapi.hook.xposed.channel.data.ChannelData
/** /**
* 系统框架控制工具 * 系统框架控制工具
*/ */
object FrameworkTool { object FrameworkTool {
/** 回调模块激活状态 */ /** 系统框架包名 */
private var onModuleActiveStatusCallback: ((Boolean) -> Unit)? = null private const val SYSTEM_FRAMEWORK_NAME = "android"
/** 回调获取的 APP 异常信息 */ private const val CALL_APP_ERRORS_DATA_GET = "call_app_errors_data_get"
private var onAppErrorsInfoDataCallback: ((ArrayList<AppErrorsInfoBean>) -> Unit)? = null 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 val CALL_APP_ERRORS_DATA_REMOVE = ChannelData<AppErrorsInfoBean>("call_app_errors_data_remove")
private var onRemoveAppErrorsInfoDataCallback: (() -> Unit)? = null 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 {
/** 模块广播接收器 */ /** [PackageParam] 实例 */
private val moduleHandlerReceiver by lazy { private var instance: PackageParam? = null
object : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) { /**
if (intent == null) return * 注册监听
runCatching { * @param instance 实例
intent.getStringExtra(Const.KEY_MODULE_HOST_FETCH)?.also { * @param initiate 实例方法体
if (it.isNotBlank()) when (it) { * @return [Host]
Const.TYPE_MODULE_VERSION_VERIFY -> */
onModuleActiveStatusCallback?.invoke(intent.getStringExtra(Const.TAG_MODULE_VERSION_VERIFY) == Const.MODULE_VERSION_VERIFY) fun with(instance: PackageParam, initiate: Host.() -> Unit) = apply { this.instance = instance }.apply(initiate)
Const.TYPE_APP_ERRORS_DATA_GET -> runCatching {
onAppErrorsInfoDataCallback?.invoke( /**
intent.getSerializableExtra(Const.TAG_APP_ERRORS_DATA_GET_CONTENT) as ArrayList<AppErrorsInfoBean> * 监听发送 APP 异常信息数组
) * @param result 回调数据
}.onFailure { onAppErrorsInfoDataCallback?.invoke(arrayListOf()) } */
Const.TYPE_APP_ERRORS_DATA_REMOVE -> onRemoveAppErrorsInfoDataCallback?.invoke() fun onPushAppErrorsInfoData(result: () -> ArrayList<AppErrorsInfoBean>) {
Const.TYPE_APP_ERRORS_DATA_CLEAR -> onClearAppErrorsInfoDataCallback?.invoke() instance?.dataChannel?.with { wait(CALL_APP_ERRORS_DATA_GET) { put(CALL_APP_ERRORS_DATA_GET_RESULT, result()) } }
else -> {} }
}
} /**
}.onFailure { loggerE(msg = "Cannot receiver message, please restart system", e = it) } * 监听移除指定 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() 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 context 实例
* @param it 成功后回调 - ([Boolean] 是否激活) * @param result 成功后回调
*/ */
fun checkingActivated(context: Context, it: (Boolean) -> Unit) { fun checkingActivated(context: Context, result: (Boolean) -> Unit) = context.dataChannel(SYSTEM_FRAMEWORK_NAME).checkingVersionEquals(result)
onModuleActiveStatusCallback = it
pushReceiver(context, Const.TYPE_MODULE_VERSION_VERIFY)
}
/** /**
* 获取 APP 异常信息数组 * 获取 APP 异常信息数组
* @param context 实例 * @param context 实例
* @param it 回调数据 * @param result 回调数据
*/ */
fun fetchAppErrorsInfoData(context: Context, it: (ArrayList<AppErrorsInfoBean>) -> Unit) { fun fetchAppErrorsInfoData(context: Context, result: (ArrayList<AppErrorsInfoBean>) -> Unit) {
onAppErrorsInfoDataCallback = it context.dataChannel(SYSTEM_FRAMEWORK_NAME).with {
pushReceiver(context, Const.TYPE_APP_ERRORS_DATA_GET) wait(CALL_APP_ERRORS_DATA_GET_RESULT) { result(it) }
put(CALL_APP_ERRORS_DATA_GET)
}
} }
/** /**
* 移除指定 APP 异常信息 * 移除指定 APP 异常信息
* @param context 实例 * @param context 实例
* @param appErrorsInfo 指定 APP 异常信息 * @param appErrorsInfo 指定 APP 异常信息
* @param it 成功后回调 * @param callback 成功后回调
*/ */
fun removeAppErrorsInfoData(context: Context, appErrorsInfo: AppErrorsInfoBean, it: () -> Unit) { fun removeAppErrorsInfoData(context: Context, appErrorsInfo: AppErrorsInfoBean, callback: () -> Unit) {
onRemoveAppErrorsInfoDataCallback = it context.dataChannel(SYSTEM_FRAMEWORK_NAME).with {
pushReceiver(context, Const.TYPE_APP_ERRORS_DATA_REMOVE, Const.TAG_APP_ERRORS_DATA_REMOVE_CONTENT, appErrorsInfo) wait(CALL_APP_ERRORS_DATA_REMOVE_RESULT) { callback() }
put(CALL_APP_ERRORS_DATA_REMOVE, appErrorsInfo)
}
} }
/** /**
* 清空 APP 异常信息数组 * 清空 APP 异常信息数组
* @param context 实例 * @param context 实例
* @param it 成功后回调 * @param callback 成功后回调
*/ */
fun clearAppErrorsInfoData(context: Context, it: () -> Unit) { fun clearAppErrorsInfoData(context: Context, callback: () -> Unit) {
onClearAppErrorsInfoDataCallback = it context.dataChannel(SYSTEM_FRAMEWORK_NAME).with {
pushReceiver(context, Const.TYPE_APP_ERRORS_DATA_CLEAR) wait(CALL_APP_ERRORS_DATA_CLEAR_RESULT) { callback() }
} put(CALL_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)
} }
} }