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
2 changes: 1 addition & 1 deletion app/src/main/java/me/iacn/biliroaming/BaseWidgetDialog.kt
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import me.iacn.biliroaming.utils.dp
import me.iacn.biliroaming.utils.setRippleBackground

open class BaseWidgetDialog(context: Context) : AlertDialog.Builder(context) {
protected fun string(resId: Int) = context.getString(resId)
protected fun string(resId: Int) = XposedInit.moduleRes.getString(resId)

protected fun categoryTitle(title: String) = TextView(context).apply {
text = title
Expand Down
71 changes: 58 additions & 13 deletions app/src/main/java/me/iacn/biliroaming/BiliBiliPackage.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

package me.iacn.biliroaming

import android.app.Activity
import android.app.AndroidAppHelper
import android.content.Context
import android.content.SharedPreferences
Expand Down Expand Up @@ -32,6 +33,7 @@ import kotlin.time.measureTimedValue
infix fun Configs.Class.from(cl: ClassLoader) = if (hasName()) name.findClassOrNull(cl) else null
val Configs.Method.orNull get() = if (hasName()) name else null
val Configs.Field.orNull get() = if (hasName()) name else null
val Configs.Class.orNull get() = if (hasName()) name else null

class BiliBiliPackage constructor(private val mClassLoader: ClassLoader, mContext: Context) {
init {
Expand Down Expand Up @@ -81,6 +83,7 @@ class BiliBiliPackage constructor(private val mClassLoader: ClassLoader, mContex
val menuGroupItemClass by Weak { mHookInfo.settings.menuGroupItem from mClassLoader }
val drawerLayoutClass by Weak { mHookInfo.drawer.layout from mClassLoader }
val drawerLayoutParamsClass by Weak { mHookInfo.drawer.layoutParams from mClassLoader }
val mineAdapterClass by Weak { mHookInfo.settings.mineAdapter from mClassLoader }
val splashInfoClass by Weak {
"tv.danmaku.bili.ui.splash.brand.BrandShowInfo" from mClassLoader
?: "tv.danmaku.bili.ui.splash.brand.model.BrandShowInfo" from mClassLoader
Expand Down Expand Up @@ -324,6 +327,8 @@ class BiliBiliPackage constructor(private val mClassLoader: ClassLoader, mContex

fun onOperateClick() = mHookInfo.onOperateClick.orNull

fun operateClickHostClass() = mHookInfo.operateClickHostClass.orNull

fun getContentString() = mHookInfo.getContentString.orNull

fun check() = mHookInfo.updateInfoSupplier.check.orNull
Expand Down Expand Up @@ -952,7 +957,7 @@ class BiliBiliPackage constructor(private val mClassLoader: ClassLoader, mContex
}
settings = settings {
val menuGroupItemClass =
"com.bilibili.lib.homepage.mine.MenuGroup\$Item" from classloader
("com.bilibili.lib.homepage.mine.MenuGroup\$Item" from classloader)
?: return@settings
menuGroupItem = class_ { name = menuGroupItemClass.name }
settingRouter = class_ {
Expand All @@ -979,7 +984,8 @@ class BiliBiliPackage constructor(private val mClassLoader: ClassLoader, mContex
}
val contextIndex = dexHelper.encodeClassIndex(Context::class.java)
val listIndex = dexHelper.encodeClassIndex(List::class.java)
dexHelper.findMethodUsingString(
// 旧版 DEX 扫描链: 先通过字符串定位 HomeUserCenter 类
val homeUserCenterClasses = dexHelper.findMethodUsingString(
"main.my-information.noportrait.0.show",
false,
-1,
Expand All @@ -990,8 +996,8 @@ class BiliBiliPackage constructor(private val mClassLoader: ClassLoader, mContex
null,
null,
false
).asSequence().mapNotNull { dexHelper.decodeMethodIndex(it)?.declaringClass }
.forEach { homeUserCenterClass ->
).asSequence().mapNotNull { dexHelper.decodeMethodIndex(it)?.declaringClass }.toList()
val legacyResult = homeUserCenterClasses.mapNotNull { homeUserCenterClass ->
val homeUserCenterIndex = dexHelper.encodeClassIndex(homeUserCenterClass)
val addSettingMethod = dexHelper.findMethodUsingString(
"bilibili://main/scan",
Expand Down Expand Up @@ -1035,12 +1041,30 @@ class BiliBiliPackage constructor(private val mClassLoader: ClassLoader, mContex
true
).asSequence().firstNotNullOfOrNull {
dexHelper.decodeMethodIndex(it)
} ?: return@settings
}
addSettingMethod?.let { homeUserCenterClass to it }
}.toList()
if (legacyResult.isNotEmpty()) {
legacyResult.forEach { (cls, method) ->
homeUserCenter += homeUserCenter {
class_ = class_ { name = homeUserCenterClass.name }
addSetting = method { name = addSettingMethod.name }
class_ = class_ { name = cls.name }
addSetting = method { name = method.name }
}
}
} else {
// 8.97.0: addSetting 方法未找到,通过字符串扫描拿到的类找菜单适配器
val adapterType =
("androidx.recyclerview.widget.RecyclerView\$Adapter" from classloader)
?: ("android.support.v7.widget.RecyclerView\$Adapter" from classloader)
mineAdapter = class_ {
adapterType ?: return@class_
name = homeUserCenterClasses.firstNotNullOfOrNull { cls ->
cls.declaredFields.firstOrNull {
adapterType.isAssignableFrom(it.type)
}?.type?.name
} ?: return@class_
}
}
}
drawer = drawer {
val navigationViewClass =
Expand Down Expand Up @@ -1841,13 +1865,33 @@ class BiliBiliPackage constructor(private val mClassLoader: ClassLoader, mContex
null,
null,
true
).asSequence().firstNotNullOfOrNull {
).asSequence().mapNotNull {
dexHelper.decodeMethodIndex(it) as? Method
}?.let {
val getContentStringMethod = it.parameterTypes[1].declaredMethods.find { m ->
}.find { method ->
// 跨版本匹配: 方法在 ConversationActivity 中,或在捕获了
// ConversationActivity 的 lambda 类中。用 Activity 类型做混淆无关匹配
val dc = method.declaringClass
Activity::class.java.isAssignableFrom(dc) ||
dc.declaredFields.any {
Activity::class.java.isAssignableFrom(it.type)
}
}?.let { method ->
// 跨版本获取 BaseTypedMessage: 旧版为方法参数,新版为 captured field
val btmClass = method.parameterTypes.getOrNull(1)
?: method.declaringClass.declaredFields.firstNotNullOfOrNull { f ->
f.type.takeIf { t ->
t != String::class.java && !t.isPrimitive &&
t.declaredMethods.any { m ->
m.returnType == String::class.java && m.parameterTypes.isEmpty()
}
}
}
?: return@let
val getContentStringMethod = btmClass.declaredMethods.find { m ->
m.returnType == String::class.java && m.parameterTypes.isEmpty()
} ?: return@let
onOperateClick = method { name = it.name }
onOperateClick = method { name = method.name }
operateClickHostClass = class_ { name = method.declaringClass.name }
getContentString = method { name = getContentStringMethod.name }
}
livePagerRecyclerView = class_ {
Expand Down Expand Up @@ -2296,8 +2340,9 @@ class BiliBiliPackage constructor(private val mClassLoader: ClassLoader, mContex
null,
null,
null,
true
).asSequence().mapNotNull { dexHelper.decodeMethodIndex(it) }.firstOrNull()
false
).asSequence().mapNotNull { dexHelper.decodeMethodIndex(it) }
.firstOrNull { it.declaringClass.name.contains("blconfig") }
?: return@preBuiltConfig
class_ = class_ { name = getMap.declaringClass.name }
get = method { name = getMap.name }
Expand Down
4 changes: 2 additions & 2 deletions app/src/main/java/me/iacn/biliroaming/CommentFilterDialog.kt
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ class CommentFilterDialog(activity: Activity, prefs: SharedPreferences) :
val currentTargetCommentAuthorLevel =
prefs.getLong("target_comment_author_level", 0L).toInt()
val tvHint = seekBarView.findViewById<TextView>(R.id.tvHint).apply {
text = if (currentTargetCommentAuthorLevel == 0) "关闭" else context.getString(
text = if (currentTargetCommentAuthorLevel == 0) "关闭" else XposedInit.moduleRes.getString(
R.string.danmaku_filter_weight_hint,
currentTargetCommentAuthorLevel
)
Expand All @@ -68,7 +68,7 @@ class CommentFilterDialog(activity: Activity, prefs: SharedPreferences) :
seekBar: SeekBar?, progress: Int, fromUser: Boolean
) {
tvHint.text =
if (progress == 0) "关闭" else context.getString(
if (progress == 0) "关闭" else XposedInit.moduleRes.getString(
R.string.danmaku_filter_weight_hint,
progress
)
Expand Down
4 changes: 2 additions & 2 deletions app/src/main/java/me/iacn/biliroaming/CustomSubtitleDialog.kt
Original file line number Diff line number Diff line change
Expand Up @@ -175,9 +175,9 @@ class CustomSubtitleDialog(activity: Activity, fragment: Fragment, prefs: Shared

private fun refreshFontStatus() {
fontStatus?.text = if (SubtitleHook.fontFile.isFile)
context.getString(R.string.custom_subtitle_status_custom)
XposedInit.moduleRes.getString(R.string.custom_subtitle_status_custom)
else
context.getString(R.string.custom_subtitle_status_default)
XposedInit.moduleRes.getString(R.string.custom_subtitle_status_default)
}

fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
Expand Down
4 changes: 2 additions & 2 deletions app/src/main/java/me/iacn/biliroaming/DynamicFilterDialog.kt
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,8 @@ class DynamicFilterDialog(activity: Activity, prefs: SharedPreferences) :
)
}
root.addView(gridLayout)
val dynamicTypes = context.resources.getStringArray(R.array.dynamic_entries).zip(
context.resources.getStringArray(R.array.dynamic_values)
val dynamicTypes = XposedInit.moduleRes.getStringArray(R.array.dynamic_entries).zip(
XposedInit.moduleRes.getStringArray(R.array.dynamic_values)
)
val colSpec = fun(colWeight: Float) = GridLayout.spec(GridLayout.UNDEFINED, colWeight)
val rowSpec = { GridLayout.spec(GridLayout.UNDEFINED) }
Expand Down
Loading
Loading