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

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.entity.YukiBaseHooker
import com.highcapable.yukihookapi.hook.factory.current import com.highcapable.yukihookapi.hook.factory.current
import com.highcapable.yukihookapi.hook.factory.injectModuleAppResources 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.processName
import com.highcapable.yukihookapi.hook.factory.registerModuleAppActivities 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 import com.highcapable.yukihookapi.hook.type.android.ViewClass
/** /**
@@ -58,16 +59,19 @@ import com.highcapable.yukihookapi.hook.type.android.ViewClass
object WeChatHooker : YukiBaseHooker() { 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 名称 */ /** TSBattery 图标 TAG 名称 */
private const val TSBARRERY_ICON_TAG = "tsbattery_icon" private const val TSBARRERY_ICON_TAG = "tsbattery_icon"
@@ -98,51 +102,41 @@ object WeChatHooker : YukiBaseHooker() {
onCreate { onCreate {
ConfigData.init(context = this) ConfigData.init(context = this)
registerModuleAppActivities(when { registerModuleAppActivities(when {
EmptyActivityClass.hasClass() -> EmptyActivityClass EmptyActivityClass != null -> EmptyActivityClass
WelabMainUIClass.hasClass() -> WelabMainUIClass WelabMainUIClass != null -> WelabMainUIClass
else -> error("Inject WeChat Activity Proxy failed, unsupport version $appVersionName($appVersionCode)") else -> error("Inject WeChat Activity Proxy failed, unsupport version $appVersionName($appVersionCode)")
}) })
if (ConfigData.isDisableAllHook) return@onCreate if (ConfigData.isDisableAllHook) return@onCreate
hookSystemWakeLock() 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) { withProcess(mainProcessName) {
/** Hook 跳转事件 */ /** Hook 跳转事件 */
LauncherUIClass.hook { LauncherUIClass?.method {
injectMember { name = "onResume"
method { emptyParam()
name = "onResume" }?.hook()?.after { instance<Activity>().jumpToModuleSettings(isFinish = false) }
emptyParam()
}
afterHook { instance<Activity>().jumpToModuleSettings(isFinish = false) }
}
}
/** 向设置界面右上角添加按钮 */ /** 向设置界面右上角添加按钮 */
SettingsUIClass.hook { SettingsUIClass?.method {
injectMember { name = "onResume"
method { emptyParam()
name = "onResume" }?.hook()?.after {
emptyParam() SettingsUIClass?.method {
} name = "get_fragment"
afterHook { emptyParam()
method { superClass(isOnlySuperClass = true)
name = "get_fragment" }?.get(instance)?.call()?.current()?.method {
emptyParam() name = "getView"
superClass(isOnlySuperClass = true) emptyParam()
}.get(instance).call()?.current()?.method { returnType = ViewClass
name = "getView" superClass(isOnlySuperClass = true)
emptyParam() }?.invoke<ViewGroup?>()?.also {
returnType = ViewClass it.context?.injectModuleAppResources()
superClass(isOnlySuperClass = true) runCatching { it.getChildAt(0) as? ViewGroup? }.getOrNull()?.also { rootView ->
}?.invoke<ViewGroup?>()?.also { if (rootView.findViewWithTag<View>(TSBARRERY_ICON_TAG) == null)
it.context?.injectModuleAppResources() rootView.addView(createPreferenceIcon(it.context))
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 系统电源锁 */ /** Hook 系统电源锁 */
fun PackageParam.hookSystemWakeLock() { fun PackageParam.hookSystemWakeLock() {
PowerManager_WakeLockClass.hook { PowerManager_WakeLockClass.method {
injectMember { name = "acquireLocked"
method { emptyParam()
name = "acquireLocked" }.hook().intercept()
emptyParam()
}
intercept()
}
}
} }

View File

@@ -189,7 +189,7 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
startActivity(Intent().apply { startActivity(Intent().apply {
component = ComponentName( component = ComponentName(
packageName, 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) putExtra(JumpEvent.OPEN_MODULE_SETTING, YukiHookAPI.Status.compiledTimestamp)
flags = Intent.FLAG_ACTIVITY_NEW_TASK flags = Intent.FLAG_ACTIVITY_NEW_TASK

View File

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

View File

@@ -23,7 +23,7 @@
package com.fankes.tsbattery.utils.factory 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 正常回调 * @param block 正常回调
*/ */
inline fun <T> T.runInSafe(msg: String = "", block: () -> Unit) { 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 * @return [PackageInfo] or null
*/ */
private fun Context.getPackageInfoCompat(packageName: String, flag: Number = 0) = runCatching { private fun Context.getPackageInfoCompat(packageName: String, flag: Number = 0) = runCatching {
@Suppress("DEPRECATION") @Suppress("DEPRECATION", "KotlinRedundantDiagnosticSuppress")
if (Build.VERSION.SDK_INT >= 33) if (Build.VERSION.SDK_INT >= 33)
packageManager?.getPackageInfo(packageName, PackageInfoFlags.of(flag.toLong())) packageManager?.getPackageInfo(packageName, PackageInfoFlags.of(flag.toLong()))
else packageManager?.getPackageInfo(packageName, flag.toInt()) else packageManager?.getPackageInfo(packageName, flag.toInt())