Skip to content

Commit 856e94a

Browse files
committed
Refactor Xposed Dsl
1 parent a678315 commit 856e94a

File tree

18 files changed

+215
-210
lines changed

18 files changed

+215
-210
lines changed

app/src/main/java/io/github/chsbuffer/revancedxposed/BaseHook.kt

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,8 @@ interface IHook {
3636
XposedBridge.hookMethod(toMember(), callback)
3737
}
3838

39-
fun Member.hookMethod(callback: XC_MethodHook) {
40-
XposedBridge.hookMethod(this, callback)
39+
fun DexMethod.hookMethod(block: HookDsl<IHookCallback>.() -> Unit) {
40+
toMember().hookMethod(block)
4141
}
4242

4343
fun DexClass.toClass() = getInstance(classLoader)
@@ -70,8 +70,9 @@ interface IHook {
7070
fun DexField.toField() = getFieldInstance(classLoader)
7171
}
7272

73+
@Suppress("UNCHECKED_CAST")
7374
@OptIn(DexKitExperimentalApi::class)
74-
class PrefCache(app: Application) : DexKitCacheBridge.Cache {
75+
class SharedPrefCache(app: Application) : DexKitCacheBridge.Cache {
7576
val pref = app.getSharedPreferences("xprevanced", MODE_PRIVATE)!!
7677
private val map = mutableMapOf<String, String>().apply {
7778
putAll(pref.all as Map<String, String>)
@@ -126,7 +127,7 @@ abstract class BaseHook(val app: Application, val lpparam: LoadPackageParam) : I
126127

127128
// cache
128129
private val moduleRel = BuildConfig.COMMIT_HASH
129-
private var cache = PrefCache(app)
130+
private var cache = SharedPrefCache(app)
130131
private var dexkit = run {
131132
System.loadLibrary("dexkit")
132133
DexKitCacheBridge.init(cache)

app/src/main/java/io/github/chsbuffer/revancedxposed/Helper.kt

Lines changed: 51 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -13,60 +13,79 @@ import de.robv.android.xposed.XposedBridge
1313
import java.io.File
1414
import java.lang.reflect.Member
1515

16-
class XHookContext(val param: MethodHookParam, val outerParam: MethodHookParam)
16+
typealias IScopedHookCallback = ScopedHookParam.(MethodHookParam) -> Unit
17+
typealias IHookCallback = (MethodHookParam) -> Unit
1718

18-
data class XHook(
19-
val before: (XHookContext.() -> Unit)?,
20-
val after: (XHookContext.() -> Unit)?
21-
)
19+
class HookDsl<TCallback>(emptyCallback: TCallback) {
20+
var before: TCallback = emptyCallback
21+
var after: TCallback = emptyCallback
2222

23-
class XHookBuilder {
24-
private var before: (XHookContext.() -> Unit)? = null
25-
private var after: (XHookContext.() -> Unit)? = null
26-
27-
fun before(f: XHookContext.() -> Unit) {
23+
fun before(f: TCallback) {
2824
this.before = f
2925
}
3026

31-
fun after(f: XHookContext.() -> Unit) {
27+
fun after(f: TCallback) {
3228
this.after = f
3329
}
30+
}
3431

35-
fun replace(f: XHookContext.() -> Any) {
36-
before = {
37-
runCatching {
38-
param.result = f()
39-
}.onFailure { err ->
40-
param.throwable = err
41-
}
32+
inline fun Member.hookMethod(crossinline block: HookDsl<IHookCallback>.() -> Unit) {
33+
val builder = HookDsl<IHookCallback> {}.apply(block)
34+
hookMethodInternal(builder.before, builder.after)
35+
}
36+
37+
inline fun Member.hookMethodInternal(
38+
crossinline before: IHookCallback, crossinline after: IHookCallback
39+
) {
40+
XposedBridge.hookMethod(this, object : XC_MethodHook() {
41+
override fun beforeHookedMethod(param: XC_MethodHook.MethodHookParam) {
42+
before(param)
4243
}
43-
after = null
44-
}
4544

46-
fun returnConstant(obj: Any) {
47-
replace { obj }
48-
}
45+
override fun afterHookedMethod(param: XC_MethodHook.MethodHookParam) {
46+
after(param)
47+
}
48+
})
49+
}
50+
51+
@JvmInline
52+
value class ScopedHookParam(val outerParam: MethodHookParam)
4953

50-
fun build() = XHook(before, after)
54+
fun scopedHook(vararg pairs: Pair<Member, HookDsl<IScopedHookCallback>.() -> Unit>): XC_MethodHook {
55+
val hook = ScopedHook()
56+
pairs.forEach { (member, block) ->
57+
val builder = HookDsl<IScopedHookCallback> {}.apply(block)
58+
hook.hookInnerMethod(member, builder.before, builder.after)
59+
}
60+
return hook
5161
}
5262

53-
class ScopedHook : XC_MethodHook {
54-
constructor(hookMethod: Member, f: XHookBuilder.() -> Unit) : this(
55-
hookMethod, XHookBuilder().apply(f).build()
56-
)
63+
inline fun scopedHook(
64+
hookMethod: Member, crossinline f: HookDsl<IScopedHookCallback>.() -> Unit
65+
): XC_MethodHook {
66+
val hook = ScopedHook()
67+
val builder = HookDsl<IScopedHookCallback> {}.apply(f)
68+
hook.hookInnerMethod(hookMethod, builder.before, builder.after)
69+
return hook
70+
}
5771

58-
constructor(hookMethod: Member, hook: XHook) {
72+
class ScopedHook : XC_MethodHook() {
73+
inline fun hookInnerMethod(
74+
hookMethod: Member,
75+
crossinline before: IScopedHookCallback,
76+
crossinline after: IScopedHookCallback
77+
) {
5978
XposedBridge.hookMethod(hookMethod, object : XC_MethodHook() {
6079
override fun beforeHookedMethod(param: MethodHookParam) {
6180
val outerParam = outerParam.get()
6281
if (outerParam == null) return
63-
hook.before?.invoke(XHookContext(param, outerParam))
82+
before(ScopedHookParam(outerParam), param)
6483
}
6584

6685
override fun afterHookedMethod(param: MethodHookParam) {
6786
val outerParam = outerParam.get()
6887
if (outerParam == null) return
69-
hook.after?.invoke(XHookContext(param, outerParam))
88+
after(ScopedHookParam(outerParam), param)
7089
}
7190
})
7291
}
@@ -126,7 +145,7 @@ fun injectHostClassLoaderToSelf(self: ClassLoader, classLoader: ClassLoader) {
126145
} catch (_: ClassNotFoundException) {
127146
}
128147

129-
throw ClassNotFoundException(name);
148+
throw ClassNotFoundException(name)
130149
}
131150
})
132151
}

app/src/main/java/io/github/chsbuffer/revancedxposed/music/MusicHook.kt

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import android.app.Application
44
import android.view.View
55
import app.revanced.extension.shared.Logger
66
import app.revanced.extension.shared.Utils
7-
import de.robv.android.xposed.XC_MethodHook
87
import de.robv.android.xposed.XC_MethodReplacement
98
import de.robv.android.xposed.XposedHelpers
109
import de.robv.android.xposed.XposedHelpers.InvocationTargetError
@@ -51,9 +50,9 @@ class MusicHook(app: Application, lpparam: LoadPackageParam) : BaseHook(app, lpp
5150
usingEqStrings("FEmusic_history", "FEmusic_offline")
5251
}
5352
}.single()
54-
}.hookMethod(object : XC_MethodHook() {
53+
}.hookMethod {
5554
val id = Utils.getResourceIdentifier("unlimited_panel", "id")
56-
override fun afterHookedMethod(param: MethodHookParam) {
55+
after { param ->
5756
val thiz = param.thisObject
5857
for (field in thiz.javaClass.fields) {
5958
val view = field.get(thiz)
@@ -64,7 +63,7 @@ class MusicHook(app: Application, lpparam: LoadPackageParam) : BaseHook(app, lpp
6463
break
6564
}
6665
}
67-
})
66+
}
6867
}
6968

7069
fun RemoveUpgradeButton() {
@@ -89,19 +88,19 @@ class MusicHook(app: Application, lpparam: LoadPackageParam) : BaseHook(app, lpp
8988
method.declaredClass!!.fields.single { f -> f.typeName == "java.util.List" }
9089
}
9190
}
92-
}.hookMethod(object : XC_MethodHook() {
91+
}.hookMethod {
9392
val pivotBarElementField =
9493
getDexField("pivotBarElementField").toField()
9594

96-
override fun afterHookedMethod(param: MethodHookParam) {
95+
after { param ->
9796
val list = pivotBarElementField.get(param.thisObject)
9897
try {
9998
XposedHelpers.callMethod(list, "remove", 4)
10099
} catch (e: InvocationTargetError) {
101100
if (e.cause !is IndexOutOfBoundsException) throw e
102101
}
103102
}
104-
})
103+
}
105104
}
106105

107106
fun MinimizedPlayback() {
@@ -168,10 +167,10 @@ class MusicHook(app: Application, lpparam: LoadPackageParam) : BaseHook(app, lpp
168167
paramTypes("boolean")
169168
}
170169
}.single()
171-
}.hookMethod(object : XC_MethodHook() {
172-
override fun beforeHookedMethod(param: MethodHookParam) {
170+
}.hookMethod {
171+
before { param ->
173172
param.args[0] = false
174173
}
175-
})
174+
}
176175
}
177176
}

app/src/main/java/io/github/chsbuffer/revancedxposed/reddit/RedditHook.kt

Lines changed: 25 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import android.app.Application
44
import android.view.View
55
import app.revanced.extension.shared.Logger
66
import app.revanced.extension.shared.Utils
7-
import de.robv.android.xposed.XC_MethodHook
87
import de.robv.android.xposed.callbacks.XC_LoadPackage
98
import io.github.chsbuffer.revancedxposed.BaseHook
109
import io.github.chsbuffer.revancedxposed.findFieldByExactType
@@ -38,10 +37,10 @@ class RedditHook(app: Application, lpparam: XC_LoadPackage.LoadPackageParam) :
3837
declaredClass(".Listing", StringMatchType.EndsWith)
3938
}
4039
}.single()
41-
}.hookMethod(object : XC_MethodHook() {
40+
}.hookMethod {
4241
val ilink = classLoader.loadClass("com.reddit.domain.model.ILink")
4342
val getPromoted = ilink.methods.single { it.name == "getPromoted" }
44-
override fun afterHookedMethod(param: MethodHookParam) {
43+
after { param ->
4544
val arrayList = param.thisObject.getObjectField("children") as Iterable<Any?>
4645
val result = mutableListOf<Any?>()
4746
var filtered = 0
@@ -63,7 +62,7 @@ class RedditHook(app: Application, lpparam: XC_LoadPackage.LoadPackageParam) :
6362
Logger.printDebug { "Filtered $filtered ads in ${arrayList.count()} posts" }
6463
param.thisObject.setObjectField("children", result)
6564
}
66-
})
65+
}
6766

6867
// endregion
6968

@@ -78,49 +77,48 @@ class RedditHook(app: Application, lpparam: XC_LoadPackage.LoadPackageParam) :
7877
usingStrings("AdPostSection(linkId=")
7978
}
8079
}.single().methods.single { it.isConstructor }
81-
}.hookMethod(object : XC_MethodHook() {
82-
override fun beforeHookedMethod(param: MethodHookParam) {
80+
}.hookMethod {
81+
before { param ->
8382
val sections = param.args[3] as MutableList<*>
8483
sections.javaClass.findFieldByExactType(Array<Any>::class.java)!!
8584
.set(sections, emptyArray<Any>())
8685
Logger.printDebug { "Removed ads from popular and latest feed" }
8786
}
88-
})
87+
}
8988
}
9089

9190
fun HideBanner() {
9291
val merge_listheader_link_detail =
9392
Utils.getResourceIdentifier("merge_listheader_link_detail", "layout")
9493
val ad_view_stub = Utils.getResourceIdentifier("ad_view_stub", "id")
95-
DexMethod("Landroid/view/View;->inflate(Landroid/content/Context;ILandroid/view/ViewGroup;)Landroid/view/View;").hookMethod(
96-
object : XC_MethodHook() {
97-
override fun afterHookedMethod(param: MethodHookParam) {
98-
val id = param.args[1] as Int
99-
if (id == merge_listheader_link_detail) {
100-
val view = param.result as View
101-
val stub = view.findViewById<View>(ad_view_stub)
102-
stub.layoutParams.apply {
103-
width = 0
104-
height = 0
105-
}
106-
107-
Logger.printDebug { "Hide banner" }
94+
DexMethod("Landroid/view/View;->inflate(Landroid/content/Context;ILandroid/view/ViewGroup;)Landroid/view/View;").hookMethod {
95+
after { param ->
96+
val id = param.args[1] as Int
97+
if (id == merge_listheader_link_detail) {
98+
val view = param.result as View
99+
val stub = view.findViewById<View>(ad_view_stub)
100+
stub.layoutParams.apply {
101+
width = 0
102+
height = 0
108103
}
104+
105+
Logger.printDebug { "Hide banner" }
109106
}
110-
})
107+
}
108+
}
111109
}
112110

113111
fun HideComment() {
114112
getDexMethod("hideCommentAdsFingerprint") {
115113
findMethod {
116114
matcher { usingStrings("link", "is not returning a link object") }
117115
}.single()
118-
}.hookMethod(object : XC_MethodHook() {
119-
override fun beforeHookedMethod(param: MethodHookParam) {
116+
}.hookMethod {
117+
before { param ->
120118
Logger.printDebug { "Hide Comment" }
121119
param.result = Object()
122120
}
123-
})
121+
}
124122
}
125123

126124
fun SanitizeUrlQuery() {
@@ -137,10 +135,10 @@ class RedditHook(app: Application, lpparam: XC_LoadPackage.LoadPackageParam) :
137135
)
138136
}
139137
}.single()
140-
}.hookMethod(object : XC_MethodHook() {
141-
override fun beforeHookedMethod(param: MethodHookParam) {
138+
}.hookMethod {
139+
before { param ->
142140
param.result = param.args[0]
143141
}
144-
})
142+
}
145143
}
146144
}

app/src/main/java/io/github/chsbuffer/revancedxposed/spotify/HideCreateButton.kt

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package io.github.chsbuffer.revancedxposed.spotify
22

33
import app.revanced.extension.spotify.layout.hide.createbutton.HideCreateButtonPatch
4-
import de.robv.android.xposed.XC_MethodHook
54
import io.github.chsbuffer.revancedxposed.AccessFlags
65
import io.github.chsbuffer.revancedxposed.Opcode
76
import io.github.chsbuffer.revancedxposed.fingerprint
@@ -43,29 +42,29 @@ fun SpotifyHook.HideCreateButton() {
4342
addInvoke { name = "add" }
4443
}
4544
}
46-
}.hookMethod(object : XC_MethodHook() {
47-
override fun beforeHookedMethod(param: MethodHookParam) {
45+
}.hookMethod {
46+
before { param ->
4847
for ((i, arg) in param.args.withIndex()) {
4948
param.args[i] = HideCreateButtonPatch.returnNullIfIsCreateButton(arg)
5049
}
5150
}
52-
})
51+
}
5352
}
5453

5554
@Suppress("IfThenToSafeAccess")
5655
if (oldNavigationBarAddItemMethod != null) {
5756
// In case an older version of the app is being patched, hook the old method which adds navigation bar items.
5857
// Return early if the navigation bar item title resource id is the old Create button title resource id.
59-
oldNavigationBarAddItemMethod.hookMethod(object : XC_MethodHook() {
60-
override fun beforeHookedMethod(param: MethodHookParam) {
58+
oldNavigationBarAddItemMethod.hookMethod {
59+
before { param ->
6160
for (arg in param.args) {
6261
if (arg !is Int) continue
6362
if (HideCreateButtonPatch.isOldCreateButton(arg)) {
6463
param.result = null
65-
return
64+
return@before
6665
}
6766
}
6867
}
69-
})
68+
}
7069
}
7170
}

0 commit comments

Comments
 (0)