mirror of
https://github.com/ReVanced/revanced-patches.git
synced 2024-11-10 09:07:46 +01:00
feat: music-microg-support
patch (#208)
* Add files via upload * feat: complete `music-microg-support` patch * fix: delete unused patch * oh no * dedupelicate some stuff and remove nativelib * Update src/main/kotlin/app/revanced/patches/music/misc/microg/patch/bytecode/MusicMicroGBytecodePatch.kt style: formatting Co-authored-by: oSumAtrIX <johan.melkonyan1@web.de> * refactor: remove listOf * fix: typo * refactor: switch to using direct pattern Co-authored-by: oSumAtrIX <johan.melkonyan1@web.de> * refactor: constants * fix: bump patch version * refactor: use full brand name Co-authored-by: oSumAtrIX <johan.melkonyan1@web.de>
This commit is contained in:
parent
5fc46dd429
commit
50863e97cc
7 changed files with 285 additions and 0 deletions
|
@ -0,0 +1,13 @@
|
||||||
|
package app.revanced.patches.music.misc.microg.annotations
|
||||||
|
|
||||||
|
import app.revanced.patcher.annotation.Compatibility
|
||||||
|
import app.revanced.patcher.annotation.Package
|
||||||
|
|
||||||
|
@Compatibility(
|
||||||
|
[Package(
|
||||||
|
"com.google.android.apps.youtube.music", arrayOf("5.14.53", "5.16.51")
|
||||||
|
)]
|
||||||
|
)
|
||||||
|
@Target(AnnotationTarget.CLASS)
|
||||||
|
@Retention(AnnotationRetention.RUNTIME)
|
||||||
|
internal annotation class MusicMicroGPatchCompatibility
|
|
@ -0,0 +1,21 @@
|
||||||
|
package app.revanced.patches.music.misc.microg.fingerprints
|
||||||
|
|
||||||
|
import app.revanced.patcher.annotation.Name
|
||||||
|
import app.revanced.patcher.annotation.Version
|
||||||
|
import app.revanced.patcher.extensions.or
|
||||||
|
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
||||||
|
import app.revanced.patcher.fingerprint.method.annotation.DirectPatternScanMethod
|
||||||
|
import app.revanced.patcher.fingerprint.method.annotation.MatchingMethod
|
||||||
|
import app.revanced.patches.music.misc.microg.annotations.MusicMicroGPatchCompatibility
|
||||||
|
import org.jf.dexlib2.AccessFlags
|
||||||
|
|
||||||
|
@Name("google-play-utility-fingerprint")
|
||||||
|
@MatchingMethod(
|
||||||
|
"Lnuv;", "b"
|
||||||
|
)
|
||||||
|
@DirectPatternScanMethod
|
||||||
|
@MusicMicroGPatchCompatibility
|
||||||
|
@Version("0.0.1")
|
||||||
|
object GooglePlayUtilityFingerprint : MethodFingerprint(
|
||||||
|
"I", AccessFlags.PUBLIC or AccessFlags.STATIC, listOf("L", "I"), null, listOf("This should never happen.", "MetadataValueReader", "GooglePlayServicesUtil", "com.android.vending", "android.hardware.type.embedded")
|
||||||
|
)
|
|
@ -0,0 +1,19 @@
|
||||||
|
package app.revanced.patches.music.misc.microg.fingerprints
|
||||||
|
|
||||||
|
import app.revanced.patcher.annotation.Name
|
||||||
|
import app.revanced.patcher.annotation.Version
|
||||||
|
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
||||||
|
import app.revanced.patcher.fingerprint.method.annotation.DirectPatternScanMethod
|
||||||
|
import app.revanced.patcher.fingerprint.method.annotation.MatchingMethod
|
||||||
|
import app.revanced.patches.music.misc.microg.annotations.MusicMicroGPatchCompatibility
|
||||||
|
|
||||||
|
@Name("google-play-prime-fingerprint")
|
||||||
|
@MatchingMethod(
|
||||||
|
"Lrwi;", "a"
|
||||||
|
)
|
||||||
|
@DirectPatternScanMethod
|
||||||
|
@MusicMicroGPatchCompatibility
|
||||||
|
@Version("0.0.1")
|
||||||
|
object PrimeFingerprint : MethodFingerprint(
|
||||||
|
null, null, null, null, listOf("com.google.android.GoogleCamera", "com.android.vending")
|
||||||
|
)
|
|
@ -0,0 +1,21 @@
|
||||||
|
package app.revanced.patches.music.misc.microg.fingerprints
|
||||||
|
|
||||||
|
import app.revanced.patcher.annotation.Name
|
||||||
|
import app.revanced.patcher.annotation.Version
|
||||||
|
import app.revanced.patcher.extensions.or
|
||||||
|
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
||||||
|
import app.revanced.patcher.fingerprint.method.annotation.FuzzyPatternScanMethod
|
||||||
|
import app.revanced.patcher.fingerprint.method.annotation.MatchingMethod
|
||||||
|
import app.revanced.patches.music.misc.microg.annotations.MusicMicroGPatchCompatibility
|
||||||
|
import org.jf.dexlib2.AccessFlags
|
||||||
|
|
||||||
|
@Name("google-play-service-checker-fingerprint")
|
||||||
|
@MatchingMethod(
|
||||||
|
"Lnuv;", "d"
|
||||||
|
)
|
||||||
|
@FuzzyPatternScanMethod(2) // FIXME: Test this threshold and find the best value.
|
||||||
|
@MusicMicroGPatchCompatibility
|
||||||
|
@Version("0.0.1")
|
||||||
|
object ServiceCheckFingerprint : MethodFingerprint(
|
||||||
|
"V", AccessFlags.PUBLIC or AccessFlags.STATIC, listOf("L", "I"), null, listOf("Google Play Services not available")
|
||||||
|
)
|
|
@ -0,0 +1,160 @@
|
||||||
|
package app.revanced.patches.music.misc.microg.patch.bytecode
|
||||||
|
|
||||||
|
import app.revanced.extensions.equalsAny
|
||||||
|
import app.revanced.patcher.annotation.Description
|
||||||
|
import app.revanced.patcher.annotation.Name
|
||||||
|
import app.revanced.patcher.annotation.Version
|
||||||
|
import app.revanced.patcher.data.impl.BytecodeData
|
||||||
|
import app.revanced.patcher.extensions.addInstructions
|
||||||
|
import app.revanced.patcher.extensions.replaceInstruction
|
||||||
|
import app.revanced.patcher.patch.annotations.Dependencies
|
||||||
|
import app.revanced.patcher.patch.annotations.Patch
|
||||||
|
import app.revanced.patcher.patch.impl.BytecodePatch
|
||||||
|
import app.revanced.patcher.patch.PatchResult
|
||||||
|
import app.revanced.patcher.patch.PatchResultSuccess
|
||||||
|
import app.revanced.patcher.util.proxy.mutableTypes.MutableClass
|
||||||
|
import app.revanced.patches.music.misc.microg.annotations.MusicMicroGPatchCompatibility
|
||||||
|
import app.revanced.patches.music.misc.microg.patch.resource.MusicMicroGResourcePatch
|
||||||
|
import app.revanced.patches.youtube.misc.microg.patch.resource.enum.StringReplaceMode
|
||||||
|
import app.revanced.patches.music.misc.microg.shared.Constants.BASE_MICROG_PACKAGE_NAME
|
||||||
|
import app.revanced.patches.music.misc.microg.shared.Constants.REVANCED_MUSIC_PACKAGE_NAME
|
||||||
|
import app.revanced.patches.music.misc.microg.fingerprints.*
|
||||||
|
import org.jf.dexlib2.Opcode
|
||||||
|
import org.jf.dexlib2.builder.MutableMethodImplementation
|
||||||
|
import org.jf.dexlib2.builder.instruction.BuilderInstruction21c
|
||||||
|
import org.jf.dexlib2.iface.instruction.formats.Instruction21c
|
||||||
|
import org.jf.dexlib2.iface.reference.StringReference
|
||||||
|
import org.jf.dexlib2.immutable.reference.ImmutableStringReference
|
||||||
|
|
||||||
|
@Patch
|
||||||
|
@Dependencies([MusicMicroGResourcePatch::class])
|
||||||
|
@Name("music-microg-support")
|
||||||
|
@Description("Patch to allow YouTube Music ReVanced to run without root and under a different package name.")
|
||||||
|
@MusicMicroGPatchCompatibility
|
||||||
|
@Version("0.0.1")
|
||||||
|
class MusicMicroGBytecodePatch : BytecodePatch(
|
||||||
|
listOf(
|
||||||
|
ServiceCheckFingerprint,
|
||||||
|
GooglePlayUtilityFingerprint,
|
||||||
|
PrimeFingerprint,
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
override fun execute(data: BytecodeData): PatchResult {
|
||||||
|
disablePlayServiceChecks()
|
||||||
|
data.classes.forEach { classDef ->
|
||||||
|
var proxiedClass: MutableClass? = null
|
||||||
|
|
||||||
|
classDef.methods.forEach methodLoop@{ method ->
|
||||||
|
val implementation = method.implementation ?: return@methodLoop
|
||||||
|
|
||||||
|
var proxiedImplementation: MutableMethodImplementation? = null
|
||||||
|
|
||||||
|
implementation.instructions.forEachIndexed { i, instruction ->
|
||||||
|
if (instruction.opcode != Opcode.CONST_STRING) return@forEachIndexed
|
||||||
|
|
||||||
|
val stringValue = ((instruction as Instruction21c).reference as StringReference).string
|
||||||
|
|
||||||
|
val replaceMode = if (stringValue.equalsAny(
|
||||||
|
"com.google.android.gms",
|
||||||
|
"com.google.android.gms.chimera",
|
||||||
|
"com.google.android.c2dm.intent.REGISTER",
|
||||||
|
"com.google.android.c2dm.permission.SEND",
|
||||||
|
"com.google.iid.TOKEN_REQUEST",
|
||||||
|
"com.google",
|
||||||
|
"com.google.android.gms.chimera.GmsIntentOperationService",
|
||||||
|
"com.google.android.gms.phenotype.internal.IPhenotypeCallbacks",
|
||||||
|
"com.google.android.gms.phenotype.internal.IPhenotypeService",
|
||||||
|
"com.google.android.gms.phenotype.service.START",
|
||||||
|
"com.google.android.gms.phenotype.PACKAGE_NAME",
|
||||||
|
"com.google.android.gms.phenotype.UPDATE",
|
||||||
|
"com.google.android.gms.phenotype",
|
||||||
|
"com.google.android.gms.auth.accounts",
|
||||||
|
"com.google.android.c2dm.intent.REGISTRATION",
|
||||||
|
"com.google.android.gsf.action.GET_GLS",
|
||||||
|
"com.google.android.gsf.login",
|
||||||
|
"content://com.google.settings/partner",
|
||||||
|
"content://com.google.android.gms.phenotype/",
|
||||||
|
"content://com.google.android.gsf.gservices",
|
||||||
|
"content://com.google.android.gsf.gservices/prefix",
|
||||||
|
"com.google.android.c2dm.intent.RECEIVE"
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
StringReplaceMode.REPLACE_WITH_MICROG
|
||||||
|
} else if (stringValue.equalsAny(
|
||||||
|
"com.google.android.apps.youtube.music.SuggestionsProvider", "com.google.android.apps.youtube.music.fileprovider"
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
StringReplaceMode.REPLACE_WITH_REVANCED
|
||||||
|
} else {
|
||||||
|
StringReplaceMode.DO_NOT_REPLACE
|
||||||
|
}
|
||||||
|
|
||||||
|
if (replaceMode != StringReplaceMode.DO_NOT_REPLACE) {
|
||||||
|
if (proxiedClass == null) {
|
||||||
|
proxiedClass = data.proxy(classDef).resolve()
|
||||||
|
}
|
||||||
|
|
||||||
|
if (proxiedImplementation == null) {
|
||||||
|
proxiedImplementation = proxiedClass!!.methods.first {
|
||||||
|
it.name == method.name && it.parameterTypes.containsAll(method.parameterTypes)
|
||||||
|
}.implementation!!
|
||||||
|
}
|
||||||
|
|
||||||
|
val newString = if (replaceMode == StringReplaceMode.REPLACE_WITH_REVANCED) stringValue.replace(
|
||||||
|
"com.google.android.apps.youtube.music", REVANCED_MUSIC_PACKAGE_NAME
|
||||||
|
)
|
||||||
|
else stringValue.replace("com.google", BASE_MICROG_PACKAGE_NAME)
|
||||||
|
|
||||||
|
proxiedImplementation!!.replaceInstruction(
|
||||||
|
i, BuilderInstruction21c(
|
||||||
|
Opcode.CONST_STRING, instruction.registerA, ImmutableStringReference(newString)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return PatchResultSuccess()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun disablePlayServiceChecks() {
|
||||||
|
listOf(
|
||||||
|
ServiceCheckFingerprint,
|
||||||
|
GooglePlayUtilityFingerprint,
|
||||||
|
).forEach { fingerprint ->
|
||||||
|
val result = fingerprint.result!!
|
||||||
|
val stringInstructions = when (result.method.returnType.first()) {
|
||||||
|
'V' -> "return-void"
|
||||||
|
'I' -> """
|
||||||
|
const/4 v0, 0x0
|
||||||
|
return v0
|
||||||
|
"""
|
||||||
|
|
||||||
|
else -> throw Exception("This case should never happen.")
|
||||||
|
}
|
||||||
|
result.mutableMethod.addInstructions(
|
||||||
|
0, stringInstructions
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
val primeMethod = PrimeFingerprint.result!!.mutableMethod
|
||||||
|
val implementation = primeMethod.implementation!!
|
||||||
|
|
||||||
|
var register = 2
|
||||||
|
val index = implementation.instructions.indexOfFirst {
|
||||||
|
if (it.opcode != Opcode.CONST_STRING) return@indexOfFirst false
|
||||||
|
|
||||||
|
val instructionString = ((it as Instruction21c).reference as StringReference).string
|
||||||
|
if (instructionString != "com.google.android.apps.youtube.music") return@indexOfFirst false
|
||||||
|
|
||||||
|
register = it.registerA
|
||||||
|
return@indexOfFirst true
|
||||||
|
}
|
||||||
|
|
||||||
|
primeMethod.replaceInstruction(
|
||||||
|
index, "const-string v$register, \"$REVANCED_MUSIC_PACKAGE_NAME\""
|
||||||
|
)
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,44 @@
|
||||||
|
package app.revanced.patches.music.misc.microg.patch.resource
|
||||||
|
|
||||||
|
import app.revanced.patcher.annotation.Description
|
||||||
|
import app.revanced.patcher.annotation.Name
|
||||||
|
import app.revanced.patcher.annotation.Version
|
||||||
|
import app.revanced.patcher.data.impl.ResourceData
|
||||||
|
import app.revanced.patcher.patch.PatchResult
|
||||||
|
import app.revanced.patcher.patch.PatchResultSuccess
|
||||||
|
import app.revanced.patcher.patch.impl.ResourcePatch
|
||||||
|
import app.revanced.patches.music.misc.microg.annotations.MusicMicroGPatchCompatibility
|
||||||
|
import app.revanced.patches.music.misc.microg.shared.Constants.BASE_MICROG_PACKAGE_NAME
|
||||||
|
import app.revanced.patches.music.misc.microg.shared.Constants.REVANCED_MUSIC_APP_NAME
|
||||||
|
import app.revanced.patches.music.misc.microg.shared.Constants.REVANCED_MUSIC_PACKAGE_NAME
|
||||||
|
|
||||||
|
@Name("music-microg-resource-patch")
|
||||||
|
@Description("Resource patch to allow YouTube Music ReVanced to run without root and under a different package name.")
|
||||||
|
@MusicMicroGPatchCompatibility
|
||||||
|
@Version("0.0.1")
|
||||||
|
class MusicMicroGResourcePatch : ResourcePatch() {
|
||||||
|
override fun execute(data: ResourceData): PatchResult {
|
||||||
|
|
||||||
|
val manifest = data["AndroidManifest.xml"].readText()
|
||||||
|
|
||||||
|
data["AndroidManifest.xml"].writeText(
|
||||||
|
manifest.replace(
|
||||||
|
"package=\"com.google.android.apps.youtube.music", "package=\"$REVANCED_MUSIC_PACKAGE_NAME"
|
||||||
|
).replace(
|
||||||
|
"android:label=\"@string/app_name", "android:label=\"$REVANCED_MUSIC_APP_NAME"
|
||||||
|
).replace(
|
||||||
|
"android:label=\"@string/app_launcher_name", "android:label=\"$REVANCED_MUSIC_APP_NAME"
|
||||||
|
).replace(
|
||||||
|
"android:authorities=\"com.google.android.apps.youtube.music", "android:authorities=\"$REVANCED_MUSIC_PACKAGE_NAME"
|
||||||
|
).replace(
|
||||||
|
"com.google.android.apps.youtube.music.permission.C2D_MESSAGE", "$REVANCED_MUSIC_PACKAGE_NAME.permission.C2D_MESSAGE"
|
||||||
|
).replace(
|
||||||
|
"com.google.android.c2dm", "$BASE_MICROG_PACKAGE_NAME.android.c2dm"
|
||||||
|
).replace(
|
||||||
|
"</queries>", "<package android:name=\"$BASE_MICROG_PACKAGE_NAME.android.gms\"/></queries>"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
return PatchResultSuccess()
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
package app.revanced.patches.music.misc.microg.shared
|
||||||
|
|
||||||
|
object Constants {
|
||||||
|
internal const val BASE_MICROG_PACKAGE_NAME = "com.mgoogle"
|
||||||
|
internal const val REVANCED_MUSIC_APP_NAME = "YouTube Music ReVanced"
|
||||||
|
internal const val REVANCED_MUSIC_PACKAGE_NAME = "app.revanced.android.apps.youtube.music"
|
||||||
|
}
|
Loading…
Reference in a new issue