From 4430044d32decc40f84f1c66103f57bdea94c1c8 Mon Sep 17 00:00:00 2001 From: Diandd <87189302+Diandd@users.noreply.github.com> Date: Thu, 3 Jul 2025 22:15:21 +0800 Subject: [PATCH] feat: skip rewarded video ads (#1668) --- .../me/iacn/biliroaming/BiliBiliPackage.kt | 16 +++++++++++++ .../java/me/iacn/biliroaming/XposedInit.kt | 1 + .../me/iacn/biliroaming/hook/RewardAdHook.kt | 23 +++++++++++++++++++ .../proto/me/iacn/biliroaming/configs.proto | 6 +++++ app/src/main/res/values-zh-rTW/strings.xml | 2 ++ app/src/main/res/values/strings.xml | 2 ++ app/src/main/res/xml/prefs_setting.xml | 5 ++++ 7 files changed, 55 insertions(+) create mode 100644 app/src/main/java/me/iacn/biliroaming/hook/RewardAdHook.kt diff --git a/app/src/main/java/me/iacn/biliroaming/BiliBiliPackage.kt b/app/src/main/java/me/iacn/biliroaming/BiliBiliPackage.kt index f3e26cb3c5..0133d03586 100644 --- a/app/src/main/java/me/iacn/biliroaming/BiliBiliPackage.kt +++ b/app/src/main/java/me/iacn/biliroaming/BiliBiliPackage.kt @@ -182,6 +182,7 @@ class BiliBiliPackage constructor(private val mClassLoader: ClassLoader, mContex val pegasusParserClass by Weak { mHookInfo.pegasusParser from mClassLoader } val resolveClientCompanionClass by Weak { mHookInfo.resolveClientCompanion.class_ from mClassLoader } val videoDownloadEntryClass by Weak { "com.bilibili.videodownloader.model.VideoDownloadEntry" from mClassLoader } + val rewardAdClass by Weak { mHookInfo.rewardAd.class_ from mClassLoader } // for v8.17.0+ val useNewMossFunc = instance.viewMossClass?.declaredMethods?.any { @@ -366,6 +367,8 @@ class BiliBiliPackage constructor(private val mClassLoader: ClassLoader, mContex fun setExtraContentMethod() = mHookInfo.gCommonResolverParams.setExtraContent.orNull + fun rewardFlag() = mHookInfo.rewardAd.rewardFlag.orNull + private fun readHookInfo(context: Context): Configs.HookInfo { try { val hookInfoFile = File(context.cacheDir, Constant.HOOK_INFO_FILE_NAME) @@ -2382,6 +2385,19 @@ class BiliBiliPackage constructor(private val mClassLoader: ClassLoader, mContex class_ = class_ { name = commonResolverParamsClass.name } setExtraContent = method { name = setExtraContentMethod.name } } + rewardAd = rewardAd { + val rewardAdActivityClass = + "com.bilibili.ad.reward.RewardAdActivity".from(classloader) ?: return@rewardAd + + class_ = class_ { name = rewardAdActivityClass.name } + val rewardFlagField = + rewardAdActivityClass.declaredFields.filter { it.type == Boolean::class.javaPrimitiveType } + .getOrNull(1) ?: return@rewardAd + + rewardFlag = field { name = rewardFlagField.name } + + } + dexHelper.close() } diff --git a/app/src/main/java/me/iacn/biliroaming/XposedInit.kt b/app/src/main/java/me/iacn/biliroaming/XposedInit.kt index 40afaee674..a1ea0586a9 100644 --- a/app/src/main/java/me/iacn/biliroaming/XposedInit.kt +++ b/app/src/main/java/me/iacn/biliroaming/XposedInit.kt @@ -131,6 +131,7 @@ class XposedInit : IXposedHookLoadPackage, IXposedHookZygoteInit { startHook { WebViewHook(lpparam.classLoader) } startHook { ShareHook(lpparam.classLoader) } startHook { DialogBlurBackgroundHook(lpparam.classLoader) } + startHook { RewardAdHook(lpparam.classLoader) } } lpparam.processName.endsWith(":download") -> { diff --git a/app/src/main/java/me/iacn/biliroaming/hook/RewardAdHook.kt b/app/src/main/java/me/iacn/biliroaming/hook/RewardAdHook.kt new file mode 100644 index 0000000000..7ba8ebb66b --- /dev/null +++ b/app/src/main/java/me/iacn/biliroaming/hook/RewardAdHook.kt @@ -0,0 +1,23 @@ +package me.iacn.biliroaming.hook + +import android.os.Bundle +import android.widget.TextView +import me.iacn.biliroaming.BiliBiliPackage.Companion.instance +import me.iacn.biliroaming.utils.* + +class RewardAdHook(classLoader: ClassLoader) : BaseHook(classLoader) { + override fun startHook() { + + if (!sPrefs.getBoolean("skip_reward_ad", false)) return + + Log.d("startHook: RewardAd") + + instance.rewardAdClass?.hookAfterMethod("onCreate", Bundle::class.java) { params -> + params.thisObject.setBooleanField(instance.rewardFlag(), true) + (params.thisObject.javaClass.declaredFields.firstOrNull { + it.type == TextView::class.java + }?.apply { isAccessible = true }?.get(params.thisObject) as? TextView)?.performClick() + } + + } +} diff --git a/app/src/main/proto/me/iacn/biliroaming/configs.proto b/app/src/main/proto/me/iacn/biliroaming/configs.proto index 0c700d9bc4..546dce0dd3 100644 --- a/app/src/main/proto/me/iacn/biliroaming/configs.proto +++ b/app/src/main/proto/me/iacn/biliroaming/configs.proto @@ -330,6 +330,11 @@ message GCommonResolverParams { optional Method setExtraContent = 2; } +message RewardAd { + optional Class class_ = 1; + optional Field rewardFlag = 2; +} + message HookInfo { int64 last_update_time = 1; optional MapIds map_ids = 2; @@ -401,4 +406,5 @@ message HookInfo { optional Class pegasus_parser = 101; optional ResolveClientCompanion resolveClientCompanion = 102; optional GCommonResolverParams gCommonResolverParams = 103; + optional RewardAd rewardAd = 104; } diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml index ed6fd365bb..52afb69370 100644 --- a/app/src/main/res/values-zh-rTW/strings.xml +++ b/app/src/main/res/values-zh-rTW/strings.xml @@ -281,4 +281,6 @@ 推薦封面比例 自訂首頁推薦小卡(雙列顯示的)封面比例 搜尋結果移除推廣 + 跳過視頻激勵廣告 + 受不了了!我要看個爽!(需重啟兩次嗶哩嗶哩) diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 911b212d2c..f4c5280aa6 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -306,4 +306,6 @@ 防瞎眼 隐藏直播模糊遮罩 隐藏部分直播的模糊遮罩 + 跳过视频激励广告 + 受不了了!我要看个爽!(需重启两次哔哩哔哩) diff --git a/app/src/main/res/xml/prefs_setting.xml b/app/src/main/res/xml/prefs_setting.xml index ab0e777ac0..1e99a9a2aa 100644 --- a/app/src/main/res/xml/prefs_setting.xml +++ b/app/src/main/res/xml/prefs_setting.xml @@ -313,6 +313,11 @@ android:key="customize_bottom_bar" android:summary="@string/customize_bottom_bar_summary" android:title="@string/customize_bottom_bar_title" /> +