diff --git a/patch-loader/src/main/java/org/lsposed/npatch/loader/LSPApplication.java b/patch-loader/src/main/java/org/lsposed/npatch/loader/LSPApplication.java index 0eee448..3cfbc11 100644 --- a/patch-loader/src/main/java/org/lsposed/npatch/loader/LSPApplication.java +++ b/patch-loader/src/main/java/org/lsposed/npatch/loader/LSPApplication.java @@ -45,7 +45,6 @@ import java.util.List; import java.util.Map; import java.util.function.BiConsumer; -import dalvik.system.DexFile; import de.robv.android.xposed.XposedBridge; import de.robv.android.xposed.XposedHelpers; import hidden.HiddenApiBridge; @@ -201,19 +200,24 @@ public class LSPApplication { appLoadedApk = activityThread.getPackageInfoNoCheck(appInfo, compatInfo); if (config.injectProvider && providerPath != null) { - ClassLoader loader = appLoadedApk.getClassLoader(); - Object dexPathList = XposedHelpers.getObjectField(loader, "pathList"); - Object dexElements = XposedHelpers.getObjectField(dexPathList, "dexElements"); - int length = Array.getLength(dexElements); - Object newElements = Array.newInstance(dexElements.getClass().getComponentType(), length + 1); - System.arraycopy(dexElements, 0, newElements, 0, length); + try { + ClassLoader loader = appLoadedApk.getClassLoader(); + Object dexPathList = XposedHelpers.getObjectField(loader, "pathList"); + Object dexElements = XposedHelpers.getObjectField(dexPathList, "dexElements"); + int length = Array.getLength(dexElements); + Object newElements = Array.newInstance(dexElements.getClass().getComponentType(), length + 1); + System.arraycopy(dexElements, 0, newElements, 0, length); - DexFile dexFile = new DexFile(providerPath.toString()); - Object element = XposedHelpers.newInstance(XposedHelpers.findClass("dalvik.system.DexPathList$Element", loader), new Class[]{ - DexFile.class - }, dexFile); - Array.set(newElements, length, element); - XposedHelpers.setObjectField(dexPathList, "dexElements", newElements); + // Use reflection for DexFile to handle deprecation on Android 14+ + Class dexFileClass = Class.forName("dalvik.system.DexFile"); + Object dexFile = dexFileClass.getConstructor(String.class).newInstance(providerPath.toString()); + Class elementClass = Class.forName("dalvik.system.DexPathList$Element"); + Object element = elementClass.getConstructor(dexFileClass).newInstance(dexFile); + Array.set(newElements, length, element); + XposedHelpers.setObjectField(dexPathList, "dexElements", newElements); + } catch (Throwable e) { + Log.e(TAG, "Failed to inject provider dex: " + e.getMessage(), e); + } } XposedHelpers.setObjectField(mBoundApplication, "info", appLoadedApk); diff --git a/patch-loader/src/main/java/org/lsposed/npatch/loader/LSPLoader.java b/patch-loader/src/main/java/org/lsposed/npatch/loader/LSPLoader.java index 8214b6e..88ba2ac 100644 --- a/patch-loader/src/main/java/org/lsposed/npatch/loader/LSPLoader.java +++ b/patch-loader/src/main/java/org/lsposed/npatch/loader/LSPLoader.java @@ -2,16 +2,20 @@ package org.lsposed.npatch.loader; import android.app.ActivityThread; import android.app.LoadedApk; -import android.content.res.XResources; +import android.util.Log; + +import java.lang.reflect.Method; import de.robv.android.xposed.XposedBridge; import de.robv.android.xposed.XposedInit; import de.robv.android.xposed.callbacks.XC_LoadPackage; public class LSPLoader { + private static final String TAG = "NPatch"; + public static void initModules(LoadedApk loadedApk) { XposedInit.loadedPackagesInProcess.add(loadedApk.getPackageName()); - XResources.setPackageNameForResDir(loadedApk.getPackageName(), loadedApk.getResDir()); + setPackageNameForResDir(loadedApk.getPackageName(), loadedApk.getResDir()); XC_LoadPackage.LoadPackageParam lpparam = new XC_LoadPackage.LoadPackageParam( XposedBridge.sLoadedPackageCallbacks); lpparam.packageName = loadedApk.getPackageName(); @@ -21,4 +25,18 @@ public class LSPLoader { lpparam.isFirstApplication = true; XC_LoadPackage.callAll(lpparam); } -} + + private static void setPackageNameForResDir(String packageName, String resDir) { + try { + // Use reflection to avoid direct type reference to android.content.res.XResources + // which fails class resolution on Android 16+ due to strict boot classloader + // namespace delegation for the android.content.res.* package. + ClassLoader cl = LSPLoader.class.getClassLoader(); + Class xResourcesClass = cl.loadClass("android.content.res.XResources"); + Method setMethod = xResourcesClass.getMethod("setPackageNameForResDir", String.class, String.class); + setMethod.invoke(null, packageName, resDir); + } catch (Throwable e) { + Log.w(TAG, "XResources.setPackageNameForResDir not available, skipping resource dir setup", e); + } + } +} \ No newline at end of file