From 048827feee43c5f363ff2d375ce35393208eb847 Mon Sep 17 00:00:00 2001 From: WeiguangTWK Date: Mon, 30 Mar 2026 17:14:52 +0800 Subject: [PATCH] Treewide: Migrate XPosed API to 101 --- app/build.gradle | 2 +- app/src/main/AndroidManifest.xml | 19 +- .../gakumas/localify/GakumasHookMain.kt | 374 +++++++++--------- .../localify/hookUtils/FilesChecker.kt | 92 ++--- .../resources/META-INF/xposed/java_init.list | 1 + .../resources/META-INF/xposed/module.prop | 3 + gradle/libs.versions.toml | 4 +- settings.gradle | 1 - 8 files changed, 239 insertions(+), 257 deletions(-) create mode 100644 app/src/main/resources/META-INF/xposed/java_init.list create mode 100644 app/src/main/resources/META-INF/xposed/module.prop diff --git a/app/build.gradle b/app/build.gradle index 256e6b1..f112b91 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -130,6 +130,6 @@ dependencies { implementation(libs.xdl) implementation(libs.shadowhook) - compileOnly(libs.xposed.api) + compileOnly(libs.libxposed.api) implementation(libs.kotlinx.serialization.json) } \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 8ff0e43..c25d888 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -21,23 +21,6 @@ android:usesCleartextTraffic="true" tools:targetApi="31"> - - - - - - - - \ No newline at end of file + diff --git a/app/src/main/java/io/github/chinosk/gakumas/localify/GakumasHookMain.kt b/app/src/main/java/io/github/chinosk/gakumas/localify/GakumasHookMain.kt index 55891f2..5e5a6c3 100644 --- a/app/src/main/java/io/github/chinosk/gakumas/localify/GakumasHookMain.kt +++ b/app/src/main/java/io/github/chinosk/gakumas/localify/GakumasHookMain.kt @@ -3,7 +3,7 @@ package io.github.chinosk.gakumas.localify import android.annotation.SuppressLint import android.app.Activity import android.app.AlertDialog -import android.app.AndroidAppHelper +import android.app.Application import android.content.Context import android.content.Intent import android.content.Intent.FLAG_ACTIVITY_NEW_TASK @@ -17,34 +17,32 @@ import android.view.MotionEvent import android.widget.Toast import com.bytedance.shadowhook.ShadowHook import com.bytedance.shadowhook.ShadowHook.ConfigBuilder -import de.robv.android.xposed.IXposedHookLoadPackage -import de.robv.android.xposed.IXposedHookZygoteInit -import de.robv.android.xposed.XC_MethodHook -import de.robv.android.xposed.XposedBridge -import de.robv.android.xposed.XposedHelpers -import de.robv.android.xposed.callbacks.XC_LoadPackage +import io.github.chinosk.gakumas.localify.hookUtils.FileHotUpdater import io.github.chinosk.gakumas.localify.hookUtils.FilesChecker +import io.github.chinosk.gakumas.localify.hookUtils.FilesChecker.localizationFilesDir +import io.github.chinosk.gakumas.localify.mainUtils.json import io.github.chinosk.gakumas.localify.models.GakumasConfig +import io.github.chinosk.gakumas.localify.models.NativeInitProgress +import io.github.chinosk.gakumas.localify.models.ProgramConfig +import io.github.chinosk.gakumas.localify.ui.game_attach.InitProgressUI +import io.github.libxposed.api.XposedInterface +import io.github.libxposed.api.XposedModule +import io.github.libxposed.api.XposedModuleInterface import kotlinx.coroutines.DelicateCoroutinesApi import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.delay import kotlinx.coroutines.isActive import kotlinx.coroutines.launch import java.io.File +import java.lang.reflect.Method import java.util.Locale import kotlin.system.measureTimeMillis -import io.github.chinosk.gakumas.localify.hookUtils.FileHotUpdater -import io.github.chinosk.gakumas.localify.hookUtils.FilesChecker.localizationFilesDir -import io.github.chinosk.gakumas.localify.mainUtils.json -import io.github.chinosk.gakumas.localify.models.NativeInitProgress -import io.github.chinosk.gakumas.localify.models.ProgramConfig -import io.github.chinosk.gakumas.localify.ui.game_attach.InitProgressUI val TAG = "GakumasLocalify" -class GakumasHookMain : IXposedHookLoadPackage, IXposedHookZygoteInit { - private lateinit var modulePath: String - private var nativeLibLoadSuccess: Boolean +class GakumasHookMain : XposedModule() { + private var modulePath: String = "" + private var nativeLibLoadSuccess: Boolean = false private var alreadyInitialized = false private val targetPackageName = "com.bandainamcoent.idolmaster_gakuen" private val nativeLibName = "MarryKotone" @@ -55,160 +53,187 @@ class GakumasHookMain : IXposedHookLoadPackage, IXposedHookZygoteInit { private var externalFilesChecked: Boolean = false private var gameActivity: Activity? = null - override fun handleLoadPackage(lpparam: XC_LoadPackage.LoadPackageParam) { -// if (lpparam.packageName == "io.github.chinosk.gakumas.localify") { -// XposedHelpers.findAndHookMethod( -// "io.github.chinosk.gakumas.localify.MainActivity", -// lpparam.classLoader, -// "showToast", -// String::class.java, -// object : XC_MethodHook() { -// override fun beforeHookedMethod(param: MethodHookParam) { -// Log.d(TAG, "beforeHookedMethod hooked: ${param.args}") -// } -// } -// ) -// } + override fun onModuleLoaded(param: XposedModuleInterface.ModuleLoadedParam) { + modulePath = getModuleApplicationInfo().sourceDir - if (lpparam.packageName != targetPackageName) { + ShadowHook.init( + ConfigBuilder() + .setMode(ShadowHook.Mode.UNIQUE) + .build() + ) + + nativeLibLoadSuccess = try { + System.loadLibrary(nativeLibName) + true + } catch (_: UnsatisfiedLinkError) { + false + } + } + + override fun onPackageReady(param: XposedModuleInterface.PackageReadyParam) { + if (param.packageName != targetPackageName) { return } - XposedHelpers.findAndHookMethod( - "android.app.Activity", - lpparam.classLoader, - "dispatchKeyEvent", - KeyEvent::class.java, - object : XC_MethodHook() { - override fun beforeHookedMethod(param: MethodHookParam) { - val keyEvent = param.args[0] as KeyEvent - val keyCode = keyEvent.keyCode - val action = keyEvent.action - // Log.d(TAG, "Key event: keyCode=$keyCode, action=$action") - keyboardEvent(keyCode, action) - } + val classLoader = param.classLoader + + hookMethod( + classLoader = classLoader, + className = "android.app.Activity", + methodName = "dispatchKeyEvent", + parameterTypes = arrayOf(KeyEvent::class.java), + before = { chain -> + val keyEvent = chain.getArg(0) as KeyEvent + keyboardEvent(keyEvent.keyCode, keyEvent.action) } ) - XposedHelpers.findAndHookMethod( - "android.app.Activity", - lpparam.classLoader, - "dispatchGenericMotionEvent", - MotionEvent::class.java, - object : XC_MethodHook() { - override fun beforeHookedMethod(param: MethodHookParam) { - val motionEvent = param.args[0] as MotionEvent - val action = motionEvent.action + hookMethod( + classLoader = classLoader, + className = "android.app.Activity", + methodName = "dispatchGenericMotionEvent", + parameterTypes = arrayOf(MotionEvent::class.java), + before = { chain -> + val motionEvent = chain.getArg(0) as MotionEvent + val action = motionEvent.action - // 左摇杆的X和Y轴 - val leftStickX = motionEvent.getAxisValue(MotionEvent.AXIS_X) - val leftStickY = motionEvent.getAxisValue(MotionEvent.AXIS_Y) + val leftStickX = motionEvent.getAxisValue(MotionEvent.AXIS_X) + val leftStickY = motionEvent.getAxisValue(MotionEvent.AXIS_Y) + val rightStickX = motionEvent.getAxisValue(MotionEvent.AXIS_Z) + val rightStickY = motionEvent.getAxisValue(MotionEvent.AXIS_RZ) + val leftTrigger = motionEvent.getAxisValue(MotionEvent.AXIS_LTRIGGER) + val rightTrigger = motionEvent.getAxisValue(MotionEvent.AXIS_RTRIGGER) + val hatX = motionEvent.getAxisValue(MotionEvent.AXIS_HAT_X) + val hatY = motionEvent.getAxisValue(MotionEvent.AXIS_HAT_Y) - // 右摇杆的X和Y轴 - val rightStickX = motionEvent.getAxisValue(MotionEvent.AXIS_Z) - val rightStickY = motionEvent.getAxisValue(MotionEvent.AXIS_RZ) - - // 左扳机 - val leftTrigger = motionEvent.getAxisValue(MotionEvent.AXIS_LTRIGGER) - - // 右扳机 - val rightTrigger = motionEvent.getAxisValue(MotionEvent.AXIS_RTRIGGER) - - // 十字键 - val hatX = motionEvent.getAxisValue(MotionEvent.AXIS_HAT_X) - val hatY = motionEvent.getAxisValue(MotionEvent.AXIS_HAT_Y) - - // 处理摇杆和扳机事件 - joystickEvent( - action, - leftStickX, - leftStickY, - rightStickX, - rightStickY, - leftTrigger, - rightTrigger, - hatX, - hatY - ) - } + joystickEvent( + action, + leftStickX, + leftStickY, + rightStickX, + rightStickY, + leftTrigger, + rightTrigger, + hatX, + hatY + ) } ) - val appActivityClass = XposedHelpers.findClass("android.app.Activity", lpparam.classLoader) - XposedBridge.hookAllMethods(appActivityClass, "onStart", object : XC_MethodHook() { - override fun beforeHookedMethod(param: MethodHookParam) { - super.beforeHookedMethod(param) - Log.d(TAG, "onStart") - val currActivity = param.thisObject as Activity - gameActivity = currActivity - if (getConfigError != null) { - showGetConfigFailed(currActivity) - } - else { - initGkmsConfig(currActivity) - } + val activityClass = classLoader.loadClass("android.app.Activity") + hookAllMethods(activityClass, "onStart") { chain -> + Log.d(TAG, "onStart") + val currActivity = chain.thisObject as Activity + gameActivity = currActivity + if (getConfigError != null) { + showGetConfigFailed(currActivity) + } else { + initGkmsConfig(currActivity) } - }) + chain.proceed() + } - XposedBridge.hookAllMethods(appActivityClass, "onResume", object : XC_MethodHook() { - override fun beforeHookedMethod(param: MethodHookParam) { - Log.d(TAG, "onResume") - val currActivity = param.thisObject as Activity - gameActivity = currActivity - if (getConfigError != null) { - showGetConfigFailed(currActivity) - } - else { - initGkmsConfig(currActivity) - } + hookAllMethods(activityClass, "onResume") { chain -> + Log.d(TAG, "onResume") + val currActivity = chain.thisObject as Activity + gameActivity = currActivity + if (getConfigError != null) { + showGetConfigFailed(currActivity) + } else { + initGkmsConfig(currActivity) } - }) + chain.proceed() + } - val cls = lpparam.classLoader.loadClass("com.unity3d.player.UnityPlayer") - XposedHelpers.findAndHookMethod( - cls, - "loadNative", - String::class.java, - object : XC_MethodHook() { - @SuppressLint("UnsafeDynamicallyLoadedCode") - override fun afterHookedMethod(param: MethodHookParam) { - super.afterHookedMethod(param) + val unityPlayerClass = classLoader.loadClass("com.unity3d.player.UnityPlayer") + val loadNativeMethod = unityPlayerClass.getDeclaredMethod("loadNative", String::class.java) - Log.i(TAG, "UnityPlayer.loadNative") - - if (alreadyInitialized) { - return - } - - val app = AndroidAppHelper.currentApplication() - if (nativeLibLoadSuccess) { - showToast("lib$nativeLibName.so loaded.") - } - else { - showToast("Load native library lib$nativeLibName.so failed.") - return - } - - if (!gkmsDataInited) { - requestConfig(app.applicationContext) - } - - FilesChecker.initDir(app.filesDir, modulePath) - initHook( - "${app.applicationInfo.nativeLibraryDir}/libil2cpp.so", - File( - app.filesDir.absolutePath, - FilesChecker.localizationFilesDir - ).absolutePath - ) - - alreadyInitialized = true - } - }) + hook(loadNativeMethod).intercept { chain -> + val result = chain.proceed() + onUnityLoadNativeAfterHook() + result + } startLoop() } + private fun hookMethod( + classLoader: ClassLoader, + className: String, + methodName: String, + parameterTypes: Array>, + before: ((XposedInterface.Chain) -> Unit)? = null, + after: ((XposedInterface.Chain, Any?) -> Unit)? = null, + ) { + val clazz = classLoader.loadClass(className) + val method = clazz.getDeclaredMethod(methodName, *parameterTypes) + hook(method).intercept { chain -> + before?.invoke(chain) + val result = chain.proceed() + after?.invoke(chain, result) + result + } + } + + private fun hookAllMethods(clazz: Class<*>, methodName: String, interceptor: (XposedInterface.Chain) -> Any?) { + val allMethods = (clazz.declaredMethods.asSequence() + clazz.methods.asSequence()) + .filter { it.name == methodName } + .distinctBy(Method::toGenericString) + .toList() + + allMethods.forEach { method -> + hook(method).intercept { chain -> interceptor(chain) } + } + } + + @SuppressLint("UnsafeDynamicallyLoadedCode") + private fun onUnityLoadNativeAfterHook() { + Log.i(TAG, "UnityPlayer.loadNative") + + if (alreadyInitialized) { + return + } + + val app = getCurrentApplication() + if (app == null) { + Log.e(TAG, "currentApplication is null") + return + } + + if (nativeLibLoadSuccess) { + showToast("lib$nativeLibName.so loaded.") + } else { + showToast("Load native library lib$nativeLibName.so failed.") + return + } + + if (!gkmsDataInited) { + requestConfig(app.applicationContext) + } + + FilesChecker.initDir(app.filesDir, modulePath) + initHook( + "${app.applicationInfo.nativeLibraryDir}/libil2cpp.so", + File( + app.filesDir.absolutePath, + FilesChecker.localizationFilesDir + ).absolutePath + ) + + alreadyInitialized = true + } + + private fun getCurrentApplication(): Application? { + return try { + val activityThreadClass = Class.forName("android.app.ActivityThread") + val method = activityThreadClass.getDeclaredMethod("currentApplication") + method.isAccessible = true + method.invoke(null) as? Application + } catch (_: Throwable) { + null + } + } + @OptIn(DelicateCoroutinesApi::class) private fun startLoop() { GlobalScope.launch { @@ -218,21 +243,20 @@ class GakumasHookMain : IXposedHookLoadPackage, IXposedHookZygoteInit { while (isActive) { val timeTaken = measureTimeMillis { - val returnValue = pluginCallbackLooper() // plugin main thread loop + val returnValue = pluginCallbackLooper() if (returnValue == 9) { NativeInitProgress.startInit = true } - if (NativeInitProgress.startInit) { // if init, update data + if (NativeInitProgress.startInit) { NativeInitProgress.pluginInitProgressLooper(NativeInitProgress) gameActivity?.let { initProgressUI.updateData(it) } } - if ((gameActivity != null) && (lastFrameStartInit != NativeInitProgress.startInit)) { // change status + if ((gameActivity != null) && (lastFrameStartInit != NativeInitProgress.startInit)) { if (NativeInitProgress.startInit) { initProgressUI.createView(gameActivity!!) - } - else { + } else { initProgressUI.finishLoad(gameActivity!!) } } @@ -269,24 +293,19 @@ class GakumasHookMain : IXposedHookLoadPackage, IXposedHookZygoteInit { null } - // 清理本地文件 if (programConfig?.cleanLocalAssets == true) { FilesChecker.cleanAssets() } - // 检查 files 版本和 assets 版本并更新 if (programConfig?.checkBuiltInAssets == true) { FilesChecker.initAndCheck(activity.filesDir, modulePath) } - // 强制导出 assets 文件 if (initConfig?.forceExportResource == true) { FilesChecker.updateFiles() } - // 使用热更新文件 if ((programConfig?.useRemoteAssets == true) || (programConfig?.useAPIAssets == true)) { - // val dataUri = intent.data val dataUri = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { intent.getParcelableExtra("resource_file", Uri::class.java) } else { @@ -297,7 +316,6 @@ class GakumasHookMain : IXposedHookLoadPackage, IXposedHookZygoteInit { if (dataUri != null) { if (!externalFilesChecked) { externalFilesChecked = true - // Log.d(TAG, "dataUri: $dataUri") FileHotUpdater.updateFilesFromZip(activity, dataUri, activity.filesDir, programConfig.delRemoteAfterUpdate) } @@ -305,7 +323,6 @@ class GakumasHookMain : IXposedHookLoadPackage, IXposedHookZygoteInit { else if (programConfig.useAPIAssets) { if (!File(activity.filesDir, localizationFilesDir).exists() && (initConfig?.forceExportResource == false)) { - // 使用 API 资源,不检查内置,API 资源无效,且游戏内没有插件数据时,释放内置数据 FilesChecker.initAndCheck(activity.filesDir, modulePath) } } @@ -444,10 +461,6 @@ class GakumasHookMain : IXposedHookLoadPackage, IXposedHookZygoteInit { } - override fun initZygote(startupParam: IXposedHookZygoteInit.StartupParam) { - modulePath = startupParam.modulePath - } - companion object { @JvmStatic external fun initHook(targetLibraryPath: String, localizationFilesDir: String) @@ -468,21 +481,25 @@ class GakumasHookMain : IXposedHookLoadPackage, IXposedHookZygoteInit { @JvmStatic external fun loadConfig(configJsonStr: String) - // Toast快速切换内容 private var toast: Toast? = null @JvmStatic fun showToast(message: String) { - val app = AndroidAppHelper.currentApplication() + val app = try { + val activityThreadClass = Class.forName("android.app.ActivityThread") + val method = activityThreadClass.getDeclaredMethod("currentApplication") + method.isAccessible = true + method.invoke(null) as? Application + } catch (_: Throwable) { + null + } + val context = app?.applicationContext if (context != null) { val handler = Handler(Looper.getMainLooper()) handler.post { - // 取消之前的 Toast toast?.cancel() - // 创建新的 Toast toast = Toast.makeText(context, message, Toast.LENGTH_SHORT) - // 展示新的 Toast toast?.show() } } @@ -494,19 +511,4 @@ class GakumasHookMain : IXposedHookLoadPackage, IXposedHookZygoteInit { @JvmStatic external fun pluginCallbackLooper(): Int } - - init { - ShadowHook.init( - ConfigBuilder() - .setMode(ShadowHook.Mode.UNIQUE) - .build() - ) - - nativeLibLoadSuccess = try { - System.loadLibrary(nativeLibName) - true - } catch (e: UnsatisfiedLinkError) { - false - } - } -} \ No newline at end of file +} diff --git a/app/src/main/java/io/github/chinosk/gakumas/localify/hookUtils/FilesChecker.kt b/app/src/main/java/io/github/chinosk/gakumas/localify/hookUtils/FilesChecker.kt index ccae7d7..f050bb5 100644 --- a/app/src/main/java/io/github/chinosk/gakumas/localify/hookUtils/FilesChecker.kt +++ b/app/src/main/java/io/github/chinosk/gakumas/localify/hookUtils/FilesChecker.kt @@ -1,15 +1,16 @@ package io.github.chinosk.gakumas.localify.hookUtils -import android.content.res.XModuleResources import android.util.Log import java.io.BufferedReader import java.io.File import java.io.IOException import java.io.InputStream import java.io.InputStreamReader - +import java.util.zip.ZipFile object FilesChecker { + private const val MODULE_ASSETS_PREFIX = "assets/" + lateinit var filesDir: File lateinit var modulePath: String val localizationFilesDir = "gakumas-local" @@ -17,7 +18,6 @@ object FilesChecker { fun initAndCheck(fileDir: File, modulePath: String) { initDir(fileDir, modulePath) - checkFiles() } @@ -46,31 +46,28 @@ object FilesChecker { pluginBasePath.mkdirs() } - val assets = XModuleResources.createInstance(modulePath, null).assets - fun forAllAssetFiles( - basePath: String, - action: (String, InputStream?) -> Unit - ) { - val assetFiles = assets.list(basePath)!! - for (file in assetFiles) { - try { - assets.open("$basePath/$file") - } catch (e: IOException) { - action("$basePath/$file", null) - forAllAssetFiles("$basePath/$file", action) + val rootAssetDir = moduleAssetPath(localizationFilesDir).trimEnd('/') + "/" + ZipFile(modulePath).use { zipFile -> + val entries = zipFile.entries() + while (entries.hasMoreElements()) { + val entry = entries.nextElement() + val name = entry.name + if (!name.startsWith(rootAssetDir)) continue + + val relativePath = name.removePrefix(MODULE_ASSETS_PREFIX) + if (relativePath.isBlank()) continue + + val outFile = File(filesDir, relativePath) + if (entry.isDirectory) { + outFile.mkdirs() continue - }.use { - action("$basePath/$file", it) } - } - } - forAllAssetFiles(localizationFilesDir) { path, file -> - val outFile = File(filesDir, path) - if (file == null) { - outFile.mkdirs() - } else { - outFile.outputStream().use { out -> - file.copyTo(out) + + outFile.parentFile?.mkdirs() + zipFile.getInputStream(entry).use { input -> + outFile.outputStream().use { output -> + input.copyTo(output) + } } } } @@ -79,15 +76,13 @@ object FilesChecker { } fun getPluginVersion(): String { - val assets = XModuleResources.createInstance(modulePath, null).assets - - for (i in assets.list(localizationFilesDir)!!) { - if (i.toString() == "version.txt") { - val stream = assets.open("$localizationFilesDir/$i") + val versionAssetPath = moduleAssetPath("$localizationFilesDir/version.txt") + ZipFile(modulePath).use { zipFile -> + val entry = zipFile.getEntry(versionAssetPath) ?: return "0.0" + zipFile.getInputStream(entry).use { stream -> return convertToString(stream).trim() } } - return "0.0" } fun getInstalledVersion(): String { @@ -100,26 +95,25 @@ object FilesChecker { } fun convertToString(inputStream: InputStream?): String { - val stringBuilder = StringBuilder() - var reader: BufferedReader? = null - try { - reader = BufferedReader(InputStreamReader(inputStream)) - var line: String? - while (reader.readLine().also { line = it } != null) { - stringBuilder.append(line) + if (inputStream == null) return "" + return try { + BufferedReader(InputStreamReader(inputStream)).use { reader -> + buildString { + var line: String? + while (reader.readLine().also { line = it } != null) { + append(line) + } + } } } catch (e: IOException) { e.printStackTrace() - } finally { - if (reader != null) { - try { - reader.close() - } catch (e: IOException) { - e.printStackTrace() - } - } + "" } - return stringBuilder.toString() + } + + private fun moduleAssetPath(path: String): String { + val cleanPath = path.trimStart('/') + return "$MODULE_ASSETS_PREFIX$cleanPath" } private fun deleteRecursively(file: File): Boolean { @@ -167,4 +161,4 @@ object FilesChecker { i18nFile.writeText("{}") } } -} \ No newline at end of file +} diff --git a/app/src/main/resources/META-INF/xposed/java_init.list b/app/src/main/resources/META-INF/xposed/java_init.list new file mode 100644 index 0000000..73f145b --- /dev/null +++ b/app/src/main/resources/META-INF/xposed/java_init.list @@ -0,0 +1 @@ +io.github.chinosk.gakumas.localify.GakumasHookMain diff --git a/app/src/main/resources/META-INF/xposed/module.prop b/app/src/main/resources/META-INF/xposed/module.prop new file mode 100644 index 0000000..92dd5df --- /dev/null +++ b/app/src/main/resources/META-INF/xposed/module.prop @@ -0,0 +1,3 @@ +minApiVersion=101 +targetApiVersion=101 +staticScope=false diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 71f1e97..81b60fa 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -6,7 +6,7 @@ shizukuApi = "12.1.0" hiddenapi-refine = "4.3.0" hiddenapi-stub = "4.2.0" okhttpBom = "4.12.0" -xposedApi = "82" +libxposedApi = "101.0.0" appcompat = "1.7.0" coil = "2.6.0" composeBom = "2024.06.00" @@ -50,7 +50,7 @@ rikka-hidden-stub = { module = "dev.rikka.hidden:stub", version.ref = "hiddenapi logging-interceptor = { module = "com.squareup.okhttp3:logging-interceptor" } okhttp = { module = "com.squareup.okhttp3:okhttp" } okhttp-bom = { module = "com.squareup.okhttp3:okhttp-bom", version.ref = "okhttpBom" } -xposed-api = { module = "de.robv.android.xposed:api", version.ref = "xposedApi" } +libxposed-api = { module = "io.github.libxposed:api", version.ref = "libxposedApi" } coil-svg = { module = "io.coil-kt:coil-svg", version.ref = "coil" } coil-compose = { module = "io.coil-kt:coil-compose", version.ref = "coil" } material = { module = "com.google.android.material:material", version.ref = "material" } diff --git a/settings.gradle b/settings.gradle index cef7bc5..ebc0828 100644 --- a/settings.gradle +++ b/settings.gradle @@ -18,7 +18,6 @@ dependencyResolutionManagement { google() mavenCentral() - maven { url "https://api.xposed.info/" } } }