refactor: migrate to YukiHookAPI new usage

This commit is contained in:
2023-10-07 20:51:34 +08:00
parent 4436815525
commit ea0b46020f
9 changed files with 239 additions and 342 deletions

View File

@@ -1,7 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.fankes.tsbattery">
xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

View File

@@ -29,7 +29,7 @@ import com.highcapable.yukihookapi.hook.factory.configs
import com.highcapable.yukihookapi.hook.factory.encase
import com.highcapable.yukihookapi.hook.xposed.proxy.IYukiHookXposedInit
@InjectYukiHookWithXposed(isUsingResourcesHook = false)
@InjectYukiHookWithXposed
object HookEntry : IYukiHookXposedInit {
/** 是否完全支持当前版本 */

View File

@@ -52,10 +52,7 @@ import com.highcapable.yukihookapi.hook.factory.injectModuleAppResources
import com.highcapable.yukihookapi.hook.factory.method
import com.highcapable.yukihookapi.hook.factory.processName
import com.highcapable.yukihookapi.hook.factory.registerModuleAppActivities
import com.highcapable.yukihookapi.hook.log.loggerD
import com.highcapable.yukihookapi.hook.log.loggerE
import com.highcapable.yukihookapi.hook.log.loggerI
import com.highcapable.yukihookapi.hook.log.loggerW
import com.highcapable.yukihookapi.hook.log.YLog
import com.highcapable.yukihookapi.hook.type.android.BuildClass
import com.highcapable.yukihookapi.hook.type.android.BundleClass
import com.highcapable.yukihookapi.hook.type.android.ContextClass
@@ -78,40 +75,48 @@ import java.lang.reflect.Proxy
object QQTIMHooker : YukiBaseHooker() {
/** QQ、TIM 存在的类 */
const val JumpActivityClass = "${PackageName.QQ}.activity.JumpActivity"
const val JumpActivityClassName = "${PackageName.QQ}.activity.JumpActivity"
/** QQ、TIM 存在的类 */
private val JumpActivityClass by lazyClassOrNull(JumpActivityClassName)
/** QQ、TIM 存在的类 (NT 版本不再存在) */
private const val QQSettingSettingActivityClass = "${PackageName.QQ}.activity.QQSettingSettingActivity"
private val QQSettingSettingActivityClass by lazyClassOrNull("${PackageName.QQ}.activity.QQSettingSettingActivity")
/** QQ 新版存在的类 (Pad 模式 - NT 版本不再存在) */
private const val QQSettingSettingFragmentClass = "${PackageName.QQ}.fragment.QQSettingSettingFragment"
private val QQSettingSettingFragmentClass by lazyClassOrNull("${PackageName.QQ}.fragment.QQSettingSettingFragment")
/** QQ、TIM 存在的类 (NT 版本不再存在) */
private const val AboutActivityClass = "${PackageName.QQ}.activity.AboutActivity"
private val AboutActivityClass by lazyClassOrNull("${PackageName.QQ}.activity.AboutActivity")
/** QQ 新版本存在的类 */
private const val GeneralSettingActivityClass = "${PackageName.QQ}.activity.GeneralSettingActivity"
private val GeneralSettingActivityClass by lazyClassOrNull("${PackageName.QQ}.activity.GeneralSettingActivity")
/** QQ 新版本 (NT) 存在的类 */
private const val MainSettingFragmentClass = "${PackageName.QQ}.setting.main.MainSettingFragment"
private val MainSettingFragmentClass by lazyClassOrNull("${PackageName.QQ}.setting.main.MainSettingFragment")
/** QQ 新版本 (NT) 存在的类 */
private const val MainSettingConfigProviderClass = "${PackageName.QQ}.setting.main.MainSettingConfigProvider"
private val MainSettingConfigProviderClass by lazyClassOrNull("${PackageName.QQ}.setting.main.MainSettingConfigProvider")
/** QQ、TIM 新版本存在的类 */
private const val FormSimpleItemClass = "${PackageName.QQ}.widget.FormSimpleItem"
private val FormSimpleItemClass by lazyClassOrNull("${PackageName.QQ}.widget.FormSimpleItem")
/** QQ、TIM 旧版本存在的类 */
private const val FormCommonSingleLineItemClass = "${PackageName.QQ}.widget.FormCommonSingleLineItem"
private val FormCommonSingleLineItemClass by lazyClassOrNull("${PackageName.QQ}.widget.FormCommonSingleLineItem")
/** QQ、TIM 存在的类 */
private const val CoreServiceClass = "${PackageName.QQ}.app.CoreService"
private val CoreServiceClass by lazyClassOrNull("${PackageName.QQ}.app.CoreService")
/** QQ、TIM 存在的类 */
private const val CoreService_KernelServiceClass = "${PackageName.QQ}.app.CoreService\$KernelService"
private val CoreService_KernelServiceClass by lazyClassOrNull("${PackageName.QQ}.app.CoreService\$KernelService")
/** 根据多个版本存的不同的类 */
private val BaseChatPieClass = VariousClass("${PackageName.QQ}.activity.aio.core.BaseChatPie", "${PackageName.QQ}.activity.BaseChatPie")
private val BaseChatPieClass by lazyClassOrNull(
VariousClass(
"${PackageName.QQ}.activity.aio.core.BaseChatPie",
"${PackageName.QQ}.activity.BaseChatPie"
)
)
/** 一个内部进程的名称 (与 X5 浏览器内核有关) */
private val privilegedProcessName = "$packageName:privileged_process"
@@ -131,7 +136,7 @@ object QQTIMHooker : YukiBaseHooker() {
* 在 QQ NT 中 [AboutActivityClass] 已被移除 - 以此作为判断条件
* @return [Boolean]
*/
private val isQQNTVersion get() = isQQ && AboutActivityClass.hasClass().not()
private val isQQNTVersion get() = isQQ && AboutActivityClass == null
/** 当前宿主的版本 */
private var hostVersionName = "<unknown>"
@@ -303,7 +308,7 @@ object QQTIMHooker : YukiBaseHooker() {
}
else -> {
HookEntry.isHookClientSupport = false
loggerW(msg = "$hostVersionName not supported!")
YLog.warn("$hostVersionName not supported!")
}
}
}
@@ -313,72 +318,55 @@ object QQTIMHooker : YukiBaseHooker() {
* @param methodName 方法名
*/
private fun hookBaseChatPie(methodName: String) {
BaseChatPieClass.hook {
injectMember {
method {
name = methodName
emptyParam()
returnType = UnitType
}
intercept()
}
}
BaseChatPieClass?.method {
name = methodName
emptyParam()
returnType = UnitType
}?.hook()?.intercept()
}
/** Hook CoreService QQ、TIM */
private fun hookCoreService() {
CoreServiceClass.hook {
CoreServiceClass?.apply {
if (isQQ) {
injectMember {
method { name = "startTempService" }
intercept()
}.ignoredNoSuchMemberFailure()
injectMember {
method {
name = "startCoreService"
param(BooleanType)
}
intercept()
}.ignoredNoSuchMemberFailure()
injectMember {
method {
name = "onStartCommand"
param(IntentClass, IntType, IntType)
}
replaceTo(any = 2)
}.ignoredNoSuchMemberFailure()
}
injectMember {
method { name = "onCreate" }
afterHook {
if (ConfigData.isEnableKillQQTimCoreService)
instance<Service>().apply {
ServiceCompat.stopForeground(this, ServiceCompat.STOP_FOREGROUND_REMOVE)
stopSelf()
loggerD(msg = "Shutdown CoreService OK!")
}
}
}
}
CoreService_KernelServiceClass.hook {
injectMember {
method { name = "onCreate" }
afterHook {
if (ConfigData.isEnableKillQQTimCoreServiceChild)
instance<Service>().apply {
ServiceCompat.stopForeground(this, ServiceCompat.STOP_FOREGROUND_REMOVE)
stopSelf()
loggerD(msg = "Shutdown CoreService\$KernelService OK!")
}
}
}
injectMember {
method {
name = "startTempService"
}.ignored().hook().intercept()
method {
name = "startCoreService"
param(BooleanType)
}.ignored().hook().intercept()
method {
name = "onStartCommand"
param(IntentClass, IntType, IntType)
}
replaceTo(any = 2)
}.ignoredNoSuchMemberFailure()
}.ignored().hook().replaceTo(any = 2)
}
method {
name = "onCreate"
}.ignored().hook().after {
if (ConfigData.isEnableKillQQTimCoreService)
instance<Service>().apply {
ServiceCompat.stopForeground(this, ServiceCompat.STOP_FOREGROUND_REMOVE)
stopSelf()
YLog.debug("Shutdown CoreService OK!")
}
}
}
CoreService_KernelServiceClass?.apply {
method {
name = "onCreate"
}.ignored().hook().after {
if (ConfigData.isEnableKillQQTimCoreServiceChild)
instance<Service>().apply {
ServiceCompat.stopForeground(this, ServiceCompat.STOP_FOREGROUND_REMOVE)
stopSelf()
YLog.debug("Shutdown CoreService\$KernelService OK!")
}
}
method {
name = "onStartCommand"
param(IntentClass, IntType, IntType)
}.ignored().hook().replaceTo(any = 2)
}
}
@@ -390,63 +378,53 @@ object QQTIMHooker : YukiBaseHooker() {
* 每个版本的差异暂未做排查
* 旧版本理论上没有这个类
*/
findClass(name = "${PackageName.QQ}.msf.service.y").hook {
injectMember {
method {
name = "a"
param(StringClass, LongType)
returnType = UnitType
}
intercept()
}.onAllFailure { loggerE(msg = "Hook MsfService Failed $it") }
}.ignoredHookClassNotFoundFailure()
"${PackageName.QQ}.msf.service.y".toClassOrNull()
?.method {
name = "a"
param(StringClass, LongType)
returnType = UnitType
}?.ignored()?.hook()?.intercept()
/**
* 干掉自动上传服务的电源锁
* 每个版本的差异暂未做排查
*/
findClass(name = "com.tencent.upload.impl.UploadServiceImpl").hook {
injectMember {
method { name = "acquireWakeLockIfNot" }
intercept()
}.onAllFailure { loggerE(msg = "Hook UploadServiceImpl Failed $it") }
}.ignoredHookClassNotFoundFailure()
"com.tencent.upload.impl.UploadServiceImpl".toClassOrNull()
?.method {
name = "acquireWakeLockIfNot"
}?.ignored()?.hook()?.intercept()
/**
* Hook 掉一个一像素保活 [Activity] 真的我怎么都想不到讯哥的程序员做出这种事情
* Hook 掉一个一像素保活 Activity 真的我怎么都想不到讯哥的程序员做出这种事情
* 这个东西经过测试会在锁屏的时候吊起来,解锁的时候自动 finish(),无限耍流氓耗电
* 2022/1/25 后期查证:锁屏界面消息快速回复窗口的解锁后拉起保活界面,也是毒瘤
*/
findClass(name = "${PackageName.QQ}.activity.QQLSUnlockActivity").hook {
injectMember {
method {
name = "onCreate"
param(BundleClass)
}
"${PackageName.QQ}.activity.QQLSUnlockActivity".toClassOrNull()
?.method {
name = "onCreate"
param(BundleClass)
}?.ignored()?.hook {
var origDevice = ""
beforeHook {
before {
/** 由于在 onCreate 里有一行判断只要型号是 xiaomi 的设备就开电源锁,所以说这里临时替换成菊花厂 */
origDevice = Build.MANUFACTURER
if (Build.MANUFACTURER.lowercase() == "xiaomi")
BuildClass.field { name = "MANUFACTURER" }.get().set("HUAWEI")
}
afterHook {
after {
instance<Activity>().finish()
/** 这里再把型号替换回去 - 不影响应用变量等 Xposed 模块修改的型号 */
BuildClass.field { name = "MANUFACTURER" }.get().set(origDevice)
}
}
}
/**
* 这个东西同上
* 反正也是一个一像素保活的 [Activity]
* 反正也是一个一像素保活的 Activity
* 讯哥的程序员真的有你的
* 2022/1/25 后期查证:锁屏界面消息快速回复窗口
*/
findClass("${PackageName.QQ}.activity.QQLSActivity\$14", "ktq").hook {
injectMember {
method { name = "run" }
intercept()
}.ignoredAllFailure()
}.ignoredHookClassNotFoundFailure()
VariousClass("${PackageName.QQ}.activity.QQLSActivity\$14", "ktq").toClassOrNull()
?.method {
name = "run"
}?.ignored()?.hook()?.intercept()
/**
* 这个是毒瘤核心类
* WakeLockMonitor
@@ -457,144 +435,97 @@ object QQTIMHooker : YukiBaseHooker() {
* 👮🏻 经过排查 Play 版本没这个类...... Emmmm 不想说啥了
* ✅ 备注8.9.x 版本已经基本移除了这个功能,没有再发现存在这个类
*/
findClass(name = "com.tencent.qapmsdk.qqbattery.monitor.WakeLockMonitor").hook {
injectMember {
method {
name = "onHook"
param(StringClass, AnyClass, AnyArrayClass, AnyClass)
}
intercept()
}
injectMember {
method {
name = "doReport"
param("com.tencent.qapmsdk.qqbattery.monitor.WakeLockMonitor\$WakeLockEntity", IntType)
}
intercept()
}
injectMember {
method {
name = "afterHookedMethod"
param("com.tencent.qapmsdk.qqbattery.monitor.MethodHookParam")
}
intercept()
}
injectMember {
method {
name = "beforeHookedMethod"
param("com.tencent.qapmsdk.qqbattery.monitor.MethodHookParam")
}
intercept()
}
injectMember {
method { name = "onAppBackground" }
intercept()
}
injectMember {
method {
name = "onOtherProcReport"
param(BundleClass)
}
intercept()
}
injectMember {
method { name = "onProcessRun30Min" }
intercept()
}
injectMember {
method { name = "onProcessBG5Min" }
intercept()
}
injectMember {
method {
name = "writeReport"
param(BooleanType)
}
intercept()
}
}.ignoredHookClassNotFoundFailure()
"com.tencent.qapmsdk.qqbattery.monitor.WakeLockMonitor".toClassOrNull()?.apply {
method {
name = "onHook"
param(StringClass, AnyClass, AnyArrayClass, AnyClass)
}.ignored().hook().intercept()
method {
name = "doReport"
param("com.tencent.qapmsdk.qqbattery.monitor.WakeLockMonitor\$WakeLockEntity", IntType)
}.ignored().hook().intercept()
method {
name = "afterHookedMethod"
param("com.tencent.qapmsdk.qqbattery.monitor.MethodHookParam")
}.ignored().hook().intercept()
method {
name = "beforeHookedMethod"
param("com.tencent.qapmsdk.qqbattery.monitor.MethodHookParam")
}.ignored().hook().intercept()
method {
name = "onAppBackground"
}.ignored().hook().intercept()
method {
name = "onOtherProcReport"
param(BundleClass)
}.ignored().hook().intercept()
method {
name = "onProcessRun30Min"
}.ignored().hook().intercept()
method {
name = "onProcessBG5Min"
}.ignored().hook().intercept()
method {
name = "writeReport"
param(BooleanType)
}.ignored().hook().intercept()
}
/**
* 这个是毒瘤核心操作类
* 功能同上、全部拦截
* 👮🏻 经过排查 Play 版本也没这个类...... Emmmm 不想说啥了
* ✅ 备注8.9.x 版本已经基本移除了这个功能,没有再发现存在这个类
*/
findClass(name = "com.tencent.qapmsdk.qqbattery.QQBatteryMonitor").hook {
injectMember {
method { name = "start" }
intercept()
}
injectMember {
method { name = "stop" }
intercept()
}
injectMember {
method {
name = "handleMessage"
param(MessageClass)
}
replaceToTrue()
}
injectMember {
method { name = "startMonitorInner" }
intercept()
}
injectMember {
method { name = "onAppBackground" }
intercept()
}
injectMember {
method { name = "onAppForeground" }
intercept()
}
injectMember {
method {
name = "setLogWhite"
paramCount = 2
}
intercept()
}
injectMember {
method {
name = "setCmdWhite"
paramCount = 2
}
intercept()
}
injectMember {
method {
name = "onWriteLog"
param(StringClass, StringClass)
}
intercept()
}
injectMember {
method {
name = "onCmdRequest"
param(StringClass)
}
intercept()
}
injectMember {
method {
name = "addData"
paramCount = 4
}
intercept()
}
injectMember {
method {
name = "onGpsScan"
paramCount = 2
}
intercept()
}
}.ignoredHookClassNotFoundFailure()
"com.tencent.qapmsdk.qqbattery.QQBatteryMonitor".toClassOrNull()?.apply {
method {
name = "start"
}.ignored().hook().intercept()
method {
name = "stop"
}.ignored().hook().intercept()
method {
name = "handleMessage"
param(MessageClass)
}.ignored().hook().intercept()
method {
name = "startMonitorInner"
}.ignored().hook().intercept()
method {
name = "onAppBackground"
}.ignored().hook().intercept()
method {
name = "onAppForeground"
}.ignored().hook().intercept()
method {
name = "setLogWhite"
paramCount = 2
}.ignored().hook().intercept()
method {
name = "setCmdWhite"
paramCount = 2
}.ignored().hook().intercept()
method {
name = "onWriteLog"
param(StringClass, StringClass)
}.ignored().hook().intercept()
method {
name = "onCmdRequest"
param(StringClass)
}.ignored().hook().intercept()
method {
name = "addData"
paramCount = 4
}.ignored().hook().intercept()
method {
name = "onGpsScan"
paramCount = 2
}.ignored().hook().intercept()
}
}
/** Hook QQ 的设置界面添加模块设置入口 (新版) */
private fun hookQQSettingsUi() {
if (MainSettingFragmentClass.hasClass().not()) return loggerE(msg = "Could not found main setting class, hook aborted")
if (MainSettingFragmentClass == null) return YLog.error("Could not found main setting class, hook aborted")
val kotlinUnit = "kotlin.Unit"
val kotlinFunction0 = "kotlin.jvm.functions.Function0"
val simpleItemProcessorClass = searchClass {
@@ -605,7 +536,7 @@ object QQTIMHooker : YukiBaseHooker() {
returnType = UnitType
}
field().count { it >= 6 }
}.get() ?: return loggerE(msg = "Could not found processor class, hook aborted")
}.get() ?: return YLog.error("Could not found processor class, hook aborted")
/**
* 创建入口点条目
@@ -623,7 +554,7 @@ object QQTIMHooker : YukiBaseHooker() {
param { it[0].name == kotlinFunction0 }
paramCount = 1
returnType = UnitType
}.giveAll().lastOrNull() ?: error("Could not found processor method")
}.giveAll().firstOrNull() ?: error("Could not found processor method")
val proxyOnClick = Proxy.newProxyInstance(appClassLoader, arrayOf(onClickMethod.parameterTypes[0])) { any, method, args ->
if (method.name == "invoke") {
context.startModuleSettings()
@@ -632,20 +563,15 @@ object QQTIMHooker : YukiBaseHooker() {
}; onClickMethod.invoke(entryItem, proxyOnClick)
} ?: error("Could not create TSBattery entry item")
}
MainSettingConfigProviderClass.hook {
injectMember {
method {
param(ContextClass)
returnType = ListClass
}
afterHook {
val context = args().first().cast<Context>() ?: return@afterHook
val processor = result<MutableList<Any?>>() ?: return@afterHook
processor.add(1, processor[0]?.javaClass?.buildOf(arrayListOf<Any>().apply { add(createTSEntryItem(context)) }, "", "") {
param(ListClass, CharSequenceClass, CharSequenceClass)
})
}
}
MainSettingConfigProviderClass?.method {
param(ContextClass)
returnType = ListClass
}?.hook()?.after {
val context = args().first().cast<Context>() ?: return@after
val processor = result<MutableList<Any?>>() ?: return@after
processor.add(1, processor[0]?.javaClass?.buildOf(arrayListOf<Any>().apply { add(createTSEntryItem(context)) }, "", "") {
param(ListClass, CharSequenceClass, CharSequenceClass)
})
}
}
@@ -656,10 +582,10 @@ object QQTIMHooker : YukiBaseHooker() {
private fun hookQQSettingsUiLegacy(instance: Any?) {
/** 当前的顶级 Item 实例 */
val formItemRefRoot = instance?.current()?.field {
type { it.name == FormSimpleItemClass || it.name == FormCommonSingleLineItemClass }.index(num = 1)
type { it == FormSimpleItemClass || it == FormCommonSingleLineItemClass }.index(num = 1)
}?.cast<View?>()
/** 创建一个新的 Item */
FormSimpleItemClass.toClassOrNull()?.buildOf<View>(instance?.compatToActivity()) { param(ContextClass) }?.current {
FormSimpleItemClass?.buildOf<View>(instance?.compatToActivity()) { param(ContextClass) }?.current {
method {
name = "setLeftText"
param(CharSequenceClass)
@@ -705,44 +631,29 @@ object QQTIMHooker : YukiBaseHooker() {
hookQQBaseChatPie()
hookCoreService()
hookQQDisgusting()
loggerI(msg = "All processes are completed for \"${processName.takeIf { it != packageName } ?: packageName}\"")
YLog.info("All processes are completed for \"${processName.takeIf { it != packageName } ?: packageName}\"")
}
}
/** 仅注入主进程 */
withProcess(mainProcessName) {
/** Hook 跳转事件 */
JumpActivityClass.hook {
injectMember {
method {
name = "doOnCreate"
param(BundleClass)
}
afterHook { instance<Activity>().jumpToModuleSettings() }
}
}
JumpActivityClass?.method {
name = "doOnCreate"
param(BundleClass)
}?.hook()?.after { instance<Activity>().jumpToModuleSettings() }
/** Hook 设置界面入口点 */
if (isQQNTVersion) hookQQSettingsUi()
else {
/** 将条目注入设置界面 (Activity) */
QQSettingSettingActivityClass.hook {
injectMember {
method {
name = "doOnCreate"
param(BundleClass)
}
afterHook { hookQQSettingsUiLegacy(instance) }
}
}
QQSettingSettingActivityClass?.method {
name = "doOnCreate"
param(BundleClass)
}?.hook()?.after { hookQQSettingsUiLegacy(instance) }
/** 将条目注入设置界面 (Fragment) */
QQSettingSettingFragmentClass.hook {
injectMember {
method {
name = "doOnCreateView"
paramCount = 3
}
afterHook { hookQQSettingsUiLegacy(instance) }
}
}.ignoredHookClassNotFoundFailure()
QQSettingSettingFragmentClass?.method {
name = "doOnCreateView"
paramCount = 3
}?.hook()?.after { hookQQSettingsUiLegacy(instance) }
}
}
}

View File

@@ -45,9 +45,10 @@ import com.fankes.tsbattery.utils.factory.dp
import com.highcapable.yukihookapi.hook.entity.YukiBaseHooker
import com.highcapable.yukihookapi.hook.factory.current
import com.highcapable.yukihookapi.hook.factory.injectModuleAppResources
import com.highcapable.yukihookapi.hook.factory.method
import com.highcapable.yukihookapi.hook.factory.processName
import com.highcapable.yukihookapi.hook.factory.registerModuleAppActivities
import com.highcapable.yukihookapi.hook.log.loggerI
import com.highcapable.yukihookapi.hook.log.YLog
import com.highcapable.yukihookapi.hook.type.android.ViewClass
/**
@@ -58,16 +59,19 @@ import com.highcapable.yukihookapi.hook.type.android.ViewClass
object WeChatHooker : YukiBaseHooker() {
/** 微信存在的类 - 未测试每个版本是否都存在 */
const val LauncherUIClass = "${PackageName.WECHAT}.ui.LauncherUI"
const val LauncherUIClassName = "${PackageName.WECHAT}.ui.LauncherUI"
/** 微信存在的类 - 未测试每个版本是否都存在 */
private const val EmptyActivityClass = "${PackageName.WECHAT}.ui.EmptyActivity"
private val LauncherUIClass by lazyClassOrNull("${PackageName.WECHAT}.ui.LauncherUI")
/** 微信存在的类 - 未测试每个版本是否都存在 */
private const val WelabMainUIClass = "${PackageName.WECHAT}.plugin.welab.ui.WelabMainUI"
private val EmptyActivityClass by lazyClassOrNull("${PackageName.WECHAT}.ui.EmptyActivity")
/** 微信存在的类 - 未测试每个版本是否都存在 */
private const val SettingsUIClass = "${PackageName.WECHAT}.plugin.setting.ui.setting.SettingsUI"
private val WelabMainUIClass by lazyClassOrNull("${PackageName.WECHAT}.plugin.welab.ui.WelabMainUI")
/** 微信存在的类 - 未测试每个版本是否都存在 */
private val SettingsUIClass by lazyClassOrNull("${PackageName.WECHAT}.plugin.setting.ui.setting.SettingsUI")
/** TSBattery 图标 TAG 名称 */
private const val TSBARRERY_ICON_TAG = "tsbattery_icon"
@@ -98,51 +102,41 @@ object WeChatHooker : YukiBaseHooker() {
onCreate {
ConfigData.init(context = this)
registerModuleAppActivities(when {
EmptyActivityClass.hasClass() -> EmptyActivityClass
WelabMainUIClass.hasClass() -> WelabMainUIClass
EmptyActivityClass != null -> EmptyActivityClass
WelabMainUIClass != null -> WelabMainUIClass
else -> error("Inject WeChat Activity Proxy failed, unsupport version $appVersionName($appVersionCode)")
})
if (ConfigData.isDisableAllHook) return@onCreate
hookSystemWakeLock()
loggerI(msg = "All processes are completed for \"${processName.takeIf { it != packageName } ?: packageName}\"")
YLog.info("All processes are completed for \"${processName.takeIf { it != packageName } ?: packageName}\"")
}
}
/** 仅注入主进程 */
withProcess(mainProcessName) {
/** Hook 跳转事件 */
LauncherUIClass.hook {
injectMember {
method {
name = "onResume"
emptyParam()
}
afterHook { instance<Activity>().jumpToModuleSettings(isFinish = false) }
}
}
LauncherUIClass?.method {
name = "onResume"
emptyParam()
}?.hook()?.after { instance<Activity>().jumpToModuleSettings(isFinish = false) }
/** 向设置界面右上角添加按钮 */
SettingsUIClass.hook {
injectMember {
method {
name = "onResume"
emptyParam()
}
afterHook {
method {
name = "get_fragment"
emptyParam()
superClass(isOnlySuperClass = true)
}.get(instance).call()?.current()?.method {
name = "getView"
emptyParam()
returnType = ViewClass
superClass(isOnlySuperClass = true)
}?.invoke<ViewGroup?>()?.also {
it.context?.injectModuleAppResources()
runCatching { it.getChildAt(0) as? ViewGroup? }.getOrNull()?.also { rootView ->
if (rootView.findViewWithTag<View>(TSBARRERY_ICON_TAG) == null)
rootView.addView(createPreferenceIcon(it.context))
}
}
SettingsUIClass?.method {
name = "onResume"
emptyParam()
}?.hook()?.after {
SettingsUIClass?.method {
name = "get_fragment"
emptyParam()
superClass(isOnlySuperClass = true)
}?.get(instance)?.call()?.current()?.method {
name = "getView"
emptyParam()
returnType = ViewClass
superClass(isOnlySuperClass = true)
}?.invoke<ViewGroup?>()?.also {
it.context?.injectModuleAppResources()
runCatching { it.getChildAt(0) as? ViewGroup? }.getOrNull()?.also { rootView ->
if (rootView.findViewWithTag<View>(TSBARRERY_ICON_TAG) == null)
rootView.addView(createPreferenceIcon(it.context))
}
}
}

View File

@@ -81,13 +81,8 @@ fun Activity.jumpToModuleSettings(isFinish: Boolean = true) {
/** Hook 系统电源锁 */
fun PackageParam.hookSystemWakeLock() {
PowerManager_WakeLockClass.hook {
injectMember {
method {
name = "acquireLocked"
emptyParam()
}
intercept()
}
}
PowerManager_WakeLockClass.method {
name = "acquireLocked"
emptyParam()
}.hook().intercept()
}

View File

@@ -189,7 +189,7 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
startActivity(Intent().apply {
component = ComponentName(
packageName,
if (packageName != PackageName.WECHAT) QQTIMHooker.JumpActivityClass else WeChatHooker.LauncherUIClass
if (packageName != PackageName.WECHAT) QQTIMHooker.JumpActivityClassName else WeChatHooker.LauncherUIClassName
)
putExtra(JumpEvent.OPEN_MODULE_SETTING, YukiHookAPI.Status.compiledTimestamp)
flags = Intent.FLAG_ACTIVITY_NEW_TASK

View File

@@ -19,7 +19,7 @@
*
* This file is created by fankes on 2022/1/7.
*/
@file:Suppress("unused", "OPT_IN_USAGE", "EXPERIMENTAL_API_USAGE")
@file:Suppress("unused")
package com.fankes.tsbattery.utils.factory
@@ -34,7 +34,6 @@ import androidx.appcompat.app.AlertDialog
import com.fankes.tsbattery.R
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.google.android.material.progressindicator.CircularProgressIndicator
import com.highcapable.yukihookapi.annotation.CauseProblemsApi
import com.highcapable.yukihookapi.hook.factory.applyModuleTheme
/**
@@ -134,7 +133,6 @@ class DialogBuilder(val context: Context) {
fun cancel() = dialogInstance?.cancel()
/** 显示对话框 */
@CauseProblemsApi
fun show() = runInSafe {
instance?.create()?.apply {
customLayoutView?.let { setView(it) }

View File

@@ -23,7 +23,7 @@
package com.fankes.tsbattery.utils.factory
import com.highcapable.yukihookapi.hook.log.loggerE
import com.highcapable.yukihookapi.hook.log.YLog
/**
* 忽略异常返回值
@@ -78,5 +78,5 @@ inline fun <T> safeOf(default: T, result: () -> T) = try {
* @param block 正常回调
*/
inline fun <T> T.runInSafe(msg: String = "", block: () -> Unit) {
runCatching(block).onFailure { if (msg.isNotBlank()) loggerE(msg = msg, e = it) }
runCatching(block).onFailure { if (msg.isNotBlank()) YLog.error(msg, it) }
}

View File

@@ -75,7 +75,7 @@ inline val Context.isNotSystemInDarkMode get() = !isSystemInDarkMode
* @return [PackageInfo] or null
*/
private fun Context.getPackageInfoCompat(packageName: String, flag: Number = 0) = runCatching {
@Suppress("DEPRECATION")
@Suppress("DEPRECATION", "KotlinRedundantDiagnosticSuppress")
if (Build.VERSION.SDK_INT >= 33)
packageManager?.getPackageInfo(packageName, PackageInfoFlags.of(flag.toLong()))
else packageManager?.getPackageInfo(packageName, flag.toInt())