diff --git a/.idea/gradle.xml b/.idea/gradle.xml
index 5cd135a..e9969a1 100644
--- a/.idea/gradle.xml
+++ b/.idea/gradle.xml
@@ -4,9 +4,10 @@
-
+
+
diff --git a/.idea/jarRepositories.xml b/.idea/jarRepositories.xml
index 0380d8d..688795e 100644
--- a/.idea/jarRepositories.xml
+++ b/.idea/jarRepositories.xml
@@ -26,5 +26,20 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
index 860da66..6199cc2 100644
--- a/.idea/misc.xml
+++ b/.idea/misc.xml
@@ -1,6 +1,6 @@
-
+
diff --git a/.idea/runConfigurations.xml b/.idea/runConfigurations.xml
deleted file mode 100644
index 797acea..0000000
--- a/.idea/runConfigurations.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/README.md b/README.md
index f695e19..38986f1 100644
--- a/README.md
+++ b/README.md
@@ -1,7 +1,44 @@
# TSBattery
+
+
+
+
TSBattery a new way to save your battery avoid cancer apps hacker it.
TSBattery 是一个旨在使 QQ、TIM 变得更省电的开源 Xposed 模块
-# Get startted
-此模块支持原生 Xposed、Lsposed(作用域 QQ、TIM 如果不起作用勾选系统框架)、EdXposed(不推荐)、太极无极(阴和阳)、Pine(梦境模块)
+# 开始使用
+点击下载最新版本
+
+
+⚠️适配说明:此模块支持原生 Xposed、Lsposed(作用域 QQ、TIM 如果不起作用勾选系统框架)、EdXposed(不推荐)、太极无极(阴和阳)、Pine(梦境模块)
# 禁止任何商业用途
本模块完全开源免费,如果好用你可以打赏支持开发,严禁未经许可进行二改贩卖,违者必惩必究。
+# 开始贡献
+欢迎为此项目进行新版本的适配代码贡献!
+## 代码规范:
+### 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,除特殊情况外,不接受其他语言的提交
\ No newline at end of file
diff --git a/app/build.gradle b/app/build.gradle
index 2b81a0a..b092488 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -20,10 +20,10 @@ android {
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'
}
\ No newline at end of file
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index bf604dc..73bee2c 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -29,8 +29,10 @@
android:value="82" />
+
@@ -40,8 +42,10 @@
+ android:targetActivity="com.fankes.tsbattery.ui.MainActivity">
+
diff --git a/app/src/main/java/com/fankes/tsbattery/hook/HookMain.kt b/app/src/main/java/com/fankes/tsbattery/hook/HookMain.kt
index 495c018..292d684 100644
--- a/app/src/main/java/com/fankes/tsbattery/hook/HookMain.kt
+++ b/app/src/main/java/com/fankes/tsbattery/hook/HookMain.kt
@@ -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,37 +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适配
+ /** 贡献者:JiZhi-Error */
"8.8.50" -> {
- replaceToNull("activity.aio.core.BaseChatPie", "bj")//remainScreenOn
- replaceToNull("activity.aio.core.BaseChatPie", "bk")//cancelRemainScreenOn
+ replaceToNull(BASE_CHAT_PIE, "bj")
+ replaceToNull(BASE_CHAT_PIE, "bk")
}
else -> logD("$version not supported!")
}
@@ -132,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,
@@ -150,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,
@@ -170,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 都是一样的类
@@ -190,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
@@ -217,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",
@@ -246,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") {
/**
* 一个不知道是什么作用的电源锁
* 同样直接干掉
@@ -268,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(),无限耍流氓耗电
@@ -317,10 +315,8 @@ class HookMain : IXposedHookLoadPackage {
"run",
replaceToNull
)
- } catch (e: Exception) {
- logE("handleLoadPackage: hook QQLSActivity Failed", e)
}
- try {
+ runWithoutError("WakerLockMonitor") {
/**
* 这个是毒瘤核心类
* WakeLockMonitor
@@ -394,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!")
}
}
}
diff --git a/app/src/main/java/com/fankes/tsbattery/hook/HookMedium.kt b/app/src/main/java/com/fankes/tsbattery/hook/HookMedium.kt
index 620e231..b0273d6 100644
--- a/app/src/main/java/com/fankes/tsbattery/hook/HookMedium.kt
+++ b/app/src/main/java/com/fankes/tsbattery/hook/HookMedium.kt
@@ -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 {
diff --git a/app/src/main/java/com/fankes/tsbattery/MainActivity.kt b/app/src/main/java/com/fankes/tsbattery/ui/MainActivity.kt
similarity index 98%
rename from app/src/main/java/com/fankes/tsbattery/MainActivity.kt
rename to app/src/main/java/com/fankes/tsbattery/ui/MainActivity.kt
index 04fa960..0fcd8a6 100644
--- a/app/src/main/java/com/fankes/tsbattery/MainActivity.kt
+++ b/app/src/main/java/com/fankes/tsbattery/ui/MainActivity.kt
@@ -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
diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml
index 849dff9..004145b 100644
--- a/app/src/main/res/layout/activity_main.xml
+++ b/app/src/main/res/layout/activity_main.xml
@@ -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">