10 Commits
4.25 ... 4.3

10 changed files with 202 additions and 96 deletions

View File

@@ -2,7 +2,7 @@
[![Blank](https://img.shields.io/badge/build-passing-brightgreen)](https://github.com/fankes/TSBattery) [![Blank](https://img.shields.io/badge/build-passing-brightgreen)](https://github.com/fankes/TSBattery)
[![Blank](https://img.shields.io/badge/license-AGPL3.0-blue)](https://github.com/fankes/TSBattery/blob/master/LICENSE) [![Blank](https://img.shields.io/badge/license-AGPL3.0-blue)](https://github.com/fankes/TSBattery/blob/master/LICENSE)
[![Blank](https://img.shields.io/badge/version-v4.25-green)](https://github.com/fankes/TSBattery/releases) [![Blank](https://img.shields.io/badge/version-v4.3-green)](https://github.com/fankes/TSBattery/releases)
[![Blank](https://img.shields.io/github/downloads/fankes/TSBattery/total?label=Release)](https://github.com/fankes/TSBattery/releases) [![Blank](https://img.shields.io/github/downloads/fankes/TSBattery/total?label=Release)](https://github.com/fankes/TSBattery/releases)
[![Blank](https://img.shields.io/github/downloads/Xposed-Modules-Repo/com.fankes.tsbattery/total?label=LSPosed%20Repo&logo=Android&style=flat&labelColor=F48FB1&logoColor=ffffff)](https://github.com/Xposed-Modules-Repo/com.fankes.tsbattery/releases) [![Blank](https://img.shields.io/github/downloads/Xposed-Modules-Repo/com.fankes.tsbattery/total?label=LSPosed%20Repo&logo=Android&style=flat&labelColor=F48FB1&logoColor=ffffff)](https://github.com/Xposed-Modules-Repo/com.fankes.tsbattery/releases)
[![Telegram](https://img.shields.io/badge/Follow-Telegram-blue.svg?logo=telegram)](https://t.me/XiaofangInternet) [![Telegram](https://img.shields.io/badge/Follow-Telegram-blue.svg?logo=telegram)](https://t.me/XiaofangInternet)

View File

@@ -72,13 +72,13 @@ android {
dependencies { dependencies {
compileOnly 'de.robv.android.xposed:api:82' compileOnly 'de.robv.android.xposed:api:82'
implementation 'com.highcapable.yukihookapi:api:1.1.9' implementation 'com.highcapable.yukihookapi:api:1.1.11'
ksp 'com.highcapable.yukihookapi:ksp-xposed:1.1.9' ksp 'com.highcapable.yukihookapi:ksp-xposed:1.1.11'
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.10.0' implementation 'androidx.core:core-ktx:1.10.1'
implementation 'androidx.appcompat:appcompat:1.6.1' implementation 'androidx.appcompat:appcompat:1.6.1'
implementation 'com.google.android.material:material:1.8.0' implementation 'com.google.android.material:material:1.9.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.4' implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
testImplementation 'junit:junit:4.13.2' testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.5' androidTestImplementation 'androidx.test.ext:junit:1.1.5'

View File

@@ -37,6 +37,12 @@
# 排除注入的 Activity # 排除注入的 Activity
-keep class com.fankes.tsbattery.ui.activity.parasitic.ConfigActivity -keep class com.fankes.tsbattery.ui.activity.parasitic.ConfigActivity
# 防止某些类被 R8 混淆 (可能是 BUG)
# FIXME: 已知问题字符串类名 (即使是常量) 也会被 R8 处理为混淆后的类名
# FIXME: 所以目前只能把不允许 R8 处理的类 keep 掉,同时在当前模块中也不会被混淆就是了
-keep class kotlin.Unit
-keep class kotlin.jvm.functions.Function0
-assumenosideeffects class kotlin.jvm.internal.Intrinsics { -assumenosideeffects class kotlin.jvm.internal.Intrinsics {
public static *** throwUninitializedProperty(...); public static *** throwUninitializedProperty(...);
public static *** throwUninitializedPropertyAccessException(...); public static *** throwUninitializedPropertyAccessException(...);

View File

@@ -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.Context
import android.content.res.Configuration import android.content.res.Configuration
import android.os.Build import android.os.Build
import android.view.View import android.view.View
@@ -30,10 +31,12 @@ import android.view.ViewGroup
import androidx.core.app.ServiceCompat import androidx.core.app.ServiceCompat
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import com.fankes.tsbattery.BuildConfig import com.fankes.tsbattery.BuildConfig
import com.fankes.tsbattery.R
import com.fankes.tsbattery.const.PackageName import com.fankes.tsbattery.const.PackageName
import com.fankes.tsbattery.data.ConfigData import com.fankes.tsbattery.data.ConfigData
import com.fankes.tsbattery.hook.HookEntry import com.fankes.tsbattery.hook.HookEntry
import com.fankes.tsbattery.hook.factory.hookSystemWakeLock import com.fankes.tsbattery.hook.factory.hookSystemWakeLock
import com.fankes.tsbattery.hook.factory.isQQNightMode
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.appVersionName import com.fankes.tsbattery.utils.factory.appVersionName
@@ -47,6 +50,7 @@ import com.highcapable.yukihookapi.hook.log.loggerI
import com.highcapable.yukihookapi.hook.log.loggerW import com.highcapable.yukihookapi.hook.log.loggerW
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.*
import java.lang.reflect.Proxy
/** /**
* Hook QQ、TIM * Hook QQ、TIM
@@ -56,15 +60,24 @@ object QQTIMHooker : YukiBaseHooker() {
/** QQ、TIM 存在的类 */ /** QQ、TIM 存在的类 */
const val JumpActivityClass = "${PackageName.QQ}.activity.JumpActivity" const val JumpActivityClass = "${PackageName.QQ}.activity.JumpActivity"
/** QQ、TIM 存在的类 */ /** QQ、TIM 存在的类 (NT 版本不再存在) */
private const val QQSettingSettingActivityClass = "${PackageName.QQ}.activity.QQSettingSettingActivity" private const val QQSettingSettingActivityClass = "${PackageName.QQ}.activity.QQSettingSettingActivity"
/** QQ 新版存在的类 (Pad 模式) */ /** QQ 新版存在的类 (Pad 模式 - NT 版本不再存在) */
private const val QQSettingSettingFragmentClass = "${PackageName.QQ}.fragment.QQSettingSettingFragment" private const val QQSettingSettingFragmentClass = "${PackageName.QQ}.fragment.QQSettingSettingFragment"
/** QQ、TIM 存在的类 */ /** QQ、TIM 存在的类 (NT 版本不再存在) */
private const val AboutActivityClass = "${PackageName.QQ}.activity.AboutActivity" private const val AboutActivityClass = "${PackageName.QQ}.activity.AboutActivity"
/** QQ 新版本存在的类 */
private const val GeneralSettingActivityClass = "${PackageName.QQ}.activity.GeneralSettingActivity"
/** QQ 新版本 (NT) 存在的类 */
private const val MainSettingFragmentClass = "${PackageName.QQ}.setting.main.MainSettingFragment"
/** QQ 新版本 (NT) 存在的类 */
private const val MainSettingConfigProviderClass = "${PackageName.QQ}.setting.main.MainSettingConfigProvider"
/** QQ、TIM 新版本存在的类 */ /** QQ、TIM 新版本存在的类 */
private const val FormSimpleItemClass = "${PackageName.QQ}.widget.FormSimpleItem" private const val FormSimpleItemClass = "${PackageName.QQ}.widget.FormSimpleItem"
@@ -78,8 +91,7 @@ object QQTIMHooker : YukiBaseHooker() {
private const val CoreService_KernelServiceClass = "${PackageName.QQ}.app.CoreService\$KernelService" private const val CoreService_KernelServiceClass = "${PackageName.QQ}.app.CoreService\$KernelService"
/** 根据多个版本存的不同的类 */ /** 根据多个版本存的不同的类 */
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")
/** 一个内部进程的名称 (与 X5 浏览器内核有关) */ /** 一个内部进程的名称 (与 X5 浏览器内核有关) */
private val privilegedProcessName = "$packageName:privileged_process" private val privilegedProcessName = "$packageName:privileged_process"
@@ -93,6 +105,14 @@ object QQTIMHooker : YukiBaseHooker() {
*/ */
private val isQQ get() = packageName == PackageName.QQ private val isQQ get() = packageName == PackageName.QQ
/**
* 当前是否为 QQ 的 NT 版本
*
* 在 QQ NT 中 [AboutActivityClass] 已被移除 - 以此作为判断条件
* @return [Boolean]
*/
private val isQQNTVersion get() = isQQ && AboutActivityClass.hasClass().not()
/** 当前宿主的版本 */ /** 当前宿主的版本 */
private var hostVersionName = "<unknown>" private var hostVersionName = "<unknown>"
@@ -122,128 +142,140 @@ object QQTIMHooker : YukiBaseHooker() {
private fun hookQQBaseChatPie() { private fun hookQQBaseChatPie() {
if (isQQ) when (hostVersionName) { if (isQQ) when (hostVersionName) {
"8.0.0" -> { "8.0.0" -> {
hookBaseChatPie(methodName = "bq") hookBaseChatPie("bq")
hookBaseChatPie(methodName = "aL") hookBaseChatPie("aL")
} }
"8.0.5", "8.0.7" -> { "8.0.5", "8.0.7" -> {
hookBaseChatPie(methodName = "bw") hookBaseChatPie("bw")
hookBaseChatPie(methodName = "aQ") hookBaseChatPie("aQ")
} }
"8.1.0", "8.1.3" -> { "8.1.0", "8.1.3" -> {
hookBaseChatPie(methodName = "bE") hookBaseChatPie("bE")
hookBaseChatPie(methodName = "aT") hookBaseChatPie("aT")
} }
"8.1.5" -> { "8.1.5" -> {
hookBaseChatPie(methodName = "bF") hookBaseChatPie("bF")
hookBaseChatPie(methodName = "aT") hookBaseChatPie("aT")
} }
"8.1.8", "8.2.0", "8.2.6" -> { "8.1.8", "8.2.0", "8.2.6" -> {
hookBaseChatPie(methodName = "bC") hookBaseChatPie("bC")
hookBaseChatPie(methodName = "aT") hookBaseChatPie("aT")
} }
"8.2.7", "8.2.8", "8.2.11", "8.3.0" -> { "8.2.7", "8.2.8", "8.2.11", "8.3.0" -> {
hookBaseChatPie(methodName = "bE") hookBaseChatPie("bE")
hookBaseChatPie(methodName = "aV") hookBaseChatPie("aV")
} }
"8.3.5" -> { "8.3.5" -> {
hookBaseChatPie(methodName = "bR") hookBaseChatPie("bR")
hookBaseChatPie(methodName = "aX") hookBaseChatPie("aX")
} }
"8.3.6" -> { "8.3.6" -> {
hookBaseChatPie(methodName = "cp") hookBaseChatPie("cp")
hookBaseChatPie(methodName = "aX") hookBaseChatPie("aX")
} }
"8.3.9" -> { "8.3.9" -> {
hookBaseChatPie(methodName = "cj") hookBaseChatPie("cj")
hookBaseChatPie(methodName = "aT") hookBaseChatPie("aT")
} }
"8.4.1", "8.4.5" -> { "8.4.1", "8.4.5" -> {
hookBaseChatPie(methodName = "ck") hookBaseChatPie("ck")
hookBaseChatPie(methodName = "aT") hookBaseChatPie("aT")
} }
"8.4.8", "8.4.10", "8.4.17", "8.4.18", "8.5.0" -> { "8.4.8", "8.4.10", "8.4.17", "8.4.18", "8.5.0" -> {
hookBaseChatPie(methodName = "remainScreenOn") hookBaseChatPie("remainScreenOn")
hookBaseChatPie(methodName = "cancelRemainScreenOn") hookBaseChatPie("cancelRemainScreenOn")
} }
"8.5.5" -> { "8.5.5" -> {
hookBaseChatPie(methodName = "bT") hookBaseChatPie("bT")
hookBaseChatPie(methodName = "aN") hookBaseChatPie("aN")
} }
"8.6.0", "8.6.5", "8.7.0", "8.7.5", "8.7.8", "8.8.0", "8.8.3", "8.8.5" -> { "8.6.0", "8.6.5", "8.7.0", "8.7.5", "8.7.8", "8.8.0", "8.8.3", "8.8.5" -> {
hookBaseChatPie(methodName = "ag") hookBaseChatPie("ag")
hookBaseChatPie(methodName = "ah") hookBaseChatPie("ah")
} }
"8.8.11", "8.8.12" -> { "8.8.11", "8.8.12" -> {
hookBaseChatPie(methodName = "bc") hookBaseChatPie("bc")
hookBaseChatPie(methodName = "bd") hookBaseChatPie("bd")
} }
"8.8.17", "8.8.20" -> { "8.8.17", "8.8.20" -> {
hookBaseChatPie(methodName = "bd") hookBaseChatPie("bd")
hookBaseChatPie(methodName = "be") hookBaseChatPie("be")
} }
"8.8.23", "8.8.28" -> { "8.8.23", "8.8.28" -> {
hookBaseChatPie(methodName = "bf") hookBaseChatPie("bf")
hookBaseChatPie(methodName = "bg") hookBaseChatPie("bg")
} }
"8.8.33" -> { "8.8.33" -> {
hookBaseChatPie(methodName = "bg") hookBaseChatPie("bg")
hookBaseChatPie(methodName = "bh") hookBaseChatPie("bh")
} }
"8.8.35", "8.8.38" -> { "8.8.35", "8.8.38" -> {
hookBaseChatPie(methodName = "bi") hookBaseChatPie("bi")
hookBaseChatPie(methodName = "bj") hookBaseChatPie("bj")
} }
"8.8.50" -> { "8.8.50" -> {
hookBaseChatPie(methodName = "bj") hookBaseChatPie("bj")
hookBaseChatPie(methodName = "bk") hookBaseChatPie("bk")
} }
"8.8.55", "8.8.68", "8.8.80" -> { "8.8.55", "8.8.68", "8.8.80" -> {
hookBaseChatPie(methodName = "bk") hookBaseChatPie("bk")
hookBaseChatPie(methodName = "bl") hookBaseChatPie("bl")
} }
"8.8.83", "8.8.85", "8.8.88", "8.8.90" -> { "8.8.83", "8.8.85", "8.8.88", "8.8.90" -> {
hookBaseChatPie(methodName = "bl") hookBaseChatPie("bl")
hookBaseChatPie(methodName = "bm") hookBaseChatPie("bm")
} }
"8.8.93", "8.8.95" -> { "8.8.93", "8.8.95" -> {
hookBaseChatPie(methodName = "J3") hookBaseChatPie("J3")
hookBaseChatPie(methodName = "S") hookBaseChatPie("S")
} }
"8.8.98" -> { "8.8.98" -> {
hookBaseChatPie(methodName = "M3") hookBaseChatPie("M3")
hookBaseChatPie(methodName = "S") hookBaseChatPie("S")
} }
"8.9.0", "8.9.1", "8.9.2" -> { "8.9.0", "8.9.1", "8.9.2" -> {
hookBaseChatPie(methodName = "N3") hookBaseChatPie("N3")
hookBaseChatPie(methodName = "S") hookBaseChatPie("S")
} }
"8.9.3", "8.9.5" -> { "8.9.3", "8.9.5" -> {
hookBaseChatPie(methodName = "H3") hookBaseChatPie("H3")
hookBaseChatPie(methodName = "P") hookBaseChatPie("P")
} }
"8.9.8", "8.9.10" -> { "8.9.8", "8.9.10" -> {
hookBaseChatPie(methodName = "H3") hookBaseChatPie("H3")
hookBaseChatPie(methodName = "N") hookBaseChatPie("N")
} }
"8.9.13" -> { "8.9.13" -> {
hookBaseChatPie(methodName = "y3") hookBaseChatPie("y3")
hookBaseChatPie(methodName = "H") hookBaseChatPie("H")
} }
"8.9.15", "8.9.18", "8.9.19", "8.9.20" -> { "8.9.15", "8.9.18", "8.9.19", "8.9.20" -> {
hookBaseChatPie(methodName = "w3") hookBaseChatPie("w3")
hookBaseChatPie(methodName = "H") hookBaseChatPie("H")
} }
"8.9.23", "8.9.25" -> { "8.9.23", "8.9.25" -> {
hookBaseChatPie(methodName = "z3") hookBaseChatPie("z3")
hookBaseChatPie(methodName = "H") hookBaseChatPie("H")
} }
"8.9.28", "8.9.30", "8.9.33" -> { "8.9.28", "8.9.30", "8.9.33" -> {
hookBaseChatPie(methodName = "A3") hookBaseChatPie("A3")
hookBaseChatPie(methodName = "H") hookBaseChatPie("H")
} }
"8.9.35", "8.9.38", "8.9.50" -> { "8.9.35", "8.9.38", "8.9.50" -> {
hookBaseChatPie(methodName = "B3") hookBaseChatPie("B3")
hookBaseChatPie(methodName = "H") hookBaseChatPie("H")
}
"8.9.53", "8.9.55", "8.9.58" -> {
hookBaseChatPie("C3")
hookBaseChatPie("H")
}
"8.9.63", "8.9.68" -> {
hookBaseChatPie("t3")
hookBaseChatPie("J")
}
"8.9.70" -> {
hookBaseChatPie("u3")
hookBaseChatPie("J")
} }
else -> { else -> {
HookEntry.isHookClientSupport = false HookEntry.isHookClientSupport = false
@@ -536,11 +568,68 @@ object QQTIMHooker : YukiBaseHooker() {
}.ignoredHookClassNotFoundFailure() }.ignoredHookClassNotFoundFailure()
} }
/** Hook QQ 的设置界面添加模块设置入口 (新版) */
private fun hookQQSettingsUi() {
if (MainSettingFragmentClass.hasClass().not()) return loggerE(msg = "Could not found main setting class, hook aborted")
val kotlinUnit = "kotlin.Unit"
val kotlinFunction0 = "kotlin.jvm.functions.Function0"
val simpleItemProcessorClass = searchClass {
from("${PackageName.QQ}.setting.processor").absolute()
constructor { param(ContextClass, IntType, CharSequenceClass, IntType) }
method {
param(kotlinFunction0)
returnType = UnitType
}
field().count { it >= 6 }
}.get() ?: return loggerE(msg = "Could not found processor class, hook aborted")
/**
* 创建入口点条目
* @param context 当前实例
* @return [Any]
*/
fun createTSEntryItem(context: Context): Any {
/** 为了使用图标资源 ID - 这里需要重新注入模块资源防止不生效 */
context.injectModuleAppResources()
val iconResId = if (context.isQQNightMode()) R.mipmap.ic_tsbattery_entry_night else R.mipmap.ic_tsbattery_entry_day
return simpleItemProcessorClass.buildOf(context, R.id.tsbattery_qq_entry_item_id, "TSBattery", iconResId) {
param(ContextClass, IntType, CharSequenceClass, IntType)
}?.also { entryItem ->
val onClickMethod = simpleItemProcessorClass.method {
param { it[0].name == kotlinFunction0 }
paramCount = 1
returnType = UnitType
}.giveAll().lastOrNull() ?: error("Could not found processor method")
val proxyOnClick = Proxy.newProxyInstance(appClassLoader, arrayOf(onClickMethod.parameterTypes[0])) { any, method, args ->
if (method.name == "invoke") {
context.startModuleSettings()
kotlinUnit.toClass().field { name = "INSTANCE" }.get().any()
} else method.invoke(any, args)
}; 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)
})
}
}
}
}
/** /**
* Hook QQ 的设置界面添加模块设置入口 * Hook QQ 的设置界面添加模块设置入口 (旧版)
* @param instance 当前设置界面实例 * @param instance 当前设置界面实例
*/ */
private fun hookQQSettingsUI(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.name == FormSimpleItemClass || it.name == FormCommonSingleLineItemClass }.index(num = 1)
@@ -583,7 +672,9 @@ object QQTIMHooker : YukiBaseHooker() {
/** 不注入此进程防止部分系统发生 X5 浏览器内核崩溃问题 */ /** 不注入此进程防止部分系统发生 X5 浏览器内核崩溃问题 */
if (processName.startsWith(privilegedProcessName)) return@onCreate if (processName.startsWith(privilegedProcessName)) return@onCreate
ConfigData.init(context = this) ConfigData.init(context = this)
registerModuleAppActivities(AboutActivityClass) if (isQQNTVersion)
registerModuleAppActivities(GeneralSettingActivityClass)
else registerModuleAppActivities(AboutActivityClass)
if (ConfigData.isDisableAllHook) return@onCreate if (ConfigData.isDisableAllHook) return@onCreate
hookSystemWakeLock() hookSystemWakeLock()
hookQQBaseChatPie() hookQQBaseChatPie()
@@ -604,26 +695,30 @@ object QQTIMHooker : YukiBaseHooker() {
afterHook { instance<Activity>().jumpToModuleSettings() } afterHook { instance<Activity>().jumpToModuleSettings() }
} }
} }
/** 将条目注入设置界面 (Activity) */ /** Hook 设置界面入口点 */
QQSettingSettingActivityClass.hook { if (isQQNTVersion) hookQQSettingsUi()
injectMember { else {
method { /** 将条目注入设置界面 (Activity) */
name = "doOnCreate" QQSettingSettingActivityClass.hook {
param(BundleClass) injectMember {
method {
name = "doOnCreate"
param(BundleClass)
}
afterHook { hookQQSettingsUiLegacy(instance) }
} }
afterHook { hookQQSettingsUI(instance) }
} }
/** 将条目注入设置界面 (Fragment) */
QQSettingSettingFragmentClass.hook {
injectMember {
method {
name = "doOnCreateView"
paramCount = 3
}
afterHook { hookQQSettingsUiLegacy(instance) }
}
}.ignoredHookClassNotFoundFailure()
} }
/** 将条目注入设置界面 (Fragment) */
QQSettingSettingFragmentClass.hook {
injectMember {
method {
name = "doOnCreateView"
paramCount = 3
}
afterHook { hookQQSettingsUI(instance) }
}
}.ignoredHookClassNotFoundFailure()
} }
} }
} }

View File

@@ -47,7 +47,7 @@ private val ThemeUtilClass = VariousClass("${PackageName.QQ}.theme.ThemeUtil", "
* QQ、TIM 主题是否为夜间模式 * QQ、TIM 主题是否为夜间模式
* @return [Boolean] * @return [Boolean]
*/ */
private fun Context.isQQNightMode() = runCatching { fun Context.isQQNightMode() = runCatching {
ThemeUtilClass.get(classLoader).method { ThemeUtilClass.get(classLoader).method {
name = "getUserCurrentThemeId" name = "getUserCurrentThemeId"
paramCount = 1 paramCount = 1

View File

@@ -55,7 +55,8 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
"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.13", "8.9.15", "8.9.18", "8.9.19", "8.9.5", "8.9.8", "8.9.10", "8.9.13", "8.9.15", "8.9.18", "8.9.19",
"8.9.20", "8.9.23", "8.9.25", "8.9.28", "8.9.30", "8.9.33", "8.9.20", "8.9.23", "8.9.25", "8.9.28", "8.9.30", "8.9.33",
"8.9.35", "8.9.38", "8.9.50" "8.9.35", "8.9.38", "8.9.50", "8.9.53", "8.9.55", "8.9.58",
"8.9.63", "8.9.68", "8.9.70"
) )
private val qqSupportVersion by lazy { private val qqSupportVersion by lazy {
if (qqSupportVersions.isNotEmpty()) { if (qqSupportVersions.isNotEmpty()) {

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

View File

@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<item name="tsbattery_qq_entry_item_id" type="id" />
</resources>

View File

@@ -12,8 +12,8 @@ ext {
targetSdk : 33 targetSdk : 33
] ]
app = [ app = [
versionName : '4.25', versionName : '4.3',
versionCode : 28, versionCode : 29,
signingConfigs: [ signingConfigs: [
secretConfigsDirPath : "${projectDir.getAbsolutePath()}/.secret", secretConfigsDirPath : "${projectDir.getAbsolutePath()}/.secret",
secretConfigsFileName: "key_store_secret.json" secretConfigsFileName: "key_store_secret.json"