Compare commits
1 commit
master
...
fix/startu
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b9980f5cb9 |
8 changed files with 202 additions and 1087 deletions
30
app/src/main/assets/Shiggy.bundle
Normal file
30
app/src/main/assets/Shiggy.bundle
Normal file
File diff suppressed because one or more lines are too long
|
|
@ -16,6 +16,7 @@ import GoonXposed.xposed.modules.bridge.AdditionalBridgeMethodsModule
|
||||||
import GoonXposed.xposed.modules.bridge.BridgeModule
|
import GoonXposed.xposed.modules.bridge.BridgeModule
|
||||||
import GoonXposed.xposed.modules.no_track.BlockCrashReportingModule
|
import GoonXposed.xposed.modules.no_track.BlockCrashReportingModule
|
||||||
import GoonXposed.xposed.modules.no_track.BlockDeepLinksTrackingModule
|
import GoonXposed.xposed.modules.no_track.BlockDeepLinksTrackingModule
|
||||||
|
import GoonXposed.xposed.modules.LogBox.LogBoxModule
|
||||||
import kotlinx.coroutines.CompletableDeferred
|
import kotlinx.coroutines.CompletableDeferred
|
||||||
|
|
||||||
object HookStateHolder {
|
object HookStateHolder {
|
||||||
|
|
@ -61,9 +62,16 @@ class Main : Module(), IXposedHookLoadPackage, IXposedHookZygoteInit {
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun handleLoadPackage(param: XC_LoadPackage.LoadPackageParam) = with(param) {
|
override fun handleLoadPackage(param: XC_LoadPackage.LoadPackageParam) = with(param) {
|
||||||
|
if (packageName != Constants.TARGET_PACKAGE) return
|
||||||
|
if (processName != Constants.TARGET_PACKAGE) return
|
||||||
if (hooked) return
|
if (hooked) return
|
||||||
|
|
||||||
val reactActivity = classLoader.loadClass(Constants.TARGET_ACTIVITY)
|
val reactActivity = try {
|
||||||
|
classLoader.loadClass(Constants.TARGET_ACTIVITY)
|
||||||
|
} catch (e: Throwable) {
|
||||||
|
Log.e("Failed to load target activity ${Constants.TARGET_ACTIVITY}", e)
|
||||||
|
null
|
||||||
|
}
|
||||||
|
|
||||||
ContextWrapper::class.java.hookMethod("attachBaseContext", Context::class.java) {
|
ContextWrapper::class.java.hookMethod("attachBaseContext", Context::class.java) {
|
||||||
after {
|
after {
|
||||||
|
|
@ -74,7 +82,7 @@ class Main : Module(), IXposedHookLoadPackage, IXposedHookZygoteInit {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
reactActivity.hookMethod("onCreate", Bundle::class.java) {
|
reactActivity?.hookMethod("onCreate", Bundle::class.java) {
|
||||||
after {
|
after {
|
||||||
val act = thisObject as Activity
|
val act = thisObject as Activity
|
||||||
Log.i("Received Activity")
|
Log.i("Received Activity")
|
||||||
|
|
@ -89,6 +97,20 @@ class Main : Module(), IXposedHookLoadPackage, IXposedHookZygoteInit {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
reactActivity?.hookMethod("onResume") {
|
||||||
|
after {
|
||||||
|
val act = thisObject as Activity
|
||||||
|
this@Main.onResume(act)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
reactActivity?.hookMethod("onPause") {
|
||||||
|
after {
|
||||||
|
val act = thisObject as Activity
|
||||||
|
this@Main.onPause(act)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
this@Main.onLoad(param)
|
this@Main.onLoad(param)
|
||||||
|
|
||||||
hooked = true
|
hooked = true
|
||||||
|
|
@ -105,4 +127,12 @@ class Main : Module(), IXposedHookLoadPackage, IXposedHookZygoteInit {
|
||||||
override fun onActivity(activity: Activity) {
|
override fun onActivity(activity: Activity) {
|
||||||
for (module in modules) module.onActivity(activity)
|
for (module in modules) module.onActivity(activity)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onResume(activity: Activity) {
|
||||||
|
for (module in modules) module.onResume(activity)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onPause(activity: Activity) {
|
||||||
|
for (module in modules) module.onPause(activity)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,10 @@ open class Module {
|
||||||
|
|
||||||
open fun onActivity(activity: Activity) {}
|
open fun onActivity(activity: Activity) {}
|
||||||
|
|
||||||
|
open fun onResume(activity: Activity) {}
|
||||||
|
|
||||||
|
open fun onPause(activity: Activity) {}
|
||||||
|
|
||||||
@Deprecated("This method is deprecated in the parent class")
|
@Deprecated("This method is deprecated in the parent class")
|
||||||
open fun buildPayload(builder: JsonObjectBuilder) {}
|
open fun buildPayload(builder: JsonObjectBuilder) {}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@ import GoonXposed.xposed.modules.HookScriptLoaderModule.PRELOADS_DIR
|
||||||
import kotlinx.coroutines.async
|
import kotlinx.coroutines.async
|
||||||
import kotlinx.coroutines.awaitAll
|
import kotlinx.coroutines.awaitAll
|
||||||
import kotlinx.coroutines.runBlocking
|
import kotlinx.coroutines.runBlocking
|
||||||
|
import kotlinx.coroutines.withTimeout
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.lang.reflect.Method
|
import java.lang.reflect.Method
|
||||||
|
|
||||||
|
|
@ -88,16 +89,18 @@ object HookScriptLoaderModule : Module() {
|
||||||
Log.i("Running custom scripts...")
|
Log.i("Running custom scripts...")
|
||||||
|
|
||||||
runBlocking {
|
runBlocking {
|
||||||
val ready = async { HookStateHolder.readyDeferred.join() }
|
|
||||||
|
|
||||||
if (!mainScript.exists()) {
|
if (!mainScript.exists()) {
|
||||||
Log.i("Main script does not exist, downloading before load...")
|
Log.i("Main script does not exist, downloading before load...")
|
||||||
val download = async { UpdaterModule.downloadScript().join() }
|
try {
|
||||||
awaitAll(ready, download)
|
withTimeout(10000L) {
|
||||||
|
UpdaterModule.downloadScript().join()
|
||||||
|
}
|
||||||
|
} catch (e: Throwable) {
|
||||||
|
Log.w("Bundle download did not complete in time", e)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
Log.i("Main script exists, updating in background...")
|
Log.i("Main script exists, updating in background...")
|
||||||
UpdaterModule.downloadScript()
|
UpdaterModule.downloadScript()
|
||||||
ready.await()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -122,15 +125,25 @@ object HookScriptLoaderModule : Module() {
|
||||||
if (mainScript.exists()) {
|
if (mainScript.exists()) {
|
||||||
runScriptFile(mainScript)
|
runScriptFile(mainScript)
|
||||||
} else {
|
} else {
|
||||||
Log.i("Main script does not exist, falling back")
|
Log.i("Main script does not exist, checking for fallback asset")
|
||||||
|
|
||||||
if (!::resources.isInitialized) resources = XModuleResources.createInstance(modulePath, null)
|
if (!::resources.isInitialized) resources = XModuleResources.createInstance(modulePath, null)
|
||||||
|
|
||||||
|
var hasFallback = false
|
||||||
|
try {
|
||||||
|
resources.assets.open("Shiggy.bundle").use { hasFallback = true }
|
||||||
|
} catch (_: Throwable) {}
|
||||||
|
|
||||||
|
if (hasFallback) {
|
||||||
|
Log.i("Loading fallback assets://Shiggy.bundle")
|
||||||
XposedBridge.invokeOriginalMethod(
|
XposedBridge.invokeOriginalMethod(
|
||||||
loadScriptFromAssets,
|
loadScriptFromAssets,
|
||||||
thisObject,
|
thisObject,
|
||||||
arrayOf(resources.assets, "assets://Shiggy.bundle", loadSynchronously)
|
arrayOf(resources.assets, "assets://Shiggy.bundle", loadSynchronously)
|
||||||
)
|
)
|
||||||
|
} else {
|
||||||
|
Log.w("No fallback bundle asset found; letting host app load default JS")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (e: Throwable) {
|
} catch (e: Throwable) {
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ package GoonXposed.xposed.modules.LogBox
|
||||||
import GoonXposed.xposed.Module
|
import GoonXposed.xposed.Module
|
||||||
import GoonXposed.xposed.Utils.Log
|
import GoonXposed.xposed.Utils.Log
|
||||||
import GoonXposed.xposed.Utils.Companion.reloadApp
|
import GoonXposed.xposed.Utils.Companion.reloadApp
|
||||||
|
import android.app.Activity
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import de.robv.android.xposed.XC_MethodHook
|
import de.robv.android.xposed.XC_MethodHook
|
||||||
import de.robv.android.xposed.XC_MethodReplacement
|
import de.robv.android.xposed.XC_MethodReplacement
|
||||||
|
|
@ -10,32 +11,71 @@ import de.robv.android.xposed.XposedBridge
|
||||||
import de.robv.android.xposed.XposedHelpers
|
import de.robv.android.xposed.XposedHelpers
|
||||||
import de.robv.android.xposed.callbacks.XC_LoadPackage
|
import de.robv.android.xposed.callbacks.XC_LoadPackage
|
||||||
import kotlinx.coroutines.*
|
import kotlinx.coroutines.*
|
||||||
|
import java.lang.ref.WeakReference
|
||||||
|
|
||||||
object LogBoxModule : Module() {
|
object LogBoxModule : Module() {
|
||||||
lateinit var packageParam: XC_LoadPackage.LoadPackageParam
|
lateinit var packageParam: XC_LoadPackage.LoadPackageParam
|
||||||
private val scope = CoroutineScope(Dispatchers.Main + SupervisorJob())
|
private val scope = CoroutineScope(Dispatchers.Main + SupervisorJob())
|
||||||
var contextForMenu: Context? = null
|
var contextForMenu: Context? = null
|
||||||
|
private var currentActivity: WeakReference<Activity>? = null
|
||||||
|
|
||||||
|
private val shakeDetector = ShakeDetector {
|
||||||
|
val act = currentActivity?.get() ?: return@ShakeDetector
|
||||||
|
act.runOnUiThread {
|
||||||
|
try {
|
||||||
|
Log.i("Shake detected! Opening Recovery Menu...")
|
||||||
|
LogBoxNavigation.showRecoveryMenu(act)
|
||||||
|
} catch (e: Throwable) {
|
||||||
|
Log.e("Failed to show recovery menu on shake: ${e.message}", e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onActivity(activity: Activity) {
|
||||||
|
currentActivity = WeakReference(activity)
|
||||||
|
contextForMenu = activity
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onResume(activity: Activity) {
|
||||||
|
currentActivity = WeakReference(activity)
|
||||||
|
contextForMenu = activity
|
||||||
|
try {
|
||||||
|
shakeDetector.start(activity)
|
||||||
|
Log.i("ShakeDetector started for activity: ${activity.javaClass.simpleName}")
|
||||||
|
} catch (e: Throwable) {
|
||||||
|
Log.e("Failed to start ShakeDetector: ${e.message}", e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onPause(activity: Activity) {
|
||||||
|
try {
|
||||||
|
shakeDetector.stop()
|
||||||
|
Log.i("ShakeDetector stopped")
|
||||||
|
} catch (e: Throwable) {
|
||||||
|
Log.e("Failed to stop ShakeDetector: ${e.message}", e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun onLoad(packageParam: XC_LoadPackage.LoadPackageParam) = with(packageParam) {
|
override fun onLoad(packageParam: XC_LoadPackage.LoadPackageParam) = with(packageParam) {
|
||||||
this@LogBoxModule.packageParam = packageParam
|
this@LogBoxModule.packageParam = packageParam
|
||||||
|
|
||||||
try {
|
runCatching {
|
||||||
val dcdReactNativeHostClass = classLoader.loadClass("com.discord.bridge.DCDReactNativeHost")
|
val dcdReactNativeHostClass = classLoader.loadClass("com.discord.bridge.DCDReactNativeHost")
|
||||||
val getUseDeveloperSupportMethod =
|
val getUseDeveloperSupportMethod =
|
||||||
dcdReactNativeHostClass.methods.first { it.name == "getUseDeveloperSupport" }
|
dcdReactNativeHostClass.declaredMethods.firstOrNull { it.name == "getUseDeveloperSupport" }
|
||||||
|
?: dcdReactNativeHostClass.methods.firstOrNull { it.name == "getUseDeveloperSupport" }
|
||||||
|
|
||||||
// NOTE: This used to call a custom `.hook { before { result = true } }` DSL that
|
if (getUseDeveloperSupportMethod != null) {
|
||||||
// relied on a shared extensions file which broke (unresolved references).
|
getUseDeveloperSupportMethod.isAccessible = true
|
||||||
// Rewritten using the standard XposedBridge/XC_MethodHook API, which is already
|
|
||||||
// used elsewhere in this file, to force this method to always return true.
|
|
||||||
XposedBridge.hookMethod(getUseDeveloperSupportMethod, object : XC_MethodHook() {
|
XposedBridge.hookMethod(getUseDeveloperSupportMethod, object : XC_MethodHook() {
|
||||||
override fun beforeHookedMethod(param: MethodHookParam) {
|
override fun beforeHookedMethod(param: MethodHookParam) {
|
||||||
param.result = true
|
param.result = true
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
Log.e("Successfully hooked DCDReactNativeHost")
|
Log.i("Successfully hooked DCDReactNativeHost")
|
||||||
} catch (e: Exception) {
|
}
|
||||||
Log.e("Failed to hook DCDReactNativeHost: ${e.message}")
|
}.onFailure { e ->
|
||||||
|
Log.w("Could not hook DCDReactNativeHost: ${e.message}")
|
||||||
}
|
}
|
||||||
|
|
||||||
return@with
|
return@with
|
||||||
|
|
@ -126,7 +166,7 @@ object LogBoxModule : Module() {
|
||||||
Log.e("Failed to get context from DevSupport (non-fatal): ${e.message}")
|
Log.e("Failed to get context from DevSupport (non-fatal): ${e.message}")
|
||||||
}
|
}
|
||||||
|
|
||||||
val finalContext = activityContext ?: contextForMenu ?: context
|
val finalContext = currentActivity?.get() ?: activityContext ?: contextForMenu ?: context
|
||||||
Log.e("Using context: $finalContext (type: ${finalContext.javaClass.name})")
|
Log.e("Using context: $finalContext (type: ${finalContext.javaClass.name})")
|
||||||
|
|
||||||
LogBoxNavigation.showRecoveryMenu(finalContext)
|
LogBoxNavigation.showRecoveryMenu(finalContext)
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,56 @@
|
||||||
|
package GoonXposed.xposed.modules.LogBox
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.hardware.Sensor
|
||||||
|
import android.hardware.SensorEvent
|
||||||
|
import android.hardware.SensorEventListener
|
||||||
|
import android.hardware.SensorManager
|
||||||
|
import kotlin.math.sqrt
|
||||||
|
|
||||||
|
class ShakeDetector(private val onShake: () -> Unit) : SensorEventListener {
|
||||||
|
private var sensorManager: SensorManager? = null
|
||||||
|
private var accelerometer: Sensor? = null
|
||||||
|
private var lastShakeTimestamp: Long = 0
|
||||||
|
|
||||||
|
fun start(context: Context): Boolean {
|
||||||
|
if (sensorManager != null) return true
|
||||||
|
sensorManager = context.getSystemService(Context.SENSOR_SERVICE) as? SensorManager
|
||||||
|
accelerometer = sensorManager?.getDefaultSensor(Sensor.TYPE_ACCELEROMETER)
|
||||||
|
return accelerometer?.let {
|
||||||
|
sensorManager?.registerListener(this, it, SensorManager.SENSOR_DELAY_UI)
|
||||||
|
} ?: false
|
||||||
|
}
|
||||||
|
|
||||||
|
fun stop() {
|
||||||
|
sensorManager?.unregisterListener(this)
|
||||||
|
sensorManager = null
|
||||||
|
accelerometer = null
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onSensorChanged(event: SensorEvent) {
|
||||||
|
if (event.sensor.type != Sensor.TYPE_ACCELEROMETER) return
|
||||||
|
|
||||||
|
val x = event.values[0] / SensorManager.GRAVITY_EARTH
|
||||||
|
val y = event.values[1] / SensorManager.GRAVITY_EARTH
|
||||||
|
val z = event.values[2] / SensorManager.GRAVITY_EARTH
|
||||||
|
|
||||||
|
// gForce will be close to 1 when there is no movement.
|
||||||
|
val gForce = sqrt((x * x + y * y + z * z).toDouble()).toFloat()
|
||||||
|
|
||||||
|
if (gForce > SHAKE_THRESHOLD_GRAVITY) {
|
||||||
|
val now = System.currentTimeMillis()
|
||||||
|
// Ignore shake events too close to each other (1 second debounce)
|
||||||
|
if (now - lastShakeTimestamp > SHAKE_SLOP_TIME_MS) {
|
||||||
|
lastShakeTimestamp = now
|
||||||
|
onShake()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onAccuracyChanged(sensor: Sensor?, accuracy: Int) {}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private const val SHAKE_THRESHOLD_GRAVITY = 2.7f
|
||||||
|
private const val SHAKE_SLOP_TIME_MS = 1000L
|
||||||
|
}
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -57,7 +57,7 @@ object UpdaterModule : Module() {
|
||||||
private const val CONFIG_FILE = "loader.json"
|
private const val CONFIG_FILE = "loader.json"
|
||||||
|
|
||||||
private const val DEFAULT_BUNDLE_URL =
|
private const val DEFAULT_BUNDLE_URL =
|
||||||
"https://github.com/OTKUSteyler/GoonCord/releases/download/latest/gooncord.js"
|
"https://github.com/OTKUSteyler/GoonCord/releases/latest/download/gooncord.js"
|
||||||
|
|
||||||
override fun onLoad(packageParam: XC_LoadPackage.LoadPackageParam) = with(packageParam) {
|
override fun onLoad(packageParam: XC_LoadPackage.LoadPackageParam) = with(packageParam) {
|
||||||
// store app data dir for later checks (LogBox settings live under files/logbox)
|
// store app data dir for later checks (LogBox settings live under files/logbox)
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue