diff --git a/app/src/main/java/com/fankes/tsbattery/const/ConstFactory.kt b/app/src/main/java/com/fankes/tsbattery/const/ConstFactory.kt index 2063b81..2bb9689 100644 --- a/app/src/main/java/com/fankes/tsbattery/const/ConstFactory.kt +++ b/app/src/main/java/com/fankes/tsbattery/const/ConstFactory.kt @@ -19,8 +19,13 @@ * * This file is Created by fankes on 2022/9/29. */ +@file:Suppress("MemberVisibilityCanBePrivate") + package com.fankes.tsbattery.const +import com.fankes.tsbattery.generated.AppProperties +import com.fankes.tsbattery.wrapper.BuildConfigWrapper + /** * 包名常量定义类 */ @@ -43,4 +48,27 @@ object JumpEvent { /** 启动模块设置 */ const val OPEN_MODULE_SETTING = "tsbattery_open_module_settings" +} + +/** + * 模块版本常量定义类 + */ +object ModuleVersion { + + /** 当前 GitHub 提交的 ID (CI 自动构建) */ + const val GITHUB_COMMIT_ID = AppProperties.GITHUB_CI_COMMIT_ID + + /** 版本名称 */ + const val NAME = BuildConfigWrapper.VERSION_NAME + + /** 版本号 */ + const val CODE = BuildConfigWrapper.VERSION_CODE + + /** 是否为 CI 自动构建版本 */ + val isCiMode = GITHUB_COMMIT_ID.isNotBlank() + + /** 当前版本名称后缀 */ + val suffix = GITHUB_COMMIT_ID.let { if (it.isNotBlank()) "-$it" else "" } + + override fun toString() = "$NAME$suffix($CODE)" } \ No newline at end of file diff --git a/app/src/main/java/com/fankes/tsbattery/hook/entity/QQTIMHooker.kt b/app/src/main/java/com/fankes/tsbattery/hook/entity/QQTIMHooker.kt index e9f8c6b..197124b 100644 --- a/app/src/main/java/com/fankes/tsbattery/hook/entity/QQTIMHooker.kt +++ b/app/src/main/java/com/fankes/tsbattery/hook/entity/QQTIMHooker.kt @@ -19,6 +19,8 @@ * * This file is Created by fankes on 2022/9/29. */ +@file:Suppress("ConstPropertyName") + package com.fankes.tsbattery.hook.entity import android.app.Activity @@ -30,8 +32,8 @@ import android.view.View import android.view.ViewGroup import androidx.core.app.ServiceCompat import androidx.fragment.app.Fragment -import com.fankes.tsbattery.BuildConfig import com.fankes.tsbattery.R +import com.fankes.tsbattery.const.ModuleVersion import com.fankes.tsbattery.const.PackageName import com.fankes.tsbattery.data.ConfigData import com.fankes.tsbattery.hook.HookEntry @@ -43,13 +45,31 @@ import com.fankes.tsbattery.utils.factory.appVersionName import com.fankes.tsbattery.utils.factory.dp import com.highcapable.yukihookapi.hook.bean.VariousClass import com.highcapable.yukihookapi.hook.entity.YukiBaseHooker -import com.highcapable.yukihookapi.hook.factory.* +import com.highcapable.yukihookapi.hook.factory.buildOf +import com.highcapable.yukihookapi.hook.factory.current +import com.highcapable.yukihookapi.hook.factory.field +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.registerModuleAppActivities import com.highcapable.yukihookapi.hook.log.loggerD 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.* -import com.highcapable.yukihookapi.hook.type.java.* +import com.highcapable.yukihookapi.hook.type.android.BuildClass +import com.highcapable.yukihookapi.hook.type.android.BundleClass +import com.highcapable.yukihookapi.hook.type.android.ContextClass +import com.highcapable.yukihookapi.hook.type.android.IntentClass +import com.highcapable.yukihookapi.hook.type.android.MessageClass +import com.highcapable.yukihookapi.hook.type.java.AnyArrayClass +import com.highcapable.yukihookapi.hook.type.java.AnyClass +import com.highcapable.yukihookapi.hook.type.java.BooleanType +import com.highcapable.yukihookapi.hook.type.java.CharSequenceClass +import com.highcapable.yukihookapi.hook.type.java.IntType +import com.highcapable.yukihookapi.hook.type.java.ListClass +import com.highcapable.yukihookapi.hook.type.java.LongType +import com.highcapable.yukihookapi.hook.type.java.StringClass +import com.highcapable.yukihookapi.hook.type.java.UnitType import java.lang.reflect.Proxy /** @@ -647,7 +667,7 @@ object QQTIMHooker : YukiBaseHooker() { method { name = "setRightText" param(CharSequenceClass) - }.call("${BuildConfig.VERSION_NAME}(${BuildConfig.VERSION_CODE})") + }.call(ModuleVersion.toString()) method { name = "setBgType" param(IntType) @@ -676,9 +696,10 @@ object QQTIMHooker : YukiBaseHooker() { /** 不注入此进程防止部分系统发生 X5 浏览器内核崩溃问题 */ if (processName.startsWith(privilegedProcessName)) return@onCreate ConfigData.init(context = this) - if (isQQNTVersion) - registerModuleAppActivities(GeneralSettingActivityClass) - else registerModuleAppActivities(AboutActivityClass) + registerModuleAppActivities(when { + isQQNTVersion -> GeneralSettingActivityClass + else -> AboutActivityClass + }) if (ConfigData.isDisableAllHook) return@onCreate hookSystemWakeLock() hookQQBaseChatPie() diff --git a/app/src/main/java/com/fankes/tsbattery/hook/entity/WeChatHooker.kt b/app/src/main/java/com/fankes/tsbattery/hook/entity/WeChatHooker.kt index 46c2f2d..30c29d9 100644 --- a/app/src/main/java/com/fankes/tsbattery/hook/entity/WeChatHooker.kt +++ b/app/src/main/java/com/fankes/tsbattery/hook/entity/WeChatHooker.kt @@ -19,6 +19,8 @@ * * This file is Created by fankes on 2022/9/29. */ +@file:Suppress("ConstPropertyName") + package com.fankes.tsbattery.hook.entity import android.app.Activity @@ -95,13 +97,11 @@ object WeChatHooker : YukiBaseHooker() { onAppLifecycle { onCreate { ConfigData.init(context = this) - registerModuleAppActivities( - when { - EmptyActivityClass.hasClass() -> EmptyActivityClass - WelabMainUIClass.hasClass() -> WelabMainUIClass - else -> error("Inject WeChat Activity Proxy failed, unsupport version $appVersionName($appVersionCode)") - } - ) + registerModuleAppActivities(when { + EmptyActivityClass.hasClass() -> EmptyActivityClass + WelabMainUIClass.hasClass() -> WelabMainUIClass + else -> error("Inject WeChat Activity Proxy failed, unsupport version $appVersionName($appVersionCode)") + }) if (ConfigData.isDisableAllHook) return@onCreate hookSystemWakeLock() loggerI(msg = "All processes are completed for \"${processName.takeIf { it != packageName } ?: packageName}\"") diff --git a/app/src/main/java/com/fankes/tsbattery/ui/activity/MainActivity.kt b/app/src/main/java/com/fankes/tsbattery/ui/activity/MainActivity.kt index 82dad36..9dce7ec 100644 --- a/app/src/main/java/com/fankes/tsbattery/ui/activity/MainActivity.kt +++ b/app/src/main/java/com/fankes/tsbattery/ui/activity/MainActivity.kt @@ -27,17 +27,24 @@ import android.content.ComponentName import android.content.Intent import android.view.HapticFeedbackConstants import androidx.core.view.isVisible -import com.fankes.tsbattery.BuildConfig +import com.fankes.projectpromote.ProjectPromote import com.fankes.tsbattery.R import com.fankes.tsbattery.const.JumpEvent +import com.fankes.tsbattery.const.ModuleVersion import com.fankes.tsbattery.const.PackageName import com.fankes.tsbattery.databinding.ActivityMainBinding import com.fankes.tsbattery.hook.entity.QQTIMHooker import com.fankes.tsbattery.hook.entity.WeChatHooker import com.fankes.tsbattery.ui.activity.base.BaseActivity -import com.fankes.tsbattery.utils.factory.* +import com.fankes.tsbattery.utils.factory.appVersionBrandOf +import com.fankes.tsbattery.utils.factory.hideOrShowLauncherIcon +import com.fankes.tsbattery.utils.factory.isInstall +import com.fankes.tsbattery.utils.factory.isLauncherIconShowing +import com.fankes.tsbattery.utils.factory.openBrowser +import com.fankes.tsbattery.utils.factory.showDialog +import com.fankes.tsbattery.utils.factory.snake import com.fankes.tsbattery.utils.tool.GithubReleaseTool -import com.fankes.tsbattery.utils.tool.YukiPromoteTool +import com.fankes.tsbattery.wrapper.BuildConfigWrapper import com.highcapable.yukihookapi.YukiHookAPI class MainActivity : BaseActivity() { @@ -65,16 +72,13 @@ class MainActivity : BaseActivity() { "${value.trim().let { it.substring(0, it.lastIndex) }}\n\n其余版本请自行测试是否有效。" } else "empty" } - private const val timSupportVersion = "2+、3+ (并未完全测试每个版本)。" - private const val wechatSupportVersion = "全版本仅支持基础省电,更多功能依然画饼。" - - /** 预发布的版本标识 */ - private const val pendingFlag = "" + private const val TIM_SUPPORT_VERSION = "2+、3+ (并未完全测试每个版本)。" + private const val WECHAT_SUPPORT_VERSION = "全版本仅支持基础省电,更多功能依然画饼。" } override fun onCreate() { /** 检查更新 */ - GithubReleaseTool.checkingForUpdate(context = this, BuildConfig.VERSION_NAME) { version, function -> + GithubReleaseTool.checkingForUpdate(context = this, ModuleVersion.NAME) { version, function -> binding.mainTextReleaseVersion.apply { text = "点击更新 $version" isVisible = true @@ -89,7 +93,7 @@ class MainActivity : BaseActivity() { binding.mainTextApiWay.isVisible = true refreshActivateExecutor() /** 推广、恰饭 */ - YukiPromoteTool.promote(context = this) + ProjectPromote.show(activity = this, ModuleVersion.toString()) } else showDialog { title = "模块没有激活" @@ -102,7 +106,27 @@ class MainActivity : BaseActivity() { binding.mainTextTimVer.text = PackageName.TIM.takeIf { isInstall(it) }?.let { appVersionBrandOf(it) } ?: "未安装" binding.mainTextWechatVer.text = PackageName.WECHAT.takeIf { isInstall(it) }?.let { appVersionBrandOf(it) } ?: "未安装" /** 设置文本 */ - binding.mainTextVersion.text = "模块版本:${BuildConfig.VERSION_NAME} $pendingFlag" + binding.mainTextVersion.text = "模块版本:${ModuleVersion.NAME}" + /** 设置 CI 自动构建标识 */ + if (ModuleVersion.isCiMode) + binding.mainTextReleaseVersion.apply { + text = "CI ${ModuleVersion.GITHUB_COMMIT_ID}" + isVisible = true + setOnClickListener { + showDialog { + title = "CI 自动构建说明" + msg = """ + 你正在使用的是 CI 自动构建版本,Commit ID 为 ${ModuleVersion.GITHUB_COMMIT_ID}。 + + 它是由代码提交后自动触发并构建、自动编译发布的,并未经任何稳定性测试,使用风险自负。 + + CI 构建的版本不支持太极 (也请不要提交 CI 版本的适配,因为它们是不稳定的),你可以使用 LSPosed / LSPatch。 + """.trimIndent() + confirmButton(text = "我知道了") + noCancelable() + } + } + } binding.mainQqItem.setOnClickListener { showDialog { title = "兼容的 QQ 版本" @@ -115,7 +139,7 @@ class MainActivity : BaseActivity() { binding.mainTimItem.setOnClickListener { showDialog { title = "兼容的 TIM 版本" - msg = timSupportVersion + msg = TIM_SUPPORT_VERSION confirmButton(text = "我知道了") } /** 振动提醒 */ @@ -124,7 +148,7 @@ class MainActivity : BaseActivity() { binding.mainWechatItem.setOnClickListener { showDialog { title = "兼容的微信版本" - msg = wechatSupportVersion + msg = WECHAT_SUPPORT_VERSION confirmButton(text = "我知道了") } /** 振动提醒 */ @@ -148,6 +172,11 @@ class MainActivity : BaseActivity() { if (btn.isPressed.not()) return@setOnCheckedChangeListener hideOrShowLauncherIcon(b) } + /** 判断当前启动模式 */ + if (packageName != BuildConfigWrapper.APPLICATION_ID) { + binding.quickActionItem.isVisible = false + binding.displaySettingItem.isVisible = false + } } /** diff --git a/app/src/main/java/com/fankes/tsbattery/ui/activity/parasitic/ConfigActivity.kt b/app/src/main/java/com/fankes/tsbattery/ui/activity/parasitic/ConfigActivity.kt index b42afcd..d96cf33 100644 --- a/app/src/main/java/com/fankes/tsbattery/ui/activity/parasitic/ConfigActivity.kt +++ b/app/src/main/java/com/fankes/tsbattery/ui/activity/parasitic/ConfigActivity.kt @@ -29,7 +29,8 @@ import android.content.res.Resources import android.widget.TextView import androidx.core.view.isGone import androidx.core.view.isVisible -import com.fankes.tsbattery.BuildConfig +import com.fankes.projectpromote.ProjectPromote +import com.fankes.tsbattery.const.ModuleVersion import com.fankes.tsbattery.const.PackageName import com.fankes.tsbattery.data.ConfigData import com.fankes.tsbattery.data.ConfigData.bind @@ -38,8 +39,14 @@ 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.base.BaseActivity -import com.fankes.tsbattery.utils.factory.* +import com.fankes.tsbattery.utils.factory.appIconOf +import com.fankes.tsbattery.utils.factory.appNameOf +import com.fankes.tsbattery.utils.factory.appVersionCode +import com.fankes.tsbattery.utils.factory.appVersionName +import com.fankes.tsbattery.utils.factory.showDialog +import com.fankes.tsbattery.utils.factory.snake import com.fankes.tsbattery.utils.tool.GithubReleaseTool +import com.fankes.tsbattery.wrapper.BuildConfigWrapper import com.highcapable.yukihookapi.YukiHookAPI import kotlin.system.exitProcess @@ -47,7 +54,7 @@ class ConfigActivity : BaseActivity() { override fun onCreate() { /** 检查更新 */ - GithubReleaseTool.checkingForUpdate(context = this, BuildConfig.VERSION_NAME) { version, function -> + GithubReleaseTool.checkingForUpdate(context = this, ModuleVersion.NAME) { version, function -> binding.updateVersionText.apply { text = "点击更新 $version" isVisible = true @@ -58,14 +65,18 @@ class ConfigActivity : BaseActivity() { binding.titleModuleIcon.setOnClickListener { showDialog { title = "打开模块主界面" - msg = "点击确定后将打开模块主界面,如果未安装模块本体将会无法打开。" + msg = "点击确定后将打开模块主界面,如果未安装模块本体将尝试打开寄生界面。" confirmButton { runCatching { startActivity(Intent().apply { - component = ComponentName(BuildConfig.APPLICATION_ID, MainActivity::class.java.name) + component = ComponentName(BuildConfigWrapper.APPLICATION_ID, MainActivity::class.java.name) flags = Intent.FLAG_ACTIVITY_NEW_TASK }) - }.onFailure { snake(msg = "打开失败,请确认你已安装模块 APP\n$it") } + }.onFailure { + runCatching { + startActivity(Intent(this@ConfigActivity, MainActivity::class.java)) + }.onFailure { snake(msg = "打开失败,请确认你已安装模块 APP 或在模块更新后重启过$appName\n$it") } + } } cancelButton() } @@ -73,8 +84,8 @@ class ConfigActivity : BaseActivity() { binding.titleNameText.text = "TSBattery 设置 (${appName.trim()})" binding.appIcon.setImageDrawable(appIconOf()) binding.appName.text = appName.trim() - binding.appVersion.text = "${appVersionName}($appVersionCode)" - binding.moduleVersion.text = "${BuildConfig.VERSION_NAME}(${BuildConfig.VERSION_CODE})" + binding.appVersion.text = "$appVersionName($appVersionCode)" + binding.moduleVersion.text = ModuleVersion.toString() binding.activeModeIcon.isVisible = HookEntry.isHookClientSupport binding.inactiveModeIcon.isGone = HookEntry.isHookClientSupport binding.unsupportItem.isGone = HookEntry.isHookClientSupport @@ -116,6 +127,8 @@ class ConfigActivity : BaseActivity() { binding.qqTimProtectModeSwitch.bind(ConfigData.ENABLE_QQ_TIM_PROTECT_MODE) { refreshCurrentModeText(); showNeedRestartTip() } binding.qqTimCoreServiceSwitch.bind(ConfigData.ENABLE_KILL_QQ_TIM_CORESERVICE) { showNeedRestartTip() } binding.qqTimCoreServiceChildSwitch.bind(ConfigData.ENABLE_KILLE_QQ_TIM_CORESERVICE_CHILD) { showNeedRestartTip() } + /** 推广、恰饭 */ + ProjectPromote.show(activity = this, ModuleVersion.toString()) } /** 显示需要重新启动提示 */ diff --git a/app/src/main/java/com/fankes/tsbattery/utils/factory/FunctionFactory.kt b/app/src/main/java/com/fankes/tsbattery/utils/factory/FunctionFactory.kt index 870f42c..22761b0 100644 --- a/app/src/main/java/com/fankes/tsbattery/utils/factory/FunctionFactory.kt +++ b/app/src/main/java/com/fankes/tsbattery/utils/factory/FunctionFactory.kt @@ -40,7 +40,7 @@ import android.provider.Settings import android.widget.Toast import androidx.core.content.getSystemService import androidx.core.content.pm.PackageInfoCompat -import com.fankes.tsbattery.BuildConfig +import com.fankes.tsbattery.wrapper.BuildConfigWrapper import com.google.android.material.snackbar.Snackbar import com.highcapable.yukihookapi.hook.xposed.application.ModuleApplication.Companion.appContext @@ -227,7 +227,7 @@ fun Context.openBrowser(url: String, packageName: String = "") = runCatching { */ fun Context.hideOrShowLauncherIcon(isShow: Boolean) { packageManager?.setComponentEnabledSetting( - ComponentName(packageName, "${BuildConfig.APPLICATION_ID}.Home"), + ComponentName(packageName, "${BuildConfigWrapper.APPLICATION_ID}.Home"), if (isShow) PackageManager.COMPONENT_ENABLED_STATE_DISABLED else PackageManager.COMPONENT_ENABLED_STATE_ENABLED, PackageManager.DONT_KILL_APP ) @@ -239,5 +239,5 @@ fun Context.hideOrShowLauncherIcon(isShow: Boolean) { */ val Context.isLauncherIconShowing get() = packageManager?.getComponentEnabledSetting( - ComponentName(packageName, "${BuildConfig.APPLICATION_ID}.Home") + ComponentName(packageName, "${BuildConfigWrapper.APPLICATION_ID}.Home") ) != PackageManager.COMPONENT_ENABLED_STATE_DISABLED \ No newline at end of file diff --git a/app/src/main/java/com/fankes/tsbattery/utils/tool/YukiPromoteTool.kt b/app/src/main/java/com/fankes/tsbattery/utils/tool/YukiPromoteTool.kt deleted file mode 100644 index 9cf388e..0000000 --- a/app/src/main/java/com/fankes/tsbattery/utils/tool/YukiPromoteTool.kt +++ /dev/null @@ -1,59 +0,0 @@ -/* - * TSBattery - A new way to save your battery avoid cancer apps hacker it. - * Copyright (C) 2017-2023 Fankes Studio(qzmmcn@163.com) - * https://github.com/fankes/TSBattery - * - * This software is non-free but opensource software: you can redistribute it - * and/or modify it under the terms of the GNU Affero General Public License - * as published by the Free Software Foundation; either - * version 3 of the License, or any later version. - * - * This software is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * and eula along with this software. If not, see - * - * - * This file is Created by fankes on 2022/5/30. - */ -package com.fankes.tsbattery.utils.tool - -import android.content.Context -import com.fankes.tsbattery.BuildConfig -import com.fankes.tsbattery.utils.factory.openBrowser -import com.fankes.tsbattery.utils.factory.showDialog -import com.highcapable.yukihookapi.YukiHookAPI -import com.highcapable.yukihookapi.hook.factory.prefs -import com.highcapable.yukihookapi.hook.xposed.prefs.data.PrefsData - -/** - * [YukiHookAPI] 的自动推广工具类 - */ -object YukiPromoteTool { - - /** 推广已读存储键值 */ - private val YUKI_PROMOTE_READED = PrefsData("yuki_promote_readed_${BuildConfig.VERSION_NAME}", false) - - /** - * 显示推广对话框 - * @param context 实例 - */ - fun promote(context: Context) { - fun saveReaded() = context.prefs().edit { put(YUKI_PROMOTE_READED, value = true) } - if (context.prefs().get(YUKI_PROMOTE_READED).not()) - context.showDialog { - title = "面向开发者的推广" - msg = "你想快速拥有一个自己的 Xposed 模块吗,你只需要拥有基础的 Android 开发经验以及使用 Kotlin 编程语言即可。\n\n" + - "快来体验 YukiHookAPI,这是一个使用 Kotlin 构建的高效 Hook API 与 Xposed 模块解决方案,助你的开发变得更轻松。" - confirmButton(text = "去看看") { - context.openBrowser(url = "https://github.com/fankes/YukiHookAPI") - saveReaded() - } - cancelButton(text = "我不是开发者") { saveReaded() } - noCancelable() - } - } -} \ No newline at end of file diff --git a/app/src/main/java/com/fankes/tsbattery/wrapper/BuildConfigWrapper.kt b/app/src/main/java/com/fankes/tsbattery/wrapper/BuildConfigWrapper.kt new file mode 100644 index 0000000..212bb2c --- /dev/null +++ b/app/src/main/java/com/fankes/tsbattery/wrapper/BuildConfigWrapper.kt @@ -0,0 +1,36 @@ +/* + * TSBattery - A new way to save your battery avoid cancer apps hacker it. + * Copyright (C) 2017-2023 Fankes Studio(qzmmcn@163.com) + * https://github.com/fankes/TSBattery + * + * This software is non-free but opensource software: you can redistribute it + * and/or modify it under the terms of the GNU Affero General Public License + * as published by the Free Software Foundation; either + * version 3 of the License, or any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * and eula along with this software. If not, see + * + * + * This file is created by fankes on 2023/9/16. + */ +@file:Suppress("unused") + +package com.fankes.tsbattery.wrapper + +import com.fankes.tsbattery.BuildConfig + +/** + * 对 [BuildConfig] 的包装 + */ +object BuildConfigWrapper { + const val APPLICATION_ID = BuildConfig.APPLICATION_ID + const val VERSION_NAME = BuildConfig.VERSION_NAME + const val VERSION_CODE = BuildConfig.VERSION_CODE + val isDebug = BuildConfig.DEBUG +} \ No newline at end of file