6 Commits
2.3 ... 2.4

Author SHA1 Message Date
23c94e4e26 Support QQ 8.8.50 Update version to 2.4 2021-11-27 19:18:24 +08:00
ead73eb23d Support QQ 8.8.50 Update version to 2.4 2021-11-27 19:16:50 +08:00
5d82e9a104 整理代码并更新依赖版本 2021-11-27 18:59:44 +08:00
Fankesyooni
14d1b9c5ac Merge pull request #4 from JiZhi-Error/master
Support QQ 8.8.50
2021-11-24 18:52:10 +08:00
JiZhi
44ea28edda Change the key file path to a relative path
Support QQ 8.8.50
2021-11-20 22:38:12 +08:00
b075fd8424 Update to 2.3 support QQ 8.8.38 2021-11-09 19:55:52 +08:00
16 changed files with 150 additions and 105 deletions

3
.idea/gradle.xml generated
View File

@@ -4,9 +4,10 @@
<component name="GradleSettings">
<option name="linkedExternalProjectsSettings">
<GradleProjectSettings>
<option name="testRunner" value="PLATFORM" />
<option name="testRunner" value="GRADLE" />
<option name="distributionType" value="DEFAULT_WRAPPED" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="gradleJvm" value="11" />
<option name="modules">
<set>
<option value="$PROJECT_DIR$" />

View File

@@ -26,5 +26,20 @@
<option name="name" value="Google" />
<option name="url" value="https://dl.google.com/dl/android/maven2/" />
</remote-repository>
<remote-repository>
<option name="id" value="maven3" />
<option name="name" value="maven3" />
<option name="url" value="https://www.jitpack.io" />
</remote-repository>
<remote-repository>
<option name="id" value="maven" />
<option name="name" value="maven" />
<option name="url" value="https://maven.aliyun.com/nexus/content/groups/public/" />
</remote-repository>
<remote-repository>
<option name="id" value="maven2" />
<option name="name" value="maven2" />
<option name="url" value="https://maven.aliyun.com/nexus/content/repositories/jcenter" />
</remote-repository>
</component>
</project>

2
.idea/misc.xml generated
View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectRootManager" version="2" languageLevel="JDK_11" default="true" project-jdk-name="1.8" project-jdk-type="JavaSDK">
<component name="ProjectRootManager" version="2" languageLevel="JDK_11" default="true" project-jdk-name="11" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/build/classes" />
</component>
<component name="ProjectType">

View File

@@ -1,10 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="RunConfigurationProducerService">
<option name="ignoredProducers">
<set>
<option value="com.android.tools.idea.compose.preview.runconfiguration.ComposePreviewRunConfigurationProducer" />
</set>
</option>
</component>
</project>

View File

@@ -1,7 +1,44 @@
# TSBattery
![Eclipse Marketplace](https://img.shields.io/badge/build-passing-brightgreen)
![Eclipse Marketplace](https://img.shields.io/badge/license-GPL3.0-blue)
![Eclipse Marketplace](https://img.shields.io/badge/version-v2.4-green)
<br/><br/>
TSBattery a new way to save your battery avoid cancer apps hacker it.<br/>
TSBattery 是一个旨在使 QQ、TIM 变得更省电的开源 Xposed 模块
# Get startted
此模块支持原生 Xposed、Lsposed(作用域 QQ、TIM 如果不起作用勾选系统框架)、EdXposed(不推荐)、太极无极(阴和阳)、Pine(梦境模块)
# 开始使用
点击下载最新版本
<a href='https://github.com/fankes/TSBattery/releases'>![Eclipse Marketplace](https://img.shields.io/badge/download-v2.4-green)</a>
<br/><br/>
⚠️适配说明:此模块支持原生 Xposed、Lsposed(作用域 QQ、TIM 如果不起作用勾选系统框架)、EdXposed(不推荐)、太极无极(阴和阳)、Pine(梦境模块)
# 禁止任何商业用途
本模块完全开源免费,如果好用你可以打赏支持开发,严禁未经许可进行二改贩卖,违者必惩必究。
# 开始贡献
欢迎为此项目进行新版本的适配代码贡献!<br/>
## 代码规范:
### 1.全部提交代码必须使用 IDE(Android Studio 或 IDEA) 进行格式化,未经格式化的代码将拒绝合并提交请求
### 2.代码必须使用 4 spaces 缩进格式化
### 3.代码注释规范:
1.第一种注释方式:可使用在方法名或顶级变量名上
```kotlin
/** 注释内容 */
fun a() {
}
/**
* 注释名称
* @param test 方法名称
* @return 返回值名称
*/
fun a(test: String) {
}
```
2.第二种注释方式:仅可使用在变量后方
```kotlin
val a = "" // 变量注释
```
⚠️注意:只允许两个 // 后方要有空格
### 4.调试性质或大批量注释代码,禁止提交
### 5.类名和方法名仅能由开发者进行修改和提交,禁止随意修改项目名称、方法名称以及类名
### 6.禁止随意更新项目依赖以及增加新的依赖,有问题请提前提交到 issues 进行说明
### 7.禁止更新项目版本号,版本号交由开发者合并代码并发布 release 版本
### 8.代码语言要求,请统一使用 Kotlin除特殊情况外不接受其他语言的提交

View File

@@ -6,7 +6,7 @@ plugins {
android {
signingConfigs {
debug {
storeFile file('/Users/fankes/ProjectPath/AndroidStudioProjects/TSBattery/keystore/public')
storeFile file('../keystore/public')
storePassword '123456'
keyAlias 'public'
keyPassword '123456'
@@ -14,16 +14,16 @@ android {
v2SigningEnabled true
}
}
compileSdkVersion 30
buildToolsVersion "30.0.3"
compileSdkVersion 31
buildToolsVersion "31.0.0"
defaultConfig {
applicationId "com.fankes.tsbattery"
minSdkVersion 22
//noinspection ExpiredTargetSdkVersion,OldTargetApi
targetSdkVersion 26
versionCode 6
versionName "2.3"
//noinspection ExpiredTargetSdkVersion
targetSdkVersion 28
versionCode 7
versionName "2.4"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
@@ -46,25 +46,18 @@ android {
dependencies {
compileOnly 'de.robv.android.xposed:api:82'
// 基础依赖包,必须要依赖
// 基础依赖包
implementation 'com.gyf.immersionbar:immersionbar:3.0.0'
// fragment快速实现(可选)
// Fragment 快速实现
implementation 'com.gyf.immersionbar:immersionbar-components:3.0.0'
// kotlin扩展(可选)
// Kotlin 扩展
implementation 'com.gyf.immersionbar:immersionbar-ktx:3.0.0'
//noinspection GradleDependency,DifferentStdlibGradleVersion
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
//noinspection GradleDependency
implementation 'androidx.core:core-ktx:1.5.0'
//noinspection GradleDependency
implementation 'androidx.appcompat:appcompat:1.3.0'
//noinspection GradleDependency
implementation 'com.google.android.material:material:1.3.0'
//noinspection GradleDependency
implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
implementation 'androidx.core:core-ktx:1.7.0'
implementation 'androidx.appcompat:appcompat:1.4.0'
implementation 'com.google.android.material:material:1.4.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.2'
testImplementation 'junit:junit:4.13.2'
//noinspection GradleDependency
androidTestImplementation 'androidx.test.ext:junit:1.1.2'
//noinspection GradleDependency
androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
}

Binary file not shown.

View File

@@ -1,18 +1,20 @@
{
"version": 2,
"version": 3,
"artifactType": {
"type": "APK",
"kind": "Directory"
},
"applicationId": "com.fankes.tsbattery",
"variantName": "processReleaseResources",
"variantName": "release",
"elements": [
{
"type": "SINGLE",
"filters": [],
"versionCode": 5,
"versionName": "2.2",
"attributes": [],
"versionCode": 7,
"versionName": "2.4",
"outputFile": "app-release.apk"
}
]
],
"elementType": "File"
}

View File

@@ -29,8 +29,10 @@
android:value="82" />
<activity
android:name="com.fankes.tsbattery.MainActivity"
android:name="com.fankes.tsbattery.ui.MainActivity"
android:exported="true"
android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="de.robv.android.xposed.category.MODULE_SETTINGS" />
@@ -40,8 +42,10 @@
<activity-alias
android:name="com.fankes.tsbattery.Home"
android:enabled="true"
android:exported="true"
android:label="@string/app_name"
android:targetActivity="com.fankes.tsbattery.MainActivity">
android:targetActivity="com.fankes.tsbattery.ui.MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />

View File

@@ -16,7 +16,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* This file is Created by fankes on 2021/9/4.
* This file is Created by fankes on 2021/11/9.
*/
@file:Suppress("unused")

View File

@@ -27,7 +27,6 @@ import android.app.AlertDialog
import android.os.Build
import android.os.Bundle
import android.util.Log
import android.widget.Toast
import androidx.annotation.Keep
import com.fankes.tsbattery.utils.XPrefUtils
import de.robv.android.xposed.*
@@ -37,6 +36,11 @@ import java.util.*
@Keep
class HookMain : IXposedHookLoadPackage {
companion object {
private const val BASE_CHAT_PIE = "activity.aio.core.BaseChatPie"
}
/** 仅作用于替换的 Hook 方法体 */
private val replaceToNull = object : XC_MethodReplacement() {
override fun replaceHookedMethod(param: MethodHookParam?): Any? {
@@ -65,32 +69,51 @@ class HookMain : IXposedHookLoadPackage {
)
}
/**
* 忽略异常运行
* @param it 正常回调
*/
private fun runWithoutError(error: String, it: () -> Unit) {
try {
it()
} catch (e: Error) {
logE("hookFailed: $error", e)
} catch (e: Exception) {
logE("hookFailed: $error", e)
} catch (e: Throwable) {
logE("hookFailed: $error", e)
}
}
/**
* 这个类 BaseChatPie 是控制聊天界面的
* 里面有两个随机混淆的方法
* 里面有两个随机混淆的方法 ⬇️
* remainScreenOn、cancelRemainScreenOn
* 这两个方法一个是挂起电源锁常驻亮屏
* 一个是停止常驻亮屏
* 不由分说每个版本混淆的方法名都会变
* 所以说每个版本重新适配 - 也可以提交分支帮我适配
* 8.8.17 版本是 bd be
* 8.8.23 版本是 bf bg
* 8.8.38 版本是 bi bj
* ⚠️ Hook 错了方法会造成闪退!
* @param version QQ 版本
*/
private fun XC_LoadPackage.LoadPackageParam.hookBaseChatPie(version: String) {
when (version) {
"8.8.17" -> {
replaceToNull("activity.aio.core.BaseChatPie", "bd")
replaceToNull("activity.aio.core.BaseChatPie", "be")
replaceToNull(BASE_CHAT_PIE, "bd")
replaceToNull(BASE_CHAT_PIE, "be")
}
"8.8.23" -> {
replaceToNull("activity.aio.core.BaseChatPie", "bf")
replaceToNull("activity.aio.core.BaseChatPie", "bg")
replaceToNull(BASE_CHAT_PIE, "bf")
replaceToNull(BASE_CHAT_PIE, "bg")
}
"8.8.38" -> {
replaceToNull("activity.aio.core.BaseChatPie", "bi")
replaceToNull("activity.aio.core.BaseChatPie", "bj")
replaceToNull(BASE_CHAT_PIE, "bi")
replaceToNull(BASE_CHAT_PIE, "bj")
}
/** 贡献者JiZhi-Error */
"8.8.50" -> {
replaceToNull(BASE_CHAT_PIE, "bj")
replaceToNull(BASE_CHAT_PIE, "bk")
}
else -> logD("$version not supported!")
}
@@ -127,17 +150,15 @@ class HookMain : IXposedHookLoadPackage {
)
/** 经过测试 QQ 与 TIM 这两个是一个模子里面的东西,所以他们的类名也基本上是一样的 */
"com.tencent.mobileqq", "com.tencent.tim" -> {
try {
runWithoutError("wakeLock acquire()") {
XposedHelpers.findAndHookMethod(
"android.os.PowerManager\$WakeLock",
lpparam.classLoader,
"acquire",
replaceToNull
)
} catch (e: Throwable) {
logE("handleLoadPackage: hook wakeLock acquire() Failed", e)
}
try {
runWithoutError("hook wakeLock acquire(time)") {
XposedHelpers.findAndHookMethod(
"android.os.PowerManager\$WakeLock",
lpparam.classLoader,
@@ -145,11 +166,9 @@ class HookMain : IXposedHookLoadPackage {
Long::class.java,
replaceToNull
)
} catch (e: Throwable) {
logE("handleLoadPackage: hook wakeLock acquire(time) Failed", e)
}
/** 增加通知栏文本显示守护状态 */
try {
runWithoutError("Notification") {
XposedHelpers.findAndHookMethod(
"android.app.Notification\$Builder",
lpparam.classLoader,
@@ -165,12 +184,10 @@ class HookMain : IXposedHookLoadPackage {
}
}
})
} catch (e: Throwable) {
logE("handleLoadPackage: hook Notification Failed", e)
}
/** 判断是否开启提示模块运行信息 */
if (XPrefUtils.getBoolean(HookMedium.ENABLE_RUN_INFO))
try {
runWithoutError("SplashActivity") {
/**
* Hook 启动界面的第一个 [Activity]
* QQ 和 TIM 都是一样的类
@@ -185,7 +202,7 @@ class HookMain : IXposedHookLoadPackage {
override fun afterHookedMethod(param: MethodHookParam?) {
val self = param?.thisObject as? Activity ?: return
try {
runWithoutError("模块已激活,但显示信息弹窗失败了") {
AlertDialog.Builder(
self,
android.R.style.Theme_Material_Light_Dialog
@@ -212,21 +229,13 @@ class HookMain : IXposedHookLoadPackage {
)
.setPositiveButton("我知道了", null)
.show()
} catch (e: Exception) {
Toast.makeText(
self,
"模块已激活,但显示信息弹窗失败了\n$e",
Toast.LENGTH_SHORT
).show()
}
}
})
} catch (e: Exception) {
logE("handleLoadPackage: hook SplashActivity Failed", e)
}
/** 关闭保守模式后不再仅仅作用于系统电源锁 */
if (!XPrefUtils.getBoolean(HookMedium.ENABLE_WHITE_MODE)) {
try {
runWithoutError("BaseChatPie(first time)") {
/** 通过在 SplashActivity 里取到应用的版本号 */
XposedHelpers.findAndHookMethod(
"com.tencent.mobileqq.activity.SplashActivity",
@@ -241,18 +250,14 @@ class HookMain : IXposedHookLoadPackage {
val version =
self.packageManager.getPackageInfo(name, 0).versionName
/** 这个地方我们只处理 QQ */
try {
runWithoutError("BaseChatPie") {
if (name == "com.tencent.mobileqq")
lpparam.hookBaseChatPie(version)
} catch (e: Exception) {
logE("handleLoadPackage: hook BaseChatPie Failed", e)
}
}
})
} catch (e: Exception) {
logE("handleLoadPackage: hook BaseChatPie(first time) Failed", e)
}
try {
runWithoutError("WakerLock") {
/**
* 一个不知道是什么作用的电源锁
* 同样直接干掉
@@ -263,10 +268,8 @@ class HookMain : IXposedHookLoadPackage {
"lock", Long::class.java,
replaceToNull
)
} catch (e: Exception) {
logE("handleLoadPackage: hook WakerLock Failed", e)
}
try {
runWithoutError("QQLSActivity") {
/**
* Hook 掉一个一像素保活 [Activity] 真的我怎么都想不到讯哥的程序员做出这种事情
* 这个东西经过测试会在锁屏的时候吊起来,解锁的时候自动 finish(),无限耍流氓耗电
@@ -312,10 +315,8 @@ class HookMain : IXposedHookLoadPackage {
"run",
replaceToNull
)
} catch (e: Exception) {
logE("handleLoadPackage: hook QQLSActivity Failed", e)
}
try {
runWithoutError("WakerLockMonitor") {
/**
* 这个是毒瘤核心类
* WakeLockMonitor
@@ -389,10 +390,8 @@ class HookMain : IXposedHookLoadPackage {
XposedBridge.hookMethod(onProcessBG5Min, replaceToNull)
XposedBridge.hookMethod(writeReport, replaceToNull)
}
} catch (e: Throwable) {
logE("handleLoadPackage: hook WakerLockMonitor Failed", e)
}
logD("handleLoadPackage: hook Complete!")
logD("hook Completed!")
}
}
}

View File

@@ -16,7 +16,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* This file is Created by fankes on 2021/9/4.
* This file is Created by fankes on 2021/11/9.
*/
package com.fankes.tsbattery.hook
@@ -26,7 +26,7 @@ import android.net.Uri
import android.os.Bundle
import android.util.Log
import androidx.annotation.Keep
import com.fankes.tsbattery.MainActivity
import com.fankes.tsbattery.ui.MainActivity
@Keep
object HookMedium {

View File

@@ -23,7 +23,7 @@
"LocalVariableName", "SameParameterValue"
)
package com.fankes.tsbattery
package com.fankes.tsbattery.ui
import android.content.ComponentName
import android.content.Context
@@ -40,6 +40,8 @@ import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.widget.SwitchCompat
import androidx.constraintlayout.utils.widget.ImageFilterView
import com.fankes.tsbattery.BuildConfig
import com.fankes.tsbattery.R
import com.fankes.tsbattery.hook.HookMedium
import com.fankes.tsbattery.utils.FileUtils
import com.gyf.immersionbar.ImmersionBar
@@ -50,7 +52,7 @@ class MainActivity : AppCompatActivity() {
companion object {
private const val moduleVersion = BuildConfig.VERSION_NAME
private const val moduleSupport = "QQ 8.5.5~8.8.38、TIM 2+"
private const val moduleSupport = "QQ 8.5.5~8.8.50、TIM 2+"
/** 声明当前实例 */
var instance: MainActivity? = null

View File

@@ -4,7 +4,7 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity"
tools:context=".ui.MainActivity"
tools:ignore="HardcodedText">
<LinearLayout

View File

@@ -1,15 +1,15 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
ext.kotlin_version = "1.4.20"
ext.kotlin_version = "1.6.0"
repositories {
google()
//noinspection JcenterRepositoryObsolete
jcenter()
maven { url 'https://maven.aliyun.com/nexus/content/groups/public/' }
maven { url 'https://maven.aliyun.com/nexus/content/repositories/jcenter' }
maven { url "https://www.jitpack.io" }
mavenCentral()
}
dependencies {
//noinspection AndroidGradlePluginVersion
classpath "com.android.tools.build:gradle:4.1.1"
//noinspection DifferentKotlinGradleVersion
classpath "com.android.tools.build:gradle:7.0.3"
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
// NOTE: Do not place your application dependencies here; they belong
@@ -20,8 +20,10 @@ buildscript {
allprojects {
repositories {
google()
//noinspection JcenterRepositoryObsolete
jcenter()
maven { url 'https://maven.aliyun.com/nexus/content/groups/public/' }
maven { url 'https://maven.aliyun.com/nexus/content/repositories/jcenter' }
maven { url "https://www.jitpack.io" }
mavenCentral()
}
}

View File

@@ -1,6 +1,6 @@
#Sat Sep 04 04:05:23 CST 2021
distributionBase=GRADLE_USER_HOME
distributionUrl=https\://services.gradle.org/distributions/gradle-6.7.1-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-7.0.2-all.zip
distributionPath=wrapper/dists
zipStorePath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME