Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 33 additions & 0 deletions app/src/main/java/me/iacn/biliroaming/BiliBiliPackage.kt
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,15 @@ class BiliBiliPackage constructor(private val mClassLoader: ClassLoader, mContex
val tripleSpeedServiceClass by Weak { "com.bilibili.ship.theseus.united.player.TripleSpeedService\$runOldTripleSpeed\$1\$listener\$1\$onLongPress\$1" from mClassLoader }
val storyPagerPlayerClass by Weak { mHookInfo.storyPagerPlayer.class_ from mClassLoader }

// Compose guard method,由 initHookInfo 中 DexHelper 查找并缓存到 hook info
val composeGuardMethod by Weak {
mHookInfo.composeGuard.orNull?.let { methodName ->
"androidx.compose.ui.platform.AbstractComposeView"
.findClassOrNull(mClassLoader)
?.declaredMethods?.find { it.name == methodName }
}
}

// for v8.17.0+
val useNewMossFunc = instance.viewMossClass?.declaredMethods?.any {
it.name == "executeRelatesFeed"
Expand Down Expand Up @@ -402,6 +411,7 @@ class BiliBiliPackage constructor(private val mClassLoader: ClassLoader, mContex
&& getVersionCode(context.packageName) == info.clientVersionCode
&& BuildConfig.VERSION_CODE == info.moduleVersionCode
&& BuildConfig.VERSION_NAME == info.moduleVersionName
&& info.generation >= getModuleGeneration(context)
&& info.biliAccounts.getAccessKey.orNull != null
)
return info
Expand Down Expand Up @@ -449,6 +459,13 @@ class BiliBiliPackage constructor(private val mClassLoader: ClassLoader, mContex
} else classloader
}

private fun getModuleGeneration(context: Context): Int = try {
context.createPackageContext(BuildConfig.APPLICATION_ID,
Context.CONTEXT_IGNORE_SECURITY)
.getSharedPreferences("biliroaming_hookinfo", Context.MODE_PRIVATE)
.getInt("generation", 0)
} catch (_: Exception) { 0 }

@JvmStatic
fun initHookInfo(context: Context) = hookInfo {
val classloader = context.classLoader
Expand All @@ -464,6 +481,21 @@ class BiliBiliPackage constructor(private val mClassLoader: ClassLoader, mContex

val dexHelper =
DexHelper(classloader.findDexClassLoader(::findRealClassloader) ?: return@hookInfo)

// 查找 AbstractComposeView 的 addView 守卫方法(供 SplashHook 使用)
val guardMethod = dexHelper.findMethodUsingString(
"Cannot add views to ",
true,
-1, -1, null,
-1,
null, null, null, true
).firstOrNull()?.let {
dexHelper.decodeMethodIndex(it)
}
if (guardMethod != null) {
composeGuard = method { name = guardMethod.name }
}

lastUpdateTime = max(
context.packageManager.getPackageInfo(
AndroidAppHelper.currentPackageName(),
Expand All @@ -479,6 +511,7 @@ class BiliBiliPackage constructor(private val mClassLoader: ClassLoader, mContex
clientVersionCode = getVersionCode(context.packageName)
moduleVersionCode = BuildConfig.VERSION_CODE
moduleVersionName = BuildConfig.VERSION_NAME
generation = getModuleGeneration(context)
mapIds = mapIds {
val reg = Regex("^tv\\.danmaku\\.bili\\.[^.]*$")
val mask = Modifier.STATIC or Modifier.PUBLIC or Modifier.FINAL
Expand Down
10 changes: 10 additions & 0 deletions app/src/main/java/me/iacn/biliroaming/MainActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ class MainActivity : Activity() {
findPreference("version").summary = BuildConfig.VERSION_NAME
findPreference("feature").onPreferenceClickListener = this
findPreference("setting").onPreferenceClickListener = this
findPreference("clear_hook_cache").onPreferenceClickListener = this
checkUpdate()
}

Expand Down Expand Up @@ -155,6 +156,7 @@ class MainActivity : Activity() {
"update" -> onUpdateCheck()
"feature" -> onFeatureClick()
"setting" -> onSettingClick()
"clear_hook_cache" -> onClearHookCacheClick()
else -> false
}

Expand All @@ -172,6 +174,14 @@ class MainActivity : Activity() {
startActivity(this)
}
}

private fun onClearHookCacheClick(): Boolean {
val prefs = activity.getSharedPreferences("biliroaming_hookinfo", Context.MODE_PRIVATE)
val nextGen = prefs.getInt("generation", 0) + 1
prefs.edit().putInt("generation", nextGen).apply()
Toast.makeText(activity, "将在下次启动哔哩哔哩时重新扫描", Toast.LENGTH_SHORT).show()
return true
}
}

companion object {
Expand Down
4 changes: 2 additions & 2 deletions app/src/main/java/me/iacn/biliroaming/hook/KotlinxJsonHook.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import me.iacn.biliroaming.hook.kotlinx.KotlinxProcessor
import me.iacn.biliroaming.hook.kotlinx.KotlinxSplashListProcessor
import me.iacn.biliroaming.hook.kotlinx.KotlinxSplashShowProcessor
import me.iacn.biliroaming.utils.Log
import me.iacn.biliroaming.utils.getObjectField
import me.iacn.biliroaming.utils.callMethodOrNull
import me.iacn.biliroaming.utils.getObjectFieldAs
import me.iacn.biliroaming.utils.hookAfterAllMethods

Expand Down Expand Up @@ -36,7 +36,7 @@ class KotlinxJsonHook(classLoader: ClassLoader) : BaseHook(classLoader) {
if (deserializer == null || result == null) return

val serialName = deserializer
.getObjectField("descriptor")
.callMethodOrNull("getDescriptor")
?.getObjectFieldAs<String>("serialName")
?: return

Expand Down
79 changes: 47 additions & 32 deletions app/src/main/java/me/iacn/biliroaming/hook/SplashHook.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,25 @@ import android.content.res.Configuration
import android.graphics.Color
import android.net.Uri
import android.os.Bundle
import android.view.Gravity
import android.view.View
import android.view.ViewGroup
import android.widget.FrameLayout
import android.widget.ImageView
import me.iacn.biliroaming.BiliBiliPackage.Companion.instance
import me.iacn.biliroaming.utils.*
import java.io.File

class SplashHook(classLoader: ClassLoader) : BaseHook(classLoader) {
override fun startHook() {
// 解除 AbstractComposeView 的 addView 限制,使其恢复普通 ViewGroup 行为
if (!composeAddViewPatched) {
try {
instance.composeGuardMethod?.replaceMethod { null }
} catch (_: Throwable) {}
composeAddViewPatched = true
}

val customSplash = sPrefs.getBoolean("custom_splash", false)
val customSplashLogo = sPrefs.getBoolean("custom_splash_logo", false)
val fullSplash = sPrefs.getBoolean("full_splash", false)
Expand Down Expand Up @@ -51,8 +61,8 @@ class SplashHook(classLoader: ClassLoader) : BaseHook(classLoader) {

if (isXmlPath) {
applyXmlPath(view, brandId, customSplash, customSplashLogo)
} else if (view is ViewGroup) {
view.post { applyComposeOverlay(view, customSplash, customSplashLogo) }
} else {
applyComposeOverlay(view, customSplash, customSplashLogo)
}
}
}
Expand Down Expand Up @@ -84,47 +94,52 @@ class SplashHook(classLoader: ClassLoader) : BaseHook(classLoader) {
}

/**
* Compose 渲染路径:在 ComposeView 上叠加 ImageView。
* ComposeView 是 ViewGroup 子类,addView 可添加覆盖层于 Compose 内容之上
* Compose 渲染路径:addView 限制已解除,直接用 FrameLayout 包裹
* overlay 添加到 ComposeView 自身,随 ComposeView 自动销毁
*/
private fun applyComposeOverlay(container: ViewGroup, customSplash: Boolean, customSplashLogo: Boolean) {
if (sPrefs.getBoolean("custom_splash", false)) {
val splashImage = File(currentContext.filesDir, SPLASH_IMAGE)
val iv = ImageView(container.context).apply {
private fun applyComposeOverlay(composeView: View, customSplash: Boolean, customSplashLogo: Boolean) {
val ctx = composeView.context
val logoH = composeView.resources.displayMetrics.heightPixels / 8
val splashImage = File(currentContext.filesDir, SPLASH_IMAGE)
val logoImage = File(currentContext.filesDir, LOGO_IMAGE)

val overlay = FrameLayout(ctx).apply {
layoutParams = ViewGroup.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT
)
}

if (customSplash) {
overlay.addView(ImageView(ctx).apply {
scaleType = ImageView.ScaleType.CENTER_CROP
layoutParams = ViewGroup.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT
layoutParams = FrameLayout.LayoutParams(
FrameLayout.LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.MATCH_PARENT
)
if (splashImage.exists()) {
setImageURI(Uri.fromFile(splashImage))
} else {
visibility = View.GONE
}
}
container.addView(iv)
if (splashImage.exists()) setImageURI(Uri.fromFile(splashImage))
else visibility = View.GONE
})
}
if (sPrefs.getBoolean("custom_splash_logo", false)) {
val logoH = container.resources.displayMetrics.heightPixels / 8
val logoImage = File(currentContext.filesDir, LOGO_IMAGE)
val iv = ImageView(container.context).apply {
if (customSplashLogo) {
overlay.addView(ImageView(ctx).apply {
scaleType = ImageView.ScaleType.FIT_CENTER
layoutParams = ViewGroup.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT, logoH
layoutParams = FrameLayout.LayoutParams(
FrameLayout.LayoutParams.MATCH_PARENT,
logoH,
Gravity.BOTTOM
)
y = (container.height - logoH).toFloat()
if (logoImage.exists()) {
setImageURI(Uri.fromFile(logoImage))
} else {
visibility = View.GONE
}
}
container.addView(iv)
if (logoImage.exists()) setImageURI(Uri.fromFile(logoImage))
else visibility = View.GONE
})
}

(composeView as ViewGroup).addView(overlay)
}

companion object {
const val SPLASH_IMAGE = "biliroaming_splash"
const val LOGO_IMAGE = "biliroaming_logo"
private var composeAddViewPatched = false
}
}
2 changes: 2 additions & 0 deletions app/src/main/proto/me/iacn/biliroaming/configs.proto
Original file line number Diff line number Diff line change
Expand Up @@ -415,4 +415,6 @@ message HookInfo {
optional GCommonResolverParams gCommonResolverParams = 103;
optional RewardAd rewardAd = 104;
optional StoryPagerPlayer storyPagerPlayer = 105;
int32 generation = 106;
optional Method compose_guard = 107;
}
2 changes: 2 additions & 0 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,8 @@
<string name="force_th_comment_summary">强制开启串台的泰区评论弹幕(仅调试使用)</string>
<string name="share_log_title">分享日志</string>
<string name="share_log_summary">可能在旧版无效</string>
<string name="clear_hook_cache_title">清除hook缓存</string>
<string name="clear_hook_cache_summary">下次打开哔哩哔哩时强制重新扫描hook信息</string>
<string name="replace_story_video_title">替换竖版视频</string>
<string name="replace_story_video_summary">替换竖版视频为正常视频</string>
<string name="customize_drawer_title">自定义我的页面</string>
Expand Down
5 changes: 5 additions & 0 deletions app/src/main/res/xml/main_activity.xml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,11 @@
android:action="android.intent.action.VIEW"
android:data="@string/help_url" />
</Preference>

<Preference
android:key="clear_hook_cache"
android:summary="@string/clear_hook_cache_summary"
android:title="@string/clear_hook_cache_title" />
</PreferenceCategory>

<PreferenceCategory
Expand Down
Loading