diff --git a/app/src/main/java/me/iacn/biliroaming/BiliBiliPackage.kt b/app/src/main/java/me/iacn/biliroaming/BiliBiliPackage.kt index 51081fc945..b00f028898 100644 --- a/app/src/main/java/me/iacn/biliroaming/BiliBiliPackage.kt +++ b/app/src/main/java/me/iacn/biliroaming/BiliBiliPackage.kt @@ -48,6 +48,7 @@ class BiliBiliPackage constructor(private val mClassLoader: ClassLoader, mContex val bangumiApiResponseClass by Weak { mHookInfo.bangumiApiResponse from mClassLoader } val rxGeneralResponseClass by Weak { "com.bilibili.okretro.call.rxjava.RxGeneralResponse" from mClassLoader } val fastJsonClass by Weak { mHookInfo.fastJson.class_ from mClassLoader } + val gsonClass by Weak { "com.google.gson.Gson" from mClassLoader } val bangumiUniformSeasonClass by Weak { mHookInfo.bangumiSeason from mClassLoader } val kingPositionComponentClass by Weak { mHookInfo.autoLike.kingPositionComponent.class_ from mClassLoader } val storyAbsControllerClass by Weak { mHookInfo.autoLike.storyAbsController.class_ from mClassLoader } diff --git a/app/src/main/java/me/iacn/biliroaming/XposedInit.kt b/app/src/main/java/me/iacn/biliroaming/XposedInit.kt index e367abfc88..a4e96979f2 100644 --- a/app/src/main/java/me/iacn/biliroaming/XposedInit.kt +++ b/app/src/main/java/me/iacn/biliroaming/XposedInit.kt @@ -88,6 +88,7 @@ class XposedInit : IXposedHookLoadPackage, IXposedHookZygoteInit { startHook { CustomThemeHook(lpparam.classLoader) } startHook { TeenagersModeHook(lpparam.classLoader) } startHook { JsonHook(lpparam.classLoader) } + startHook { GsonHook(lpparam.classLoader) } startHook { ShareHook(lpparam.classLoader) } startHook { AutoLikeHook(lpparam.classLoader) } startHook { SettingHook(lpparam.classLoader) } diff --git a/app/src/main/java/me/iacn/biliroaming/hook/GsonHook.kt b/app/src/main/java/me/iacn/biliroaming/hook/GsonHook.kt new file mode 100644 index 0000000000..f5768c4d7b --- /dev/null +++ b/app/src/main/java/me/iacn/biliroaming/hook/GsonHook.kt @@ -0,0 +1,52 @@ +package me.iacn.biliroaming.hook + +import me.iacn.biliroaming.BiliBiliPackage.Companion.instance +import me.iacn.biliroaming.hook.gson.GsonProcessor +import me.iacn.biliroaming.hook.gson.SplashListProcessor +import me.iacn.biliroaming.hook.gson.SplashShowProcessor +import me.iacn.biliroaming.utils.Log +import me.iacn.biliroaming.utils.getObjectField +import me.iacn.biliroaming.utils.hookAfterAllMethods + +class GsonHook(classLoader: ClassLoader) : BaseHook(classLoader) { + private val allProcessors = listOf( + SplashListProcessor(), + SplashShowProcessor(), + ) + + private val enabledProcessors: Map> by lazy { + allProcessors + .filter { it.shouldEnable() } + .groupBy { it.targetClassName } + } + + override fun startHook() { + if (enabledProcessors.isEmpty()) return + Log.d("startHook: Gson") + + val gsonClass = instance.gsonClass ?: return + val fromJsonName = instance.gsonFromJson() ?: return + + gsonClass.hookAfterAllMethods(fromJsonName) { param -> + dispatchResult(param.result) + } + } + + private fun dispatchResult(result: Any?) { + if (result == null) return + + // Network path: unwrap GeneralResponse -> T + var target = result + if (result.javaClass == instance.generalResponseClass) { + target = result.getObjectField("data") ?: return + } + + enabledProcessors[target.javaClass.name]?.forEach { processor -> + try { + processor.process(target) + } catch (e: Throwable) { + Log.e("GsonHook processor ${processor.targetClassName} error: $e") + } + } + } +} diff --git a/app/src/main/java/me/iacn/biliroaming/hook/gson/GsonProcessor.kt b/app/src/main/java/me/iacn/biliroaming/hook/gson/GsonProcessor.kt new file mode 100644 index 0000000000..476dde4f26 --- /dev/null +++ b/app/src/main/java/me/iacn/biliroaming/hook/gson/GsonProcessor.kt @@ -0,0 +1,12 @@ +package me.iacn.biliroaming.hook.gson + +interface GsonProcessor { + /** Full class name of the target deserialized type */ + val targetClassName: String + + /** Return true if this processor's settings are enabled */ + fun shouldEnable(): Boolean + + /** Process the deserialized result object */ + fun process(result: Any) +} \ No newline at end of file diff --git a/app/src/main/java/me/iacn/biliroaming/hook/gson/SplashListProcessor.kt b/app/src/main/java/me/iacn/biliroaming/hook/gson/SplashListProcessor.kt new file mode 100644 index 0000000000..7deb0e89e9 --- /dev/null +++ b/app/src/main/java/me/iacn/biliroaming/hook/gson/SplashListProcessor.kt @@ -0,0 +1,17 @@ +package me.iacn.biliroaming.hook.gson + +import me.iacn.biliroaming.utils.sPrefs +import me.iacn.biliroaming.utils.getObjectFieldOrNullAs + +class SplashListProcessor : GsonProcessor { + override val targetClassName = + "tv.danmaku.bili.splash.ad.model.SplashListResponse" + + override fun shouldEnable() = + sPrefs.getBoolean("hidden", false) && sPrefs.getBoolean("purify_splash", false) + + override fun process(result: Any) { + result.getObjectFieldOrNullAs>("splashList")?.clear() + result.getObjectFieldOrNullAs>("strategyList")?.clear() + } +} \ No newline at end of file diff --git a/app/src/main/java/me/iacn/biliroaming/hook/gson/SplashShowProcessor.kt b/app/src/main/java/me/iacn/biliroaming/hook/gson/SplashShowProcessor.kt new file mode 100644 index 0000000000..bd85d9b681 --- /dev/null +++ b/app/src/main/java/me/iacn/biliroaming/hook/gson/SplashShowProcessor.kt @@ -0,0 +1,16 @@ +package me.iacn.biliroaming.hook.gson + +import me.iacn.biliroaming.utils.sPrefs +import me.iacn.biliroaming.utils.getObjectFieldOrNullAs + +class SplashShowProcessor : GsonProcessor { + override val targetClassName = + "tv.danmaku.bili.splash.ad.model.SplashShowResponse" + + override fun shouldEnable() = + sPrefs.getBoolean("hidden", false) && sPrefs.getBoolean("purify_splash", false) + + override fun process(result: Any) { + result.getObjectFieldOrNullAs>("strategyList")?.clear() + } +} \ No newline at end of file