mirror of
https://github.com/fankes/TSBattery.git
synced 2025-09-07 19:14:19 +08:00
Compare commits
8 Commits
Author | SHA1 | Date | |
---|---|---|---|
1337d7cf31
|
|||
8855595b80
|
|||
4bf53efa7a
|
|||
7f2e97a94e
|
|||
16e0278369
|
|||
20f6d5529f
|
|||
08d7676478
|
|||
a67faed81c
|
14
README.md
14
README.md
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
[](https://github.com/fankes/TSBattery)
|
[](https://github.com/fankes/TSBattery)
|
||||||
[](https://github.com/fankes/TSBattery/blob/master/LICENSE)
|
[](https://github.com/fankes/TSBattery/blob/master/LICENSE)
|
||||||
[](https://github.com/fankes/TSBattery/releases)
|
[](https://github.com/fankes/TSBattery/releases)
|
||||||
[](https://github.com/fankes/TSBattery/releases)
|
[](https://github.com/fankes/TSBattery/releases)
|
||||||
[](https://github.com/Xposed-Modules-Repo/com.fankes.tsbattery/releases)
|
[](https://github.com/Xposed-Modules-Repo/com.fankes.tsbattery/releases)
|
||||||
[](https://t.me/XiaofangInternet)
|
[](https://t.me/XiaofangInternet)
|
||||||
@@ -18,15 +18,17 @@ TSBattery 是一个旨在使 QQ、TIM、微信 变得更省电的开源 Xposed
|
|||||||
|
|
||||||
## 适配说明
|
## 适配说明
|
||||||
|
|
||||||
- 支持并建议使用 <b>LSPosed</b>(若作用域没有自动出现推荐请勾选 QQ、TIM、微信)
|
- 支持并建议使用 **LSPosed**(若作用域没有自动出现推荐请勾选 QQ、TIM、微信)
|
||||||
|
|
||||||
- 可以使用 <b>~~EdXposed~~</b>,但随时停止支持
|
- 可以使用 **~~EdXposed~~**,但随时停止支持
|
||||||
|
|
||||||
- <b>太极无极 · 阴</b> 支持性不是很好,建议使用 <b>太极无极 · 阳</b>
|
- **太极无极 · 阴** 支持性不是很好,建议使用 **太极无极 · 阳** 或 **LSPatch (推荐)**
|
||||||
|
|
||||||
- 支持 <b>Pine</b>(梦境模块) 但是部分功能有限制
|
- 支持 **Pine**(梦境模块) 但是部分功能有限制
|
||||||
|
|
||||||
- 请不要使用 <b>~~应用转生~~</b>,发生封号情况后果自负
|
- 请不要使用 **~~应用转生~~**,发生封号情况后果自负
|
||||||
|
|
||||||
|
- 如果微信不能在 **LSPosed** 中生效,请尝试勾选任意包含微信作用域的模块,例如 **微X模块**
|
||||||
|
|
||||||
## 请勿用于非法用途
|
## 请勿用于非法用途
|
||||||
|
|
||||||
|
@@ -59,8 +59,8 @@ android {
|
|||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
compileOnly 'de.robv.android.xposed:api:82'
|
compileOnly 'de.robv.android.xposed:api:82'
|
||||||
implementation 'com.highcapable.yukihookapi:api:1.1.1'
|
implementation 'com.highcapable.yukihookapi:api:1.1.2'
|
||||||
ksp 'com.highcapable.yukihookapi:ksp-xposed:1.1.1'
|
ksp 'com.highcapable.yukihookapi:ksp-xposed:1.1.2'
|
||||||
implementation 'com.github.duanhong169:drawabletoolbox:1.0.7'
|
implementation 'com.github.duanhong169:drawabletoolbox:1.0.7'
|
||||||
implementation 'com.squareup.okhttp3:okhttp:5.0.0-alpha.7'
|
implementation 'com.squareup.okhttp3:okhttp:5.0.0-alpha.7'
|
||||||
implementation 'androidx.core:core-ktx:1.9.0'
|
implementation 'androidx.core:core-ktx:1.9.0'
|
||||||
|
@@ -24,15 +24,11 @@
|
|||||||
package com.fankes.tsbattery.hook
|
package com.fankes.tsbattery.hook
|
||||||
|
|
||||||
import com.fankes.tsbattery.const.PackageName
|
import com.fankes.tsbattery.const.PackageName
|
||||||
import com.fankes.tsbattery.data.ConfigData
|
|
||||||
import com.fankes.tsbattery.hook.entity.QQTIMHooker
|
import com.fankes.tsbattery.hook.entity.QQTIMHooker
|
||||||
import com.fankes.tsbattery.hook.entity.WeChatHooker
|
import com.fankes.tsbattery.hook.entity.WeChatHooker
|
||||||
import com.fankes.tsbattery.utils.factory.versionName
|
|
||||||
import com.highcapable.yukihookapi.annotation.xposed.InjectYukiHookWithXposed
|
import com.highcapable.yukihookapi.annotation.xposed.InjectYukiHookWithXposed
|
||||||
import com.highcapable.yukihookapi.hook.factory.configs
|
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.factory.registerModuleAppActivities
|
|
||||||
import com.highcapable.yukihookapi.hook.param.PackageParam
|
|
||||||
import com.highcapable.yukihookapi.hook.xposed.proxy.IYukiHookXposedInit
|
import com.highcapable.yukihookapi.hook.xposed.proxy.IYukiHookXposedInit
|
||||||
|
|
||||||
@InjectYukiHookWithXposed(isUsingResourcesHook = false)
|
@InjectYukiHookWithXposed(isUsingResourcesHook = false)
|
||||||
@@ -50,31 +46,9 @@ class HookEntry : IYukiHookXposedInit {
|
|||||||
isEnableDataChannel = false
|
isEnableDataChannel = false
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 装载对象是否为 QQ、TIM、微信
|
|
||||||
* @return [Boolean]
|
|
||||||
*/
|
|
||||||
private fun PackageParam.isCurrentScope() = packageName.let { it == PackageName.QQ || it == PackageName.TIM || it == PackageName.WECHAT }
|
|
||||||
|
|
||||||
override fun onHook() = encase {
|
override fun onHook() = encase {
|
||||||
loadApp {
|
loadApp(PackageName.QQ) { loadHooker(QQTIMHooker) }
|
||||||
if (isCurrentScope()) onAppLifecycle {
|
loadApp(PackageName.TIM) { loadHooker(QQTIMHooker) }
|
||||||
attachBaseContext { baseContext, hasCalledSuper ->
|
loadApp(PackageName.WECHAT) { loadHooker(WeChatHooker) }
|
||||||
if (hasCalledSuper) return@attachBaseContext
|
|
||||||
ConfigData.init(baseContext)
|
|
||||||
when (baseContext.packageName) {
|
|
||||||
PackageName.QQ, PackageName.TIM -> loadHooker(QQTIMHooker.apply { appVersionName = baseContext.versionName })
|
|
||||||
PackageName.WECHAT -> loadHooker(WeChatHooker)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
onCreate {
|
|
||||||
when (packageName) {
|
|
||||||
PackageName.QQ, PackageName.TIM ->
|
|
||||||
registerModuleAppActivities(proxy = "${PackageName.QQ}.activity.QQSettingSettingActivity")
|
|
||||||
PackageName.WECHAT -> registerModuleAppActivities(proxy = "${PackageName.WECHAT}.plugin.welab.ui.WelabMainUI")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -23,6 +23,7 @@ package com.fankes.tsbattery.hook.entity
|
|||||||
|
|
||||||
import android.app.Activity
|
import android.app.Activity
|
||||||
import android.app.Service
|
import android.app.Service
|
||||||
|
import android.content.res.Configuration
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
@@ -35,13 +36,13 @@ import com.fankes.tsbattery.hook.factory.hookSystemWakeLock
|
|||||||
import com.fankes.tsbattery.hook.factory.jumpToModuleSettings
|
import com.fankes.tsbattery.hook.factory.jumpToModuleSettings
|
||||||
import com.fankes.tsbattery.hook.factory.startModuleSettings
|
import com.fankes.tsbattery.hook.factory.startModuleSettings
|
||||||
import com.fankes.tsbattery.utils.factory.dp
|
import com.fankes.tsbattery.utils.factory.dp
|
||||||
|
import com.fankes.tsbattery.utils.factory.versionName
|
||||||
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.buildOf
|
import com.highcapable.yukihookapi.hook.factory.*
|
||||||
import com.highcapable.yukihookapi.hook.factory.current
|
|
||||||
import com.highcapable.yukihookapi.hook.factory.field
|
|
||||||
import com.highcapable.yukihookapi.hook.log.loggerD
|
import com.highcapable.yukihookapi.hook.log.loggerD
|
||||||
import com.highcapable.yukihookapi.hook.log.loggerE
|
import com.highcapable.yukihookapi.hook.log.loggerE
|
||||||
|
import com.highcapable.yukihookapi.hook.log.loggerI
|
||||||
import com.highcapable.yukihookapi.hook.type.android.*
|
import com.highcapable.yukihookapi.hook.type.android.*
|
||||||
import com.highcapable.yukihookapi.hook.type.java.*
|
import com.highcapable.yukihookapi.hook.type.java.*
|
||||||
|
|
||||||
@@ -56,6 +57,9 @@ object QQTIMHooker : YukiBaseHooker() {
|
|||||||
/** QQ、TIM 存在的类 */
|
/** QQ、TIM 存在的类 */
|
||||||
private const val QQSettingSettingActivityClass = "${PackageName.QQ}.activity.QQSettingSettingActivity"
|
private const val QQSettingSettingActivityClass = "${PackageName.QQ}.activity.QQSettingSettingActivity"
|
||||||
|
|
||||||
|
/** QQ、TIM 存在的类 */
|
||||||
|
private const val AboutActivityClass = "${PackageName.QQ}.activity.AboutActivity"
|
||||||
|
|
||||||
/** QQ、TIM 新版本存在的类 */
|
/** QQ、TIM 新版本存在的类 */
|
||||||
private const val FormSimpleItemClass = "${PackageName.QQ}.widget.FormSimpleItem"
|
private const val FormSimpleItemClass = "${PackageName.QQ}.widget.FormSimpleItem"
|
||||||
|
|
||||||
@@ -72,6 +76,9 @@ object QQTIMHooker : YukiBaseHooker() {
|
|||||||
private val BaseChatPieClass =
|
private val BaseChatPieClass =
|
||||||
VariousClass("${PackageName.QQ}.activity.aio.core.BaseChatPie", "${PackageName.QQ}.activity.BaseChatPie")
|
VariousClass("${PackageName.QQ}.activity.aio.core.BaseChatPie", "${PackageName.QQ}.activity.BaseChatPie")
|
||||||
|
|
||||||
|
/** 默认的 [Configuration] */
|
||||||
|
var baseConfiguration: Configuration? = null
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 当前是否为 QQ
|
* 当前是否为 QQ
|
||||||
* @return [Boolean]
|
* @return [Boolean]
|
||||||
@@ -79,7 +86,7 @@ object QQTIMHooker : YukiBaseHooker() {
|
|||||||
private val isQQ get() = packageName == PackageName.QQ
|
private val isQQ get() = packageName == PackageName.QQ
|
||||||
|
|
||||||
/** 当前宿主的版本 */
|
/** 当前宿主的版本 */
|
||||||
var appVersionName = "<unknown>"
|
private var appVersionName = "<unknown>"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 这个类 QQ 的 BaseChatPie 是控制聊天界面的
|
* 这个类 QQ 的 BaseChatPie 是控制聊天界面的
|
||||||
@@ -204,6 +211,10 @@ object QQTIMHooker : YukiBaseHooker() {
|
|||||||
hookBaseChatPie(methodName = "H3")
|
hookBaseChatPie(methodName = "H3")
|
||||||
hookBaseChatPie(methodName = "N")
|
hookBaseChatPie(methodName = "N")
|
||||||
}
|
}
|
||||||
|
"8.9.13" -> {
|
||||||
|
hookBaseChatPie(methodName = "y3")
|
||||||
|
hookBaseChatPie(methodName = "H")
|
||||||
|
}
|
||||||
else -> {
|
else -> {
|
||||||
HookEntry.isHookClientSupport = false
|
HookEntry.isHookClientSupport = false
|
||||||
loggerD(msg = "$appVersionName not supported!")
|
loggerD(msg = "$appVersionName not supported!")
|
||||||
@@ -496,67 +507,77 @@ object QQTIMHooker : YukiBaseHooker() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun onHook() {
|
override fun onHook() {
|
||||||
/** Hook 跳转事件 */
|
onAppLifecycle {
|
||||||
JumpActivityClass.hook {
|
attachBaseContext { baseContext, hasCalledSuper ->
|
||||||
injectMember {
|
if (hasCalledSuper.not()) baseConfiguration = baseContext.resources.configuration
|
||||||
method {
|
}
|
||||||
name = "doOnCreate"
|
onCreate {
|
||||||
param(BundleClass)
|
appVersionName = versionName
|
||||||
}
|
ConfigData.init(context = this)
|
||||||
afterHook { instance<Activity>().jumpToModuleSettings() }
|
registerModuleAppActivities(AboutActivityClass)
|
||||||
|
if (ConfigData.isDisableAllHook) return@onCreate
|
||||||
|
hookSystemWakeLock()
|
||||||
|
hookQQBaseChatPie()
|
||||||
|
hookCoreService()
|
||||||
|
hookQQDisgusting()
|
||||||
|
loggerI(msg = "All processes are completed for \"${processName.takeIf { it != packageName } ?: packageName}\"")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/** 将条目注入设置界面 */
|
/** 仅注入主进程 */
|
||||||
QQSettingSettingActivityClass.hook {
|
withProcess(mainProcessName) {
|
||||||
injectMember {
|
/** Hook 跳转事件 */
|
||||||
method {
|
JumpActivityClass.hook {
|
||||||
name = "doOnCreate"
|
injectMember {
|
||||||
param(BundleClass)
|
method {
|
||||||
|
name = "doOnCreate"
|
||||||
|
param(BundleClass)
|
||||||
|
}
|
||||||
|
afterHook { instance<Activity>().jumpToModuleSettings() }
|
||||||
}
|
}
|
||||||
afterHook {
|
}
|
||||||
/** 当前的顶级 Item 实例 */
|
/** 将条目注入设置界面 */
|
||||||
val formItemRefRoot = field {
|
QQSettingSettingActivityClass.hook {
|
||||||
type(FormSimpleItemClass).index(num = 1)
|
injectMember {
|
||||||
}.ignored().get(instance).cast() ?: field {
|
method {
|
||||||
type(FormCommonSingleLineItemClass).index(num = 1)
|
name = "doOnCreate"
|
||||||
}.ignored().get(instance).cast<View?>()
|
param(BundleClass)
|
||||||
/** 创建一个新的 Item */
|
}
|
||||||
FormSimpleItemClass.toClassOrNull()?.buildOf<View>(instance) { param(ContextClass) }?.current {
|
afterHook {
|
||||||
method {
|
/** 当前的顶级 Item 实例 */
|
||||||
name = "setLeftText"
|
val formItemRefRoot = field {
|
||||||
param(CharSequenceType)
|
type(FormSimpleItemClass).index(num = 1)
|
||||||
}.call("TSBattery")
|
}.ignored().get(instance).cast() ?: field {
|
||||||
method {
|
type(FormCommonSingleLineItemClass).index(num = 1)
|
||||||
name = "setRightText"
|
}.ignored().get(instance).cast<View?>()
|
||||||
param(CharSequenceType)
|
/** 创建一个新的 Item */
|
||||||
}.call(BuildConfig.VERSION_NAME)
|
FormSimpleItemClass.toClassOrNull()?.buildOf<View>(instance) { param(ContextClass) }?.current {
|
||||||
method {
|
method {
|
||||||
name = "setBgType"
|
name = "setLeftText"
|
||||||
param(IntType)
|
param(CharSequenceType)
|
||||||
}.call(if (isQQ) 0 else 2)
|
}.call("TSBattery")
|
||||||
}?.apply { setOnClickListener { instance<Activity>().startModuleSettings() } }?.also { item ->
|
method {
|
||||||
var listGroup = formItemRefRoot?.parent as? ViewGroup?
|
name = "setRightText"
|
||||||
val lparam = (if (listGroup?.childCount == 1) {
|
param(CharSequenceType)
|
||||||
listGroup = listGroup.parent as? ViewGroup
|
}.call(BuildConfig.VERSION_NAME)
|
||||||
(formItemRefRoot?.parent as? View?)?.layoutParams
|
method {
|
||||||
} else formItemRefRoot?.layoutParams)
|
name = "setBgType"
|
||||||
?: ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)
|
param(IntType)
|
||||||
/** 设置圆角和间距 */
|
}.call(if (isQQ) 0 else 2)
|
||||||
if (isQQ) (lparam as? ViewGroup.MarginLayoutParams?)?.setMargins(0, 15.dp(item.context), 0, 0)
|
}?.apply { setOnClickListener { instance<Activity>().startModuleSettings() } }?.also { item ->
|
||||||
/** 将 Item 添加到设置界面 */
|
var listGroup = formItemRefRoot?.parent as? ViewGroup?
|
||||||
listGroup?.also { if (isQQ) it.addView(item, lparam) else it.addView(item, 0, lparam) }
|
val lparam = (if (listGroup?.childCount == 1) {
|
||||||
|
listGroup = listGroup.parent as? ViewGroup
|
||||||
|
(formItemRefRoot?.parent as? View?)?.layoutParams
|
||||||
|
} else formItemRefRoot?.layoutParams)
|
||||||
|
?: ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)
|
||||||
|
/** 设置圆角和间距 */
|
||||||
|
if (isQQ) (lparam as? ViewGroup.MarginLayoutParams?)?.setMargins(0, 15.dp(item.context), 0, 0)
|
||||||
|
/** 将 Item 添加到设置界面 */
|
||||||
|
listGroup?.also { if (isQQ) it.addView(item, lparam) else it.addView(item, 0, lparam) }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (ConfigData.isDisableAllHook) return
|
|
||||||
/** Hook 系统电源锁 */
|
|
||||||
hookSystemWakeLock()
|
|
||||||
/** Hook 聊天界面 */
|
|
||||||
hookQQBaseChatPie()
|
|
||||||
/** Hook CoreService */
|
|
||||||
hookCoreService()
|
|
||||||
/** Hook QQ 不省电的功能 */
|
|
||||||
hookQQDisgusting()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -36,10 +36,14 @@ import com.fankes.tsbattery.hook.factory.jumpToModuleSettings
|
|||||||
import com.fankes.tsbattery.hook.factory.startModuleSettings
|
import com.fankes.tsbattery.hook.factory.startModuleSettings
|
||||||
import com.fankes.tsbattery.utils.factory.absoluteStatusBarHeight
|
import com.fankes.tsbattery.utils.factory.absoluteStatusBarHeight
|
||||||
import com.fankes.tsbattery.utils.factory.dp
|
import com.fankes.tsbattery.utils.factory.dp
|
||||||
|
import com.fankes.tsbattery.utils.factory.versionCode
|
||||||
|
import com.fankes.tsbattery.utils.factory.versionName
|
||||||
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.log.loggerD
|
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.type.android.BundleClass
|
import com.highcapable.yukihookapi.hook.type.android.BundleClass
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -52,57 +56,76 @@ object WeChatHooker : YukiBaseHooker() {
|
|||||||
/** 微信存在的类 - 未测试每个版本是否都存在 */
|
/** 微信存在的类 - 未测试每个版本是否都存在 */
|
||||||
const val LauncherUIClass = "${PackageName.WECHAT}.ui.LauncherUI"
|
const val LauncherUIClass = "${PackageName.WECHAT}.ui.LauncherUI"
|
||||||
|
|
||||||
|
/** 微信存在的类 - 未测试每个版本是否都存在 */
|
||||||
|
private const val EmptyActivityClass = "${PackageName.WECHAT}.ui.EmptyActivity"
|
||||||
|
|
||||||
|
/** 微信存在的类 - 未测试每个版本是否都存在 */
|
||||||
|
private const val WelabMainUIClass = "${PackageName.WECHAT}.plugin.welab.ui.WelabMainUI"
|
||||||
|
|
||||||
/** 微信存在的类 - 未测试每个版本是否都存在 */
|
/** 微信存在的类 - 未测试每个版本是否都存在 */
|
||||||
private const val SettingsUIClass = "${PackageName.WECHAT}.plugin.setting.ui.setting.SettingsUI"
|
private const val SettingsUIClass = "${PackageName.WECHAT}.plugin.setting.ui.setting.SettingsUI"
|
||||||
|
|
||||||
override fun onHook() {
|
override fun onHook() {
|
||||||
/** Hook 跳转事件 */
|
onAppLifecycle {
|
||||||
LauncherUIClass.hook {
|
onCreate {
|
||||||
injectMember {
|
ConfigData.init(context = this)
|
||||||
method {
|
registerModuleAppActivities(
|
||||||
name = "onResume"
|
when {
|
||||||
emptyParam()
|
EmptyActivityClass.hasClass() -> EmptyActivityClass
|
||||||
}
|
WelabMainUIClass.hasClass() -> WelabMainUIClass
|
||||||
afterHook { instance<Activity>().jumpToModuleSettings(isFinish = false) }
|
else -> error("Inject WeChat Activity Proxy failed, unsupport version $versionName($versionCode)")
|
||||||
|
}
|
||||||
|
)
|
||||||
|
if (ConfigData.isDisableAllHook) return@onCreate
|
||||||
|
hookSystemWakeLock()
|
||||||
|
loggerI(msg = "All processes are completed for \"${processName.takeIf { it != packageName } ?: packageName}\"")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/** 向设置界面右上角添加按钮 */
|
/** 仅注入主进程 */
|
||||||
SettingsUIClass.hook {
|
withProcess(mainProcessName) {
|
||||||
injectMember {
|
/** Hook 跳转事件 */
|
||||||
method {
|
LauncherUIClass.hook {
|
||||||
name = "onCreate"
|
injectMember {
|
||||||
param(BundleClass)
|
|
||||||
}
|
|
||||||
afterHook {
|
|
||||||
method {
|
method {
|
||||||
name = "get_fragment"
|
name = "onResume"
|
||||||
emptyParam()
|
emptyParam()
|
||||||
superClass(isOnlySuperClass = true)
|
}
|
||||||
}.get(instance).call()?.current()
|
afterHook { instance<Activity>().jumpToModuleSettings(isFinish = false) }
|
||||||
?.field { name = "mController" }
|
}
|
||||||
?.current()?.method { name = "getContentView" }
|
}
|
||||||
?.invoke<ViewGroup>()?.addView(LinearLayout(instance()).apply {
|
/** 向设置界面右上角添加按钮 */
|
||||||
context.injectModuleAppResources()
|
SettingsUIClass.hook {
|
||||||
gravity = Gravity.END or Gravity.BOTTOM
|
injectMember {
|
||||||
layoutParams = ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)
|
method {
|
||||||
addView(ImageView(context).apply {
|
name = "onCreate"
|
||||||
layoutParams = ViewGroup.MarginLayoutParams(20.dp(context), 20.dp(context)).apply {
|
param(BundleClass)
|
||||||
topMargin = context.absoluteStatusBarHeight + 15.dp(context)
|
}
|
||||||
rightMargin = 20.dp(context)
|
afterHook {
|
||||||
}
|
method {
|
||||||
setColorFilter(ResourcesCompat.getColor(resources, R.color.colorTextGray, null))
|
name = "get_fragment"
|
||||||
setImageResource(R.drawable.ic_icon)
|
emptyParam()
|
||||||
if (Build.VERSION.SDK_INT >= 26) tooltipText = "TSBattery 设置"
|
superClass(isOnlySuperClass = true)
|
||||||
setOnClickListener { context.startModuleSettings() }
|
}.get(instance).call()?.current()
|
||||||
|
?.field { name = "mController" }
|
||||||
|
?.current()?.method { name = "getContentView" }
|
||||||
|
?.invoke<ViewGroup>()?.addView(LinearLayout(instance()).apply {
|
||||||
|
context.injectModuleAppResources()
|
||||||
|
gravity = Gravity.END or Gravity.BOTTOM
|
||||||
|
layoutParams = ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)
|
||||||
|
addView(ImageView(context).apply {
|
||||||
|
layoutParams = ViewGroup.MarginLayoutParams(20.dp(context), 20.dp(context)).apply {
|
||||||
|
topMargin = context.absoluteStatusBarHeight + 15.dp(context)
|
||||||
|
rightMargin = 20.dp(context)
|
||||||
|
}
|
||||||
|
setColorFilter(ResourcesCompat.getColor(resources, R.color.colorTextGray, null))
|
||||||
|
setImageResource(R.drawable.ic_icon)
|
||||||
|
if (Build.VERSION.SDK_INT >= 26) tooltipText = "TSBattery 设置"
|
||||||
|
setOnClickListener { context.startModuleSettings() }
|
||||||
|
})
|
||||||
})
|
})
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (ConfigData.isDisableAllHook) return
|
|
||||||
/** Hook 系统电源锁 */
|
|
||||||
hookSystemWakeLock()
|
|
||||||
/** 日志省电大法 */
|
|
||||||
loggerD(msg = "ウイチャット:それが機能するかどうかはわかりませんでした")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -24,15 +24,45 @@ package com.fankes.tsbattery.hook.factory
|
|||||||
import android.app.Activity
|
import android.app.Activity
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
|
import androidx.appcompat.app.AppCompatDelegate
|
||||||
import com.fankes.tsbattery.const.JumpEvent
|
import com.fankes.tsbattery.const.JumpEvent
|
||||||
|
import com.fankes.tsbattery.const.PackageName
|
||||||
|
import com.fankes.tsbattery.hook.entity.QQTIMHooker.toClass
|
||||||
import com.fankes.tsbattery.ui.activity.parasitic.ConfigActivity
|
import com.fankes.tsbattery.ui.activity.parasitic.ConfigActivity
|
||||||
import com.highcapable.yukihookapi.YukiHookAPI
|
import com.highcapable.yukihookapi.YukiHookAPI
|
||||||
|
import com.highcapable.yukihookapi.hook.bean.VariousClass
|
||||||
|
import com.highcapable.yukihookapi.hook.factory.field
|
||||||
|
import com.highcapable.yukihookapi.hook.factory.method
|
||||||
import com.highcapable.yukihookapi.hook.param.PackageParam
|
import com.highcapable.yukihookapi.hook.param.PackageParam
|
||||||
import com.highcapable.yukihookapi.hook.type.android.PowerManager_WakeLockClass
|
import com.highcapable.yukihookapi.hook.type.android.PowerManager_WakeLockClass
|
||||||
import kotlin.system.exitProcess
|
import kotlin.system.exitProcess
|
||||||
|
|
||||||
|
/** QQ、TIM 存在的类 */
|
||||||
|
private const val MobileQQClass = "mqq.app.MobileQQ"
|
||||||
|
|
||||||
|
/** QQ、TIM 存在的类 */
|
||||||
|
private val ThemeUtilClass = VariousClass("${PackageName.QQ}.theme.ThemeUtil", "${PackageName.QQ}.vas.theme.api.ThemeUtil")
|
||||||
|
|
||||||
|
/**
|
||||||
|
* QQ、TIM 主题是否为夜间模式
|
||||||
|
* @return [Boolean]
|
||||||
|
*/
|
||||||
|
private fun Context.isQQNightMode() = runCatching {
|
||||||
|
ThemeUtilClass.get(classLoader).method {
|
||||||
|
name = "getUserCurrentThemeId"
|
||||||
|
paramCount = 1
|
||||||
|
}.get().string(MobileQQClass.toClass(classLoader)
|
||||||
|
.field { name = "sMobileQQ" }.ignored().get().current(ignored = true)?.field { name = "mAppRuntime" }?.any()
|
||||||
|
).let { it.endsWith(suffix = "1103") || it.endsWith(suffix = "2920") }
|
||||||
|
}.getOrNull() ?: false
|
||||||
|
|
||||||
/** 启动模块设置 [Activity] */
|
/** 启动模块设置 [Activity] */
|
||||||
fun Context.startModuleSettings() = startActivity(Intent(this, ConfigActivity::class.java))
|
fun Context.startModuleSettings() {
|
||||||
|
/** 为 QQ、TIM 适配夜间模式 */
|
||||||
|
if (packageName == PackageName.QQ || packageName == PackageName.TIM)
|
||||||
|
AppCompatDelegate.setDefaultNightMode(if (isQQNightMode()) AppCompatDelegate.MODE_NIGHT_YES else AppCompatDelegate.MODE_NIGHT_NO)
|
||||||
|
startActivity(Intent(this, ConfigActivity::class.java))
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 跳转模块设置 [Activity]
|
* 跳转模块设置 [Activity]
|
||||||
|
@@ -53,7 +53,7 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
|
|||||||
"8.8.20", "8.8.23", "8.8.28", "8.8.33", "8.8.35", "8.8.38", "8.8.50",
|
"8.8.20", "8.8.23", "8.8.28", "8.8.33", "8.8.35", "8.8.38", "8.8.50",
|
||||||
"8.8.55", "8.8.68", "8.8.80", "8.8.83", "8.8.85", "8.8.88", "8.8.90",
|
"8.8.55", "8.8.68", "8.8.80", "8.8.83", "8.8.85", "8.8.88", "8.8.90",
|
||||||
"8.8.93", "8.8.95", "8.8.98", "8.9.0", "8.9.1", "8.9.2", "8.9.3",
|
"8.8.93", "8.8.95", "8.8.98", "8.9.0", "8.9.1", "8.9.2", "8.9.3",
|
||||||
"8.9.5", "8.9.8", "8.9.10"
|
"8.9.5", "8.9.8", "8.9.10", "8.9.13"
|
||||||
)
|
)
|
||||||
private val qqSupportVersion by lazy {
|
private val qqSupportVersion by lazy {
|
||||||
if (qqSupportVersions.isNotEmpty()) {
|
if (qqSupportVersions.isNotEmpty()) {
|
||||||
|
@@ -19,12 +19,13 @@
|
|||||||
*
|
*
|
||||||
* This file is Created by fankes on 2022/9/28.
|
* This file is Created by fankes on 2022/9/28.
|
||||||
*/
|
*/
|
||||||
@file:Suppress("SetTextI18n")
|
@file:Suppress("SetTextI18n", "DEPRECATION")
|
||||||
|
|
||||||
package com.fankes.tsbattery.ui.activity.parasitic
|
package com.fankes.tsbattery.ui.activity.parasitic
|
||||||
|
|
||||||
import android.content.ComponentName
|
import android.content.ComponentName
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
|
import android.content.res.Resources
|
||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
import androidx.core.view.isGone
|
import androidx.core.view.isGone
|
||||||
import androidx.core.view.isVisible
|
import androidx.core.view.isVisible
|
||||||
@@ -34,6 +35,7 @@ import com.fankes.tsbattery.data.ConfigData
|
|||||||
import com.fankes.tsbattery.data.ConfigData.bind
|
import com.fankes.tsbattery.data.ConfigData.bind
|
||||||
import com.fankes.tsbattery.databinding.ActivityConfigBinding
|
import com.fankes.tsbattery.databinding.ActivityConfigBinding
|
||||||
import com.fankes.tsbattery.hook.HookEntry
|
import com.fankes.tsbattery.hook.HookEntry
|
||||||
|
import com.fankes.tsbattery.hook.entity.QQTIMHooker
|
||||||
import com.fankes.tsbattery.ui.activity.MainActivity
|
import com.fankes.tsbattery.ui.activity.MainActivity
|
||||||
import com.fankes.tsbattery.ui.activity.base.BaseActivity
|
import com.fankes.tsbattery.ui.activity.base.BaseActivity
|
||||||
import com.fankes.tsbattery.utils.factory.*
|
import com.fankes.tsbattery.utils.factory.*
|
||||||
@@ -117,6 +119,17 @@ class ConfigActivity : BaseActivity<ActivityConfigBinding>() {
|
|||||||
text = text.toString().replace(oldValue = "{APP_NAME}", appName)
|
text = text.toString().replace(oldValue = "{APP_NAME}", appName)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** 重新设置 DPI 防止 QQ、TIM 修改它 */
|
||||||
|
override fun getResources(): Resources? = super.getResources().apply {
|
||||||
|
if (packageName == PackageName.QQ || packageName == PackageName.TIM)
|
||||||
|
QQTIMHooker.baseConfiguration?.also {
|
||||||
|
updateConfiguration(configuration.apply {
|
||||||
|
fontScale = it.fontScale
|
||||||
|
densityDpi = it.densityDpi
|
||||||
|
}, displayMetrics)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取当前 APP 名称
|
* 获取当前 APP 名称
|
||||||
* @return [String]
|
* @return [String]
|
||||||
|
@@ -132,7 +132,7 @@ class DialogBuilder(val context: Context) {
|
|||||||
|
|
||||||
/** 显示对话框 */
|
/** 显示对话框 */
|
||||||
@CauseProblemsApi
|
@CauseProblemsApi
|
||||||
fun show() {
|
fun show() = runInSafe {
|
||||||
instance?.create()?.apply {
|
instance?.create()?.apply {
|
||||||
customLayoutView?.let { setView(it) }
|
customLayoutView?.let { setView(it) }
|
||||||
dialogInstance = this
|
dialogInstance = this
|
||||||
|
@@ -5,8 +5,8 @@ plugins {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ext {
|
ext {
|
||||||
appVersionName = "4.0"
|
appVersionName = "4.1"
|
||||||
appVersionCode = 25
|
appVersionCode = 26
|
||||||
enableR8 = true
|
enableR8 = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user