Skip to content

V2.2.1 Stable: deep delegation + fixed collision + safe AXML - #1

Merged
austinsager merged 1 commit into
mainfrom
erik/v2.2.1-stable
Jul 21, 2026
Merged

V2.2.1 Stable: deep delegation + fixed collision + safe AXML#1
austinsager merged 1 commit into
mainfrom
erik/v2.2.1-stable

Conversation

@austinsager

Copy link
Copy Markdown
Owner

Massive overhaul from lspatch to my app. readme.md will be updated soon with explanation.

Copilot AI review requested due to automatic review settings July 21, 2026 18:25
@austinsager
austinsager merged commit a31e66c into main Jul 21, 2026
1 check passed

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR refactors the build/packaging setup while introducing a new “deep delegation” proxy Application and a “persona” spoofing layer in the patch-loader, alongside a “safe AXML” approach intended to avoid corrupting binary manifests.

Changes:

  • Reworked Gradle configuration (root/build scripts, repository config, module wiring).
  • Implemented a deep-delegating LSPatchProxyApplication and simplified LSPatchLoader to focus on persona initialization.
  • Replaced AXML patching with a “safe stub” implementation and adjusted the JAR module packaging approach.

Reviewed changes

Copilot reviewed 7 out of 8 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
settings.gradle.kts Consolidates repository/include declarations.
patch-loader/src/main/java/org/lsposed/lspatch/proxy/LSPatchProxyApplication.java Adds deep delegation that replaces the framework Application instance and updates provider contexts.
patch-loader/src/main/java/org/lsposed/lspatch/loader/LSPatchLoader.java Simplifies loader initialization to persona-related behavior (now conflicts with proxy ownership).
patch-loader/build.gradle.kts Converts patch-loader to a minimal Android library module and removes prior packaging/copy tasks.
jar/src/main/java/org/lsposed/lspatch/jar/utils/AxmlUtils.java Replaces manifest patching with a non-rewriting “safe stub” implementation.
jar/build.gradle.kts Switches to an application/fat-jar style build and changes runtime dependency strategy.
gradle.properties Updates Gradle/AndroidX properties and build verbosity settings.
build.gradle.kts Replaces the prior shared build logic (extras + common Android config) with only plugin declarations.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +11 to 15
public static void patchManifest(File manifestFile, String newAppClass) {
if (!manifestFile.exists()) {
Logger.w("AndroidManifest.xml missing");
return;
}
Comment on lines +16 to +24
Logger.w("════════════════════════════════════════════════════════");
Logger.w("AXML SAFE STUB — no binary rewrite performed");
Logger.w("Persona will NOT activate until real ResXMLTree encoder is added");
Logger.w("Target class: " + (newAppClass != null ? newAppClass : "org.lsposed.lspatch.proxy.LSPatchProxyApplication"));
Logger.w("════════════════════════════════════════════════════════");
try {
Files.setLastModifiedTime(manifestFile.toPath(),
java.nio.file.attribute.FileTime.fromMillis(System.currentTimeMillis()));
} catch (Exception ignored) {}
Comment on lines +76 to 81
if (ai.metaData != null && ai.metaData.containsKey(META_ORIG_APP)) {
String orig = ai.metaData.getString(META_ORIG_APP);
realApplication = (Application) context.getClassLoader()
.loadClass(orig).getDeclaredConstructor().newInstance();
Log.i(TAG, "Delegated to real Application: " + orig);
}
Comment on lines +1 to +8
plugins { id("com.android.library") }
android {
defaultConfig {
multiDexEnabled = false
}

buildFeatures {
buildConfig = true
}

buildTypes {
release {
isMinifyEnabled = false
proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro")
}
}

externalNativeBuild {
cmake {
path("src/main/jni/CMakeLists.txt")
}
}
namespace = "org.lsposed.lspatch.loader"
compileSdk = 35
defaultConfig { minSdk = 26; targetSdk = 35 }
compileOptions { sourceCompatibility = JavaVersion.VERSION_21; targetCompatibility = JavaVersion.VERSION_21 }
}

androidComponents.onVariants { variant ->
val variantCapped = variant.name.replaceFirstChar { it.uppercase() }

task<Copy>("copyDex$variantCapped") {
dependsOn("assemble$variantCapped")
from("$buildDir/intermediates/dex/${variant.name}/mergeDex$variantCapped/classes.dex")
rename("classes.dex", "loader.dex")
into("${rootProject.projectDir}/out/assets/${variant.name}/lspatch")
}

task<Copy>("copySo$variantCapped") {
dependsOn("assemble$variantCapped")
dependsOn("strip${variantCapped}DebugSymbols")
val libDir = variant.name + "/strip${variantCapped}DebugSymbols"
from(
fileTree(
"dir" to "$buildDir/intermediates/stripped_native_libs/$libDir/out/lib",
"include" to listOf("**/liblspatch.so")
)
)
into("${rootProject.projectDir}/out/assets/${variant.name}/lspatch/so")
}

task("copy$variantCapped") {
dependsOn("copySo$variantCapped")
dependsOn("copyDex$variantCapped")

doLast {
println("Dex and so files has been copied to ${rootProject.projectDir}${File.separator}out")
}
}
}

dependencies {
compileOnly("vector:stubs")
implementation("vector:core")
implementation("vector:bridge")
implementation("vector:daemon-service")
implementation(projects.share.android)
implementation(projects.share.java)

implementation(libs.gson)
}
dependencies { implementation("androidx.annotation:annotation:1.8.2") }
Comment thread jar/build.gradle.kts
Comment on lines +1 to 8
plugins { id("java-library"); id("application") }
java { sourceCompatibility = JavaVersion.VERSION_21; targetCompatibility = JavaVersion.VERSION_21 }
application { mainClass.set("org.lsposed.lspatch.jar.Main") }
tasks.jar {
manifest { attributes["Main-Class"] = "org.lsposed.lspatch.jar.Main" }
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
from(configurations.runtimeClasspath.get().map { if (it.isDirectory) it else zipTree(it) })
}
Comment on lines +12 to +16
Log.i(TAG, "Virtual Persona Layer starting...");
DeviceProfileManager persona = DeviceProfileManager.getInstance(base);
BuildSpoofer.apply(persona);
SettingsSpooferStub.prepare(base, persona);
Log.i(TAG, "Persona spoofs applied (Build + Settings). Deep delegation owned by Proxy.");
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants