Revenge Next Native Kotlin Development
Native plugins execute pre-compiled DEX bytecode inside Discord\'s ClassLoader before Hermes JS initializes.
1. Plugin Structure
A native plugin contains a Kotlin source tree under src/main/kotlin and a manifest.json:
{
"format": 1,
"id": "dev.everestmcarthur.my-plugin",
"name": "My Plugin",
"description": "High performance native Android hooks.",
"author": "Rosie",
"icon": "ic_cog_24px",
"version": "1.0.0",
"dependencies": {
"revenge.api": {
"version": ">=1 <2"
},
"discord": {
"version": "*"
}
},
"dist": {
"script": "index.js",
"android": {
"path": "plugin.jar",
"class": "dev.everestmcarthur.myplugin.MyPlugin"
}
}
}
2. Kotlin DSL Entrypoint (MyPlugin.kt)
Annotate the file with @file:JvmName(...) matching dist.android.class:
@file:JvmName("MyPlugin")
package dev.everestmcarthur.myplugin
import android.widget.TextView
import de.robv.android.xposed.XC_MethodHook
import de.robv.android.xposed.XposedBridge
import de.robv.android.xposed.XposedHelpers
import io.github.revenge.plugins.plugin
import io.github.revenge.xposed.api.registerMethod
val myPlugin = plugin {
start {
registerMethod("${manifest.id}.setNativeConfig") { args ->
val jsonConfig = args.optString(0)
"ACK"
}
try {
val messageViewClass = XposedHelpers.findClass(
"com.discord.chat.presentation.message.view.MessageContentView",
hostClassLoader
)
XposedBridge.hookAllMethods(
messageViewClass,
"setLineSpacing",
object : XC_MethodHook() {
override fun beforeHookedMethod(param: MethodHookParam) {
param.args[0] = 0.0f
param.args[1] = 1.0f
}
}
)
} catch (e: Throwable) {
}
}
stop {
}
}
3. Compilation & Packaging
Compile all native plugins into build/outputs/plugin/plugin.jar using Gradle and D8 desugaring: