--- name: morphe-library-reference description: Complete reference for all Morphe utility libraries — BytecodeUtils, ResourceUtils, FreeRegisterProvider, Settings, UI, Extensions. Use when writing patches that need utility functions, settings, extensions, or advanced bytecode operations. --- > **When to use:** Writing patches that need more than basic addInstructions. This covers all utility code copied from morphe-patches-library into our repo. # Morphe Library Reference > ⚠️ Pinned source: morphe-patcher `6f189f9`, patches-library `6501aee`. Official docs may lag > the source — the pinned source wins if anything contradicts this file. ## Patch Utilities (Kotlin — `app.morphe.util.*`) ### BytecodeUtils.kt — Most Used **Return overrides (simplest patching):** ```kotlin import app.morphe.util.returnEarly import app.morphe.util.returnLate method.returnEarly() // return-void method.returnEarly(true) // return true at start, skip all code method.returnEarly(false) // return false method.returnEarly(0) // return int 0 method.returnEarly("text") // return string method.returnEarly(null) // return null object method.returnLate(true) // override ALL return statements to true method.returnLate(false) // override ALL return statements to false ``` **`addInstructions` deprecation note:** Always supply the index argument: ```kotlin method.addInstructions(0, "...") // ✅ correct method.addInstructions("...") // ❌ deprecated — will be deleted ``` **Instruction search:** ```kotlin import app.morphe.util.indexOfFirstInstruction import app.morphe.util.indexOfFirstInstructionOrThrow import app.morphe.util.indexOfFirstStringInstruction import app.morphe.util.findInstructionIndicesReversedOrThrow // By opcode method.indexOfFirstInstruction(Opcode.INVOKE_VIRTUAL) method.indexOfFirstInstructionOrThrow(Opcode.RETURN) method.indexOfFirstInstructionOrThrow(startIndex, Opcode.IF_EQZ) // By predicate method.indexOfFirstInstruction { getReference()?.name == "isPremium" } // By string method.indexOfFirstStringInstructionOrThrow("premium") // Reversed (from end — safe for modification) method.indexOfFirstInstructionReversedOrThrow(Opcode.RETURN) method.findInstructionIndicesReversedOrThrow(Opcode.RETURN) // all indices method.findInstructionIndicesReversedOrThrow(stringFilter) // all filter matches // By literal value method.indexOfFirstLiteralInstructionOrThrow(1337L) method.containsLiteralInstruction(1337L) ``` **Literal overrides:** ```kotlin import app.morphe.util.insertLiteralOverride method.insertLiteralOverride(1337L, "Lext;->check(I)I") // call extension method.insertLiteralOverride(1337L, false) // constant override ``` **Control flow:** ```kotlin import app.morphe.util.addInstructionsAtControlFlowLabel method.addInstructionsAtControlFlowLabel(index, "const/4 v0, 0x1") ``` **View hiding:** ```kotlin import app.morphe.util.injectHideViewCall method.injectHideViewCall(insertIndex, viewRegister, "Lext;", "hideView") ``` **toString() discovery:** ```kotlin import app.morphe.util.findFieldFromToString import app.morphe.util.findMethodFromToString val field = method.findFieldFromToString("fieldName=") val targetMethod = method.findMethodFromToString("fieldName=") ``` **Class utilities:** ```kotlin import app.morphe.util.traverseClassHierarchy import app.morphe.util.toPublicAccessFlags traverseClassHierarchy(mutableClass) { /* each class in hierarchy */ } val flags = accessFlags.toPublicAccessFlags() field.removeFlags(AccessFlags.FINAL) mutableClass.constructor() mutableClass.fieldByName("name") classDef.toStringMethod() ``` **Method cloning:** ```kotlin import app.morphe.util.cloneParameters val cloned = method.cloneParameters() ``` **Helpers:** ```kotlin method.addInstructionsToEnd("invoke-static {}, Lext;->hook()V") method.p0Register // actual register number of p0 method.numberOfParameterRegisters // Read all registers used by an instruction val usedRegs: List = instruction.registersUsed true.toHexString() // "0x1" ``` ### FreeRegisterProvider.kt Find unused registers in a method for temporary use without increasing register count. ### MemoryUtils.kt Memory-efficient DEX operations. ### ResourceUtils.kt XML/resource manipulation for ResourcePatch contexts. ### PatchListGenerator.kt Generates patches-list.json during build. ## Patch Templates (Kotlin — `app.morphe.patches.all.misc.*`) ### ReplaceStringPatch ```kotlin import app.morphe.patches.all.misc.string.replaceStringPatch // Replace string globally across all classes val myPatch = replaceStringPatch(from = "old text", to = "new text") ``` ### ResourceMappingPatch Maps resource IDs for use in bytecode patches. ```kotlin import app.morphe.patches.all.misc.resources.getResourceId import app.morphe.patches.all.misc.resources.ResourceType val id = getResourceId(ResourceType.ID, "resource_name") val index = method.indexOfFirstResourceIdOrThrow("resource_name") ``` ### HexPatchBuilder Hex-level binary patching for native libraries. ### TransformInstructionsPatch + MethodCall Transform method calls across entire classes. ## Extension Library (Java — `app.morphe.extension.shared.*`) Runtime code that runs inside the patched app. Use with `extendWith("name.mpe")` in patches. ### Core | Class | Purpose | |-------|---------| | `Utils.java` | Context access, toast, reboot, network checks | | `Logger.java` | Logging with tag support | | `ResourceType.java` | Android resource type enum | | `ResourceUtils.java` | Runtime resource access | | `StringRef.java` | Lazy string reference | ### Search | Class | Purpose | |-------|---------| | `TrieSearch.java` | Base trie search | | `StringTrieSearch.java` | String pattern matching | | `ByteTrieSearch.java` | Byte pattern matching | ### Settings (for patches with user preferences) | Class | Purpose | |-------|---------| | `Setting.java` | Base setting class | | `BooleanSetting.java` | Boolean toggle | | `IntegerSetting.java` | Integer value | | `LongSetting.java` | Long value | | `FloatSetting.java` | Float value | | `StringSetting.java` | String value | | `EnumSetting.java` | Enum selection | | `BaseSettings.java` | Common settings | | `AppLanguage.java` | Language setting | | `SharedPrefCategory.java` | SharedPreferences wrapper | ### UI (for patches with custom UI) | Class | Purpose | |-------|---------| | `CustomDialog.java` | Custom dialog builder | | `SheetBottomDialog.java` | Bottom sheet dialog | | `ColorDot.java` | Color indicator view | | `ColorPickerPreference.java` | Color picker setting | | `ColorPickerView.java` | Color picker widget | | `Dim.java` | Dimension utilities | ## File Locations ``` ${PATCHES_DIR}/patches/src/main/kotlin/ ├── app/morphe/util/ # Kotlin utilities │ ├── BytecodeUtils.kt # ★ Most used │ ├── FreeRegisterProvider.kt │ ├── MemoryUtils.kt │ ├── ResourceUtils.kt │ └── PatchListGenerator.kt ├── app/morphe/patches/all/misc/ # Reusable patch templates │ ├── string/ReplaceStringPatch.kt │ ├── resources/ResourceMappingPatch.kt │ ├── hex/HexPatchBuilder.kt │ └── transformation/ │ ├── MethodCall.kt │ └── TransformInstructionsPatch.kt └── /patches// # Your patches (discover group from build.gradle.kts) ${PATCHES_DIR}/extensions/extension/src/main/java/ └── app/morphe/extension/shared/ # Java runtime code ├── Utils.java, Logger.java, etc. ├── settings/ # Settings framework └── ui/ # UI components ``` `${PATCHES_DIR}` = `${MORPHE_PATCHES_DIR:-morphe-patches}`