fix: undelay module initialization

This commit is contained in:
pylixonly 2024-10-11 23:48:21 +08:00
parent 42a08d1d21
commit 59d85ef774
11 changed files with 71 additions and 33 deletions

2
.idea/compiler.xml generated
View file

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<project version="4"> <project version="4">
<component name="CompilerConfiguration"> <component name="CompilerConfiguration">
<bytecodeTargetLevel target="19" /> <bytecodeTargetLevel target="17" />
</component> </component>
</project> </project>

18
.idea/deploymentTargetSelector.xml generated Normal file
View file

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="deploymentTargetSelector">
<selectionStates>
<SelectionState runConfigName="app">
<option name="selectionMode" value="DROPDOWN" />
<DropdownSelection timestamp="2024-10-11T15:31:32.125634Z">
<Target type="DEFAULT_BOOT">
<handle>
<DeviceId pluginId="PhysicalDevice" identifier="serial=4H4HW8U8Z98LCY89" />
</handle>
</Target>
</DropdownSelection>
<DialogSelection />
</SelectionState>
</selectionStates>
</component>
</project>

5
.idea/gradle.xml generated
View file

@ -4,16 +4,15 @@
<component name="GradleSettings"> <component name="GradleSettings">
<option name="linkedExternalProjectsSettings"> <option name="linkedExternalProjectsSettings">
<GradleProjectSettings> <GradleProjectSettings>
<option name="testRunner" value="GRADLE" />
<option name="distributionType" value="DEFAULT_WRAPPED" />
<option name="externalProjectPath" value="$PROJECT_DIR$" /> <option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="gradleJvm" value="#JAVA_HOME" /> <option name="gradleJvm" value="#GRADLE_LOCAL_JAVA_HOME" />
<option name="modules"> <option name="modules">
<set> <set>
<option value="$PROJECT_DIR$" /> <option value="$PROJECT_DIR$" />
<option value="$PROJECT_DIR$/app" /> <option value="$PROJECT_DIR$/app" />
</set> </set>
</option> </option>
<option name="resolveExternalAnnotations" value="false" />
</GradleProjectSettings> </GradleProjectSettings>
</option> </option>
</component> </component>

10
.idea/migrations.xml generated Normal file
View file

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectMigrations">
<option name="MigrateToGradleLocalJavaHome">
<set>
<option value="$PROJECT_DIR$" />
</set>
</option>
</component>
</project>

2
.idea/misc.xml generated
View file

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<project version="4"> <project version="4">
<component name="ExternalStorageConfigurationManager" enabled="true" /> <component name="ExternalStorageConfigurationManager" enabled="true" />
<component name="ProjectRootManager" version="2" languageLevel="JDK_19" default="true" project-jdk-name="19" project-jdk-type="JavaSDK"> <component name="ProjectRootManager" version="2" languageLevel="JDK_17" default="true" project-jdk-name="jbr-17" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/build/classes" /> <output url="file://$PROJECT_DIR$/build/classes" />
</component> </component>
<component name="ProjectType"> <component name="ProjectType">

2
.idea/vcs.xml generated
View file

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<project version="4"> <project version="4">
<component name="VcsDirectoryMappings"> <component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" /> <mapping directory="" vcs="Git" />
</component> </component>
</project> </project>

View file

@ -12,8 +12,8 @@ android {
applicationId = "io.github.pyoncord.xposed" applicationId = "io.github.pyoncord.xposed"
minSdk = 24 minSdk = 24
targetSdk = 33 targetSdk = 33
versionCode = 203 versionCode = 204
versionName = "0.2.3" versionName = "0.2.4"
} }
buildTypes { buildTypes {

View file

@ -5,15 +5,12 @@ package io.github.pyoncord.xposed
import android.content.res.AssetManager import android.content.res.AssetManager
import android.os.Build import android.os.Build
import android.graphics.Color
import android.graphics.Typeface import android.graphics.Typeface
import android.graphics.Typeface.CustomFallbackBuilder import android.graphics.Typeface.CustomFallbackBuilder
import android.graphics.fonts.Font import android.graphics.fonts.Font
import android.graphics.fonts.FontFamily import android.graphics.fonts.FontFamily
import android.util.Log import android.util.Log
import android.webkit.URLUtil
import de.robv.android.xposed.XC_MethodReplacement import de.robv.android.xposed.XC_MethodReplacement
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.serialization.Serializable import kotlinx.serialization.Serializable
@ -21,8 +18,6 @@ import kotlinx.serialization.decodeFromString
import kotlinx.serialization.json.* import kotlinx.serialization.json.*
import java.io.IOException import java.io.IOException
import java.io.File import java.io.File
import java.net.HttpURLConnection
import java.net.URL
import kotlinx.coroutines.* import kotlinx.coroutines.*
import io.ktor.client.* import io.ktor.client.*
@ -67,7 +62,7 @@ class FontsModule: PyonModule() {
val assetManager: AssetManager = param.args[2] as AssetManager val assetManager: AssetManager = param.args[2] as AssetManager
return createAssetTypeface(fontFamilyName, style, assetManager) return createAssetTypeface(fontFamilyName, style, assetManager)
} }
}); })
val fontDefFile = File(appInfo.dataDir, "files/pyoncord/fonts.json") val fontDefFile = File(appInfo.dataDir, "files/pyoncord/fonts.json")
if (!fontDefFile.exists()) return@with if (!fontDefFile.exists()) return@with
@ -144,7 +139,7 @@ class FontsModule: PyonModule() {
// ignore // ignore
} }
for (fontRootPath in arrayOf(fontsAbsPath, FONTS_ASSET_PATH).filter { it != null }) { for (fontRootPath in arrayOf(fontsAbsPath, FONTS_ASSET_PATH).filterNotNull()) {
for (fileExtension in FILE_EXTENSIONS) { for (fileExtension in FILE_EXTENSIONS) {
val fileName = java.lang.StringBuilder() val fileName = java.lang.StringBuilder()
.append(fontRootPath) .append(fontRootPath)
@ -220,7 +215,7 @@ class FontsModule: PyonModule() {
// Lastly, after all those checks above, this is the original RN logic for // Lastly, after all those checks above, this is the original RN logic for
// getting the typeface. // getting the typeface.
for (fontRootPath in arrayOf(fontsAbsPath, FONTS_ASSET_PATH).filter { it != null }) { for (fontRootPath in arrayOf(fontsAbsPath, FONTS_ASSET_PATH).filterNotNull()) {
for (fileExtension in FILE_EXTENSIONS) { for (fileExtension in FILE_EXTENSIONS) {
val fileName = java.lang.StringBuilder() val fileName = java.lang.StringBuilder()
.append(fontRootPath) .append(fontRootPath)

View file

@ -1,8 +1,6 @@
package io.github.pyoncord.xposed package io.github.pyoncord.xposed
import android.app.Activity import android.app.Activity
import android.app.AndroidAppHelper
import android.content.Context
import android.content.res.AssetManager import android.content.res.AssetManager
import android.content.res.Resources import android.content.res.Resources
import android.util.Log import android.util.Log
@ -12,7 +10,6 @@ import de.robv.android.xposed.IXposedHookLoadPackage
import de.robv.android.xposed.XC_MethodHook import de.robv.android.xposed.XC_MethodHook
import de.robv.android.xposed.XposedBridge import de.robv.android.xposed.XposedBridge
import de.robv.android.xposed.callbacks.XC_LoadPackage import de.robv.android.xposed.callbacks.XC_LoadPackage
import io.github.pyoncord.xposed.BuildConfig
import io.ktor.client.* import io.ktor.client.*
import io.ktor.client.call.* import io.ktor.client.call.*
import io.ktor.client.request.* import io.ktor.client.request.*
@ -60,14 +57,27 @@ class Main : IXposedHookLoadPackage {
lpparam.classLoader.loadClass("com.discord.react_activities.ReactActivity") lpparam.classLoader.loadClass("com.discord.react_activities.ReactActivity")
}.getOrElse { return } // Package is not our the target app, return }.getOrElse { return } // Package is not our the target app, return
var activity: Activity? = null;
val onActivityCreateCallback = mutableSetOf<(activity: Activity) -> Unit>()
XposedBridge.hookMethod(reactActivity.getDeclaredMethod("onCreate", Bundle::class.java), object : XC_MethodHook() { XposedBridge.hookMethod(reactActivity.getDeclaredMethod("onCreate", Bundle::class.java), object : XC_MethodHook() {
override fun beforeHookedMethod(param: MethodHookParam) { override fun beforeHookedMethod(param: MethodHookParam) {
init(lpparam, param.thisObject as Activity) activity = param.thisObject as Activity;
onActivityCreateCallback.forEach { cb -> cb(activity!!) }
onActivityCreateCallback.clear()
} }
}) })
init(lpparam) { cb ->
if (activity != null) cb(activity!!)
else onActivityCreateCallback.add(cb)
}
} }
fun init(param: XC_LoadPackage.LoadPackageParam, activity: Activity) = with (param) { private fun init(
param: XC_LoadPackage.LoadPackageParam,
onActivityCreate: ((activity: Activity) -> Unit) -> Unit
) = with (param) {
val catalystInstanceImpl = classLoader.loadClass("com.facebook.react.bridge.CatalystInstanceImpl") val catalystInstanceImpl = classLoader.loadClass("com.facebook.react.bridge.CatalystInstanceImpl")
for (module in pyonModules) module.onInit(param) for (module in pyonModules) module.onInit(param)
@ -150,10 +160,16 @@ class Main : IXposedHookLoadPackage {
return@async return@async
} catch (e: RedirectResponseException) { } catch (e: RedirectResponseException) {
if (e.response.status != HttpStatusCode.NotModified) throw e; if (e.response.status != HttpStatusCode.NotModified) throw e;
Log.e("Bunny", "Server reponded with status code 304 - no changes to file") Log.e("Bunny", "Server responded with status code 304 - no changes to file")
} catch (e: Throwable) { } catch (e: Throwable) {
onActivityCreate { activity ->
activity.runOnUiThread { activity.runOnUiThread {
Toast.makeText(activity.applicationContext, "Failed to fetch JS bundle, Bunny may not load!", Toast.LENGTH_SHORT).show() Toast.makeText(
activity.applicationContext,
"Failed to fetch JS bundle, Bunny may not load!",
Toast.LENGTH_SHORT
).show()
}
} }
Log.e("Bunny", "Failed to download bundle", e) Log.e("Bunny", "Failed to download bundle", e)

View file

@ -18,7 +18,7 @@ data class SysColors(
class SysColorsModule : PyonModule() { class SysColorsModule : PyonModule() {
private lateinit var context: Context private lateinit var context: Context
fun isSupported() = Build.VERSION.SDK_INT >= Build.VERSION_CODES.S private fun isSupported() = Build.VERSION.SDK_INT >= Build.VERSION_CODES.S
override fun buildJson(builder: JsonObjectBuilder) { override fun buildJson(builder: JsonObjectBuilder) {
context = AndroidAppHelper.currentApplication() context = AndroidAppHelper.currentApplication()
@ -43,7 +43,7 @@ class SysColorsModule : PyonModule() {
} }
} }
fun convertToColor(id: Int): String { private fun convertToColor(id: Int): String {
val clr = if (isSupported()) ContextCompat.getColor(context, id) else 0 val clr = if (isSupported()) ContextCompat.getColor(context, id) else 0
return String.format("#%06X", 0xFFFFFF and clr) return String.format("#%06X", 0xFFFFFF and clr)
} }

View file

@ -58,14 +58,14 @@ class ThemeModule : PyonModule() {
hookTheme() hookTheme()
} }
fun File.isValidish(): Boolean { private fun File.isValidish(): Boolean {
if (!this.exists()) return false if (!this.exists()) return false
val text = this.readText() val text = this.readText()
return !text.isBlank() && text != "{}" && text != "null" return text.isNotBlank() && text != "{}" && text != "null"
} }
fun getTheme(): Theme? { private fun getTheme(): Theme? {
val filesDir = File(param.appInfo.dataDir, "files").apply { mkdirs() } val filesDir = File(param.appInfo.dataDir, "files").apply { mkdirs() }
val pyonDir = File(filesDir, "pyoncord").apply { mkdirs() } val pyonDir = File(filesDir, "pyoncord").apply { mkdirs() }
val themeFile = File(pyonDir, "current-theme.json") val themeFile = File(pyonDir, "current-theme.json")
@ -139,12 +139,12 @@ class ThemeModule : PyonModule() {
} }
// Convert 0xRRGGBBAA to 0XAARRGGBB // Convert 0xRRGGBBAA to 0XAARRGGBB
fun hexStringToColorInt(hexString: String): Int { private fun hexStringToColorInt(hexString: String): Int {
val parsed = Color.parseColor(hexString) val parsed = Color.parseColor(hexString)
return parsed.takeIf { hexString.length == 7 } ?: parsed and 0xFFFFFF or (parsed ushr 24) return parsed.takeIf { hexString.length == 7 } ?: (parsed and 0xFFFFFF or (parsed ushr 24))
} }
fun hookThemeMethod(themeClass: Class<*>, methodName: String, themeValue: Int) { private fun hookThemeMethod(themeClass: Class<*>, methodName: String, themeValue: Int) {
try { try {
themeClass.getDeclaredMethod(methodName).let { method -> themeClass.getDeclaredMethod(methodName).let { method ->
// Log.i("Hooking $methodName -> ${themeValue.toString(16)}") // Log.i("Hooking $methodName -> ${themeValue.toString(16)}")