feat(GmsCore support): Reduce amount of necessary changes and add update check (#6582)

This commit is contained in:
oSumAtrIX 2026-02-15 19:37:38 +01:00 committed by GitHub
parent 6f70167369
commit 650e6a2710
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 571 additions and 696 deletions

View file

@ -27,5 +27,4 @@ private fun gmsCoreSupportResourcePatch(
toPackageName = REVANCED_MAGAZINES_PACKAGE_NAME,
spoofedPackageSignature = "24bb24c05e47e0aefa68a58a766179d9b613a666",
gmsCoreVendorGroupIdOption = gmsCoreVendorGroupIdOption,
addStringResources = false,
)

View file

@ -22,7 +22,6 @@ private fun gmsCoreSupportResourcePatch(
) = app.revanced.patches.shared.misc.gms.gmsCoreSupportResourcePatch(
fromPackageName = PHOTOS_PACKAGE_NAME,
toPackageName = REVANCED_PHOTOS_PACKAGE_NAME,
addStringResources = false,
spoofedPackageSignature = "24bb24c05e47e0aefa68a58a766179d9b613a600",
gmsCoreVendorGroupIdOption = gmsCoreVendorGroupIdOption,
)

View file

@ -4,15 +4,17 @@ import app.revanced.patcher.patch.Option
import app.revanced.patches.all.misc.resources.addResources
import app.revanced.patches.all.misc.resources.addResourcesPatch
import app.revanced.patches.music.misc.extension.sharedExtensionPatch
import app.revanced.patches.music.misc.fileprovider.fileProviderPatch
import app.revanced.patches.music.misc.gms.Constants.MUSIC_PACKAGE_NAME
import app.revanced.patches.music.misc.gms.Constants.REVANCED_MUSIC_PACKAGE_NAME
import app.revanced.patches.music.misc.settings.PreferenceScreen
import app.revanced.patches.music.misc.settings.settingsPatch
import app.revanced.patches.music.misc.spoof.spoofVideoStreamsPatch
import app.revanced.patches.music.misc.fileprovider.fileProviderPatch
import app.revanced.patches.shared.castContextFetchFingerprint
import app.revanced.patches.shared.misc.gms.gmsCoreSupportPatch
import app.revanced.patches.shared.misc.settings.preference.IntentPreference
import app.revanced.patches.shared.misc.settings.preference.PreferenceScreenPreference
import app.revanced.patches.shared.misc.settings.preference.SwitchPreference
import app.revanced.patches.shared.primeMethodFingerprint
@Suppress("unused")
@ -32,8 +34,8 @@ val gmsCoreSupportPatch = gmsCoreSupportPatch(
compatibleWith(
MUSIC_PACKAGE_NAME(
"7.29.52",
"8.10.52"
)
"8.10.52",
),
)
}
@ -50,21 +52,27 @@ private fun gmsCoreSupportResourcePatch(
val gmsCoreVendorGroupId by gmsCoreVendorGroupIdOption
PreferenceScreen.MISC.addPreferences(
IntentPreference(
"microg_settings",
intent = IntentPreference.Intent("", "org.microg.gms.ui.SettingsActivity") {
"$gmsCoreVendorGroupId.android.gms"
}
)
PreferenceScreenPreference(
"revanced_gms_core_screen",
preferences = setOf(
SwitchPreference("revanced_gms_core_check_updates"),
IntentPreference(
"revanced_gms_core_settings",
intent = IntentPreference.Intent("", "org.microg.gms.ui.SettingsActivity") {
"$gmsCoreVendorGroupId.android.gms"
},
),
),
),
)
}
},
) {
dependsOn(
addResourcesPatch,
settingsPatch,
fileProviderPatch(
MUSIC_PACKAGE_NAME,
REVANCED_MUSIC_PACKAGE_NAME
)
REVANCED_MUSIC_PACKAGE_NAME,
),
)
}

View file

@ -24,7 +24,7 @@ internal val serviceCheckFingerprint = fingerprint {
strings("Google Play Services not available")
}
internal val gmsCoreSupportFingerprint = fingerprint {
internal val getGmsCoreVendorGroupIdFingerprint = fingerprint {
accessFlags(AccessFlags.PRIVATE, AccessFlags.STATIC)
returns("Ljava/lang/String;")
parameters()

View file

@ -2,26 +2,18 @@ package app.revanced.patches.shared.misc.gms
import app.revanced.patcher.Fingerprint
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
import app.revanced.patcher.extensions.InstructionExtensions.instructions
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction
import app.revanced.patcher.patch.BytecodePatchBuilder
import app.revanced.patcher.patch.BytecodePatchContext
import app.revanced.patcher.patch.Option
import app.revanced.patcher.patch.Patch
import app.revanced.patcher.patch.ResourcePatchBuilder
import app.revanced.patcher.patch.ResourcePatchContext
import app.revanced.patcher.patch.bytecodePatch
import app.revanced.patcher.patch.resourcePatch
import app.revanced.patcher.patch.stringOption
import app.revanced.patcher.patch.*
import app.revanced.patches.all.misc.packagename.changePackageNamePatch
import app.revanced.patches.all.misc.packagename.setOrGetFallbackPackageName
import app.revanced.patches.all.misc.resources.addResources
import app.revanced.patches.all.misc.resources.addResourcesPatch
import app.revanced.patches.shared.misc.gms.Constants.ACTIONS
import app.revanced.patches.shared.misc.gms.Constants.AUTHORITIES
import app.revanced.patches.shared.misc.gms.Constants.PERMISSIONS
import app.revanced.util.getReference
import app.revanced.util.returnEarly
import app.revanced.patches.shared.misc.gms.Constants.APP_AUTHORITIES
import app.revanced.patches.shared.misc.gms.Constants.APP_PERMISSIONS
import app.revanced.patches.shared.misc.gms.Constants.GMS_AUTHORITIES
import app.revanced.patches.shared.misc.gms.Constants.GMS_PERMISSIONS
import app.revanced.util.*
import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.builder.instruction.BuilderInstruction21c
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
@ -29,8 +21,7 @@ import com.android.tools.smali.dexlib2.iface.instruction.formats.Instruction21c
import com.android.tools.smali.dexlib2.iface.reference.StringReference
import com.android.tools.smali.dexlib2.immutable.reference.ImmutableStringReference
import com.android.tools.smali.dexlib2.util.MethodUtil
import org.w3c.dom.Element
import org.w3c.dom.Node
import java.net.URI
internal const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/extension/shared/GmsCoreSupport;"
@ -69,10 +60,7 @@ fun gmsCoreSupportPatch(
val gmsCoreVendorGroupIdOption = stringOption(
key = "gmsCoreVendorGroupId",
default = "app.revanced",
values =
mapOf(
"ReVanced" to "app.revanced",
),
values = mapOf("ReVanced" to "app.revanced"),
title = "GmsCore vendor group ID",
description = "The vendor's group ID for GmsCore.",
required = true,
@ -84,9 +72,9 @@ fun gmsCoreSupportPatch(
extensionPatch,
)
val gmsCoreVendorGroupId by gmsCoreVendorGroupIdOption
execute {
val gmsCoreVendorGroupId = gmsCoreVendorGroupIdOption.value!!
fun transformStringReferences(transform: (str: String) -> String?) = classes.forEach {
val mutableClass by lazy {
proxy(it).mutableClass
@ -118,80 +106,54 @@ fun gmsCoreSupportPatch(
}
}
// region Collection of transformations that are applied to all strings.
fun commonTransform(referencedString: String): String? = when (referencedString) {
fun transformPackages(string: String): String? = when (string) {
"com.google",
"com.google.android.gms",
in PERMISSIONS,
in ACTIONS,
in AUTHORITIES,
-> referencedString.replace("com.google", gmsCoreVendorGroupId!!)
in GMS_PERMISSIONS,
in GMS_AUTHORITIES,
-> if (string.startsWith("com.google")) {
string.replace("com.google", gmsCoreVendorGroupId)
} else {
"$gmsCoreVendorGroupId.$string"
}
in APP_PERMISSIONS,
in APP_AUTHORITIES,
-> "$toPackageName.$string"
// No vendor prefix for whatever reason...
"subscribedfeeds" -> "$gmsCoreVendorGroupId.subscribedfeeds"
else -> null
}
fun contentUrisTransform(str: String): String? {
// only when content:// uri
if (str.startsWith("content://")) {
// check if matches any authority
for (authority in AUTHORITIES) {
val uriPrefix = "content://$authority"
if (str.startsWith(uriPrefix)) {
return str.replace(
uriPrefix,
"content://${authority.replace("com.google", gmsCoreVendorGroupId!!)}",
)
}
fun transformContentUrlAuthority(string: String) = if (!string.startsWith("content://")) {
null
} else {
runCatching { URI.create(string) }.map {
when (it.authority) {
in GMS_AUTHORITIES ->
if (it.authority.startsWith("com.google")) {
string.replace("com.google", gmsCoreVendorGroupId)
} else {
string.replace(
it.authority,
"$gmsCoreVendorGroupId.${it.authority}",
)
}
in APP_AUTHORITIES ->
string.replace(it.authority, "$toPackageName.${it.authority}")
else -> null
}
// gms also has a 'subscribedfeeds' authority, check for that one too
val subFeedsUriPrefix = "content://subscribedfeeds"
if (str.startsWith(subFeedsUriPrefix)) {
return str.replace(subFeedsUriPrefix, "content://$gmsCoreVendorGroupId.subscribedfeeds")
}
}
return null
}.getOrNull()
}
fun packageNameTransform(fromPackageName: String, toPackageName: String): (String) -> String? = { string ->
when (string) {
"$fromPackageName.SuggestionProvider",
"$fromPackageName.fileprovider",
-> string.replace(fromPackageName, toPackageName)
else -> null
}
}
fun transformPrimeMethod(packageName: String) {
primeMethodFingerprint!!.method.apply {
var register = 2
val index = instructions.indexOfFirst {
if (it.getReference<StringReference>()?.string != fromPackageName) return@indexOfFirst false
register = (it as OneRegisterInstruction).registerA
return@indexOfFirst true
}
replaceInstruction(index, "const-string v$register, \"$packageName\"")
}
}
// endregion
val packageName = setOrGetFallbackPackageName(toPackageName)
// Transform all strings using all provided transforms, first match wins.
val transformations = arrayOf(
::commonTransform,
::contentUrisTransform,
packageNameTransform(fromPackageName, packageName),
::transformPackages,
::transformContentUrlAuthority,
)
transformStringReferences transform@{ string ->
transformations.forEach { transform ->
transform(string)?.let { transformedString -> return@transform transformedString }
@ -201,16 +163,26 @@ fun gmsCoreSupportPatch(
}
// Specific method that needs to be patched.
primeMethodFingerprint?.let { transformPrimeMethod(packageName) }
if (primeMethodFingerprint?.methodOrNull != null) {
val primeMethod = primeMethodFingerprint.method
val index = primeMethod.indexOfFirstInstruction {
getReference<StringReference>()?.string == fromPackageName
}
val register = primeMethod.getInstruction<OneRegisterInstruction>(index).registerA
primeMethod.replaceInstruction(
index,
"const-string v$register, \"$packageName\"",
)
}
// Return these methods early to prevent the app from crashing.
earlyReturnFingerprints.forEach { it.method.returnEarly() }
serviceCheckFingerprint.method.returnEarly()
// Google Play Utility is not present in all apps, so we need to check if it's present.
if (googlePlayUtilityFingerprint.methodOrNull != null) {
googlePlayUtilityFingerprint.method.returnEarly(0)
}
googlePlayUtilityFingerprint.methodOrNull?.returnEarly(0)
// Set original and patched package names for extension to use.
originalPackageNameExtensionFingerprint.method.returnEarly(fromPackageName)
@ -219,11 +191,11 @@ fun gmsCoreSupportPatch(
mainActivityOnCreateFingerprint.method.addInstruction(
0,
"invoke-static/range { p0 .. p0 }, $EXTENSION_CLASS_DESCRIPTOR->" +
"checkGmsCore(Landroid/app/Activity;)V"
"checkGmsCore(Landroid/app/Activity;)V",
)
// Change the vendor of GmsCore in the extension.
gmsCoreSupportFingerprint.method.returnEarly(gmsCoreVendorGroupId!!)
getGmsCoreVendorGroupIdFingerprint.method.returnEarly(gmsCoreVendorGroupId)
executeBlock()
}
@ -231,274 +203,6 @@ fun gmsCoreSupportPatch(
block()
}
/**
* A collection of permissions, intents and content provider authorities
* that are present in GmsCore which need to be transformed.
*/
private object Constants {
/**
* All permissions.
*/
val PERMISSIONS = setOf(
"com.google.android.c2dm.permission.RECEIVE",
"com.google.android.c2dm.permission.SEND",
"com.google.android.gms.auth.api.phone.permission.SEND",
"com.google.android.gms.permission.AD_ID",
"com.google.android.gms.permission.AD_ID_NOTIFICATION",
"com.google.android.gms.permission.CAR_FUEL",
"com.google.android.gms.permission.CAR_INFORMATION",
"com.google.android.gms.permission.CAR_MILEAGE",
"com.google.android.gms.permission.CAR_SPEED",
"com.google.android.gms.permission.CAR_VENDOR_EXTENSION",
"com.google.android.googleapps.permission.GOOGLE_AUTH",
"com.google.android.googleapps.permission.GOOGLE_AUTH.cp",
"com.google.android.googleapps.permission.GOOGLE_AUTH.local",
"com.google.android.googleapps.permission.GOOGLE_AUTH.mail",
"com.google.android.googleapps.permission.GOOGLE_AUTH.writely",
"com.google.android.gtalkservice.permission.GTALK_SERVICE",
"com.google.android.providers.gsf.permission.READ_GSERVICES",
)
/**
* All intent actions.
*/
val ACTIONS = setOf(
"com.google.android.c2dm.intent.RECEIVE",
"com.google.android.c2dm.intent.REGISTER",
"com.google.android.c2dm.intent.REGISTRATION",
"com.google.android.c2dm.intent.UNREGISTER",
"com.google.android.contextmanager.service.ContextManagerService.START",
"com.google.android.gcm.intent.SEND",
"com.google.android.gms.accounts.ACCOUNT_SERVICE",
"com.google.android.gms.accountsettings.ACCOUNT_PREFERENCES_SETTINGS",
"com.google.android.gms.accountsettings.action.BROWSE_SETTINGS",
"com.google.android.gms.accountsettings.action.VIEW_SETTINGS",
"com.google.android.gms.accountsettings.MY_ACCOUNT",
"com.google.android.gms.accountsettings.PRIVACY_SETTINGS",
"com.google.android.gms.accountsettings.SECURITY_SETTINGS",
"com.google.android.gms.ads.gservice.START",
"com.google.android.gms.ads.identifier.service.EVENT_ATTESTATION",
"com.google.android.gms.ads.service.CACHE",
"com.google.android.gms.ads.service.CONSENT_LOOKUP",
"com.google.android.gms.ads.service.HTTP",
"com.google.android.gms.analytics.service.START",
"com.google.android.gms.app.settings.GoogleSettingsLink",
"com.google.android.gms.appstate.service.START",
"com.google.android.gms.appusage.service.START",
"com.google.android.gms.asterism.service.START",
"com.google.android.gms.audiomodem.service.AudioModemService.START",
"com.google.android.gms.audit.service.START",
"com.google.android.gms.auth.account.authapi.START",
"com.google.android.gms.auth.account.authenticator.auto.service.START",
"com.google.android.gms.auth.account.authenticator.chromeos.START",
"com.google.android.gms.auth.account.authenticator.tv.service.START",
"com.google.android.gms.auth.account.data.service.START",
"com.google.android.gms.auth.api.credentials.PICKER",
"com.google.android.gms.auth.api.credentials.service.START",
"com.google.android.gms.auth.api.identity.service.authorization.START",
"com.google.android.gms.auth.api.identity.service.credentialsaving.START",
"com.google.android.gms.auth.api.identity.service.signin.START",
"com.google.android.gms.auth.api.phone.service.InternalService.START",
"com.google.android.gms.auth.api.signin.service.START",
"com.google.android.gms.auth.be.appcert.AppCertService",
"com.google.android.gms.auth.blockstore.service.START",
"com.google.android.gms.auth.config.service.START",
"com.google.android.gms.auth.cryptauth.cryptauthservice.START",
"com.google.android.gms.auth.GOOGLE_SIGN_IN",
"com.google.android.gms.auth.login.LOGIN",
"com.google.android.gms.auth.proximity.devicesyncservice.START",
"com.google.android.gms.auth.proximity.securechannelservice.START",
"com.google.android.gms.auth.proximity.START",
"com.google.android.gms.auth.service.START",
"com.google.android.gms.backup.ACTION_BACKUP_SETTINGS",
"com.google.android.gms.backup.G1_BACKUP",
"com.google.android.gms.backup.G1_RESTORE",
"com.google.android.gms.backup.GMS_MODULE_RESTORE",
"com.google.android.gms.beacon.internal.IBleService.START",
"com.google.android.gms.car.service.START",
"com.google.android.gms.carrierauth.service.START",
"com.google.android.gms.cast.firstparty.START",
"com.google.android.gms.cast.remote_display.service.START",
"com.google.android.gms.cast.service.BIND_CAST_DEVICE_CONTROLLER_SERVICE",
"com.google.android.gms.cast_mirroring.service.START",
"com.google.android.gms.checkin.BIND_TO_SERVICE",
"com.google.android.gms.chromesync.service.START",
"com.google.android.gms.clearcut.service.START",
"com.google.android.gms.common.account.CHOOSE_ACCOUNT",
"com.google.android.gms.common.download.START",
"com.google.android.gms.common.service.START",
"com.google.android.gms.common.telemetry.service.START",
"com.google.android.gms.config.START",
"com.google.android.gms.constellation.service.START",
"com.google.android.gms.credential.manager.service.firstparty.START",
"com.google.android.gms.deviceconnection.service.START",
"com.google.android.gms.drive.ApiService.RESET_AFTER_BOOT",
"com.google.android.gms.drive.ApiService.START",
"com.google.android.gms.drive.ApiService.STOP",
"com.google.android.gms.droidguard.service.INIT",
"com.google.android.gms.droidguard.service.PING",
"com.google.android.gms.droidguard.service.START",
"com.google.android.gms.enterprise.loader.service.START",
"com.google.android.gms.facs.cache.service.START",
"com.google.android.gms.facs.internal.service.START",
"com.google.android.gms.feedback.internal.IFeedbackService",
"com.google.android.gms.fido.credentialstore.internal_service.START",
"com.google.android.gms.fido.fido2.privileged.START",
"com.google.android.gms.fido.fido2.regular.START",
"com.google.android.gms.fido.fido2.zeroparty.START",
"com.google.android.gms.fido.sourcedevice.service.START",
"com.google.android.gms.fido.targetdevice.internal_service.START",
"com.google.android.gms.fido.u2f.privileged.START",
"com.google.android.gms.fido.u2f.thirdparty.START",
"com.google.android.gms.fido.u2f.zeroparty.START",
"com.google.android.gms.fitness.BleApi",
"com.google.android.gms.fitness.ConfigApi",
"com.google.android.gms.fitness.GoalsApi",
"com.google.android.gms.fitness.GoogleFitnessService.START",
"com.google.android.gms.fitness.HistoryApi",
"com.google.android.gms.fitness.InternalApi",
"com.google.android.gms.fitness.RecordingApi",
"com.google.android.gms.fitness.SensorsApi",
"com.google.android.gms.fitness.SessionsApi",
"com.google.android.gms.fonts.service.START",
"com.google.android.gms.freighter.service.START",
"com.google.android.gms.games.internal.connect.service.START",
"com.google.android.gms.games.PLAY_GAMES_UPGRADE",
"com.google.android.gms.games.service.START",
"com.google.android.gms.gass.START",
"com.google.android.gms.gmscompliance.service.START",
"com.google.android.gms.googlehelp.HELP",
"com.google.android.gms.googlehelp.service.GoogleHelpService.START",
"com.google.android.gms.growth.service.START",
"com.google.android.gms.herrevad.services.LightweightNetworkQualityAndroidService.START",
"com.google.android.gms.icing.INDEX_SERVICE",
"com.google.android.gms.icing.LIGHTWEIGHT_INDEX_SERVICE",
"com.google.android.gms.identity.service.BIND",
"com.google.android.gms.inappreach.service.START",
"com.google.android.gms.instantapps.START",
"com.google.android.gms.kids.service.START",
"com.google.android.gms.languageprofile.service.START",
"com.google.android.gms.learning.internal.dynamitesupport.START",
"com.google.android.gms.learning.intservice.START",
"com.google.android.gms.learning.predictor.START",
"com.google.android.gms.learning.trainer.START",
"com.google.android.gms.learning.training.background.START",
"com.google.android.gms.location.places.GeoDataApi",
"com.google.android.gms.location.places.PlaceDetectionApi",
"com.google.android.gms.location.places.PlacesApi",
"com.google.android.gms.location.reporting.service.START",
"com.google.android.gms.location.settings.LOCATION_HISTORY",
"com.google.android.gms.location.settings.LOCATION_REPORTING_SETTINGS",
"com.google.android.gms.locationsharing.api.START",
"com.google.android.gms.locationsharingreporter.service.START",
"com.google.android.gms.lockbox.service.START",
"com.google.android.gms.matchstick.lighter.service.START",
"com.google.android.gms.mdm.services.DeviceManagerApiService.START",
"com.google.android.gms.mdm.services.START",
"com.google.android.gms.mdns.service.START",
"com.google.android.gms.measurement.START",
"com.google.android.gms.nearby.bootstrap.service.NearbyBootstrapService.START",
"com.google.android.gms.nearby.connection.service.START",
"com.google.android.gms.nearby.fastpair.START",
"com.google.android.gms.nearby.messages.service.NearbyMessagesService.START",
"com.google.android.gms.nearby.sharing.service.NearbySharingService.START",
"com.google.android.gms.nearby.sharing.START_SERVICE",
"com.google.android.gms.notifications.service.START",
"com.google.android.gms.ocr.service.internal.START",
"com.google.android.gms.ocr.service.START",
"com.google.android.gms.oss.licenses.service.START",
"com.google.android.gms.payse.service.BIND",
"com.google.android.gms.people.contactssync.service.START",
"com.google.android.gms.people.service.START",
"com.google.android.gms.phenotype.service.START",
"com.google.android.gms.photos.autobackup.service.START",
"com.google.android.gms.playlog.service.START",
"com.google.android.gms.plus.service.default.INTENT",
"com.google.android.gms.plus.service.image.INTENT",
"com.google.android.gms.plus.service.internal.START",
"com.google.android.gms.plus.service.START",
"com.google.android.gms.potokens.service.START",
"com.google.android.gms.pseudonymous.service.START",
"com.google.android.gms.rcs.START",
"com.google.android.gms.reminders.service.START",
"com.google.android.gms.romanesco.MODULE_BACKUP_AGENT",
"com.google.android.gms.romanesco.service.START",
"com.google.android.gms.safetynet.service.START",
"com.google.android.gms.scheduler.ACTION_PROXY_SCHEDULE",
"com.google.android.gms.search.service.SEARCH_AUTH_START",
"com.google.android.gms.semanticlocation.service.START_ODLH",
"com.google.android.gms.sesame.service.BIND",
"com.google.android.gms.settings.EXPOSURE_NOTIFICATION_SETTINGS",
"com.google.android.gms.setup.auth.SecondDeviceAuth.START",
"com.google.android.gms.signin.service.START",
"com.google.android.gms.smartdevice.d2d.SourceDeviceService.START",
"com.google.android.gms.smartdevice.d2d.TargetDeviceService.START",
"com.google.android.gms.smartdevice.directtransfer.SourceDirectTransferService.START",
"com.google.android.gms.smartdevice.directtransfer.TargetDirectTransferService.START",
"com.google.android.gms.smartdevice.postsetup.PostSetupService.START",
"com.google.android.gms.smartdevice.setup.accounts.AccountsService.START",
"com.google.android.gms.smartdevice.wifi.START_WIFI_HELPER_SERVICE",
"com.google.android.gms.social.location.activity.service.START",
"com.google.android.gms.speech.service.START",
"com.google.android.gms.statementservice.EXECUTE",
"com.google.android.gms.stats.ACTION_UPLOAD_DROPBOX_ENTRIES",
"com.google.android.gms.tapandpay.service.BIND",
"com.google.android.gms.telephonyspam.service.START",
"com.google.android.gms.testsupport.service.START",
"com.google.android.gms.thunderbird.service.START",
"com.google.android.gms.trustagent.BridgeApi.START",
"com.google.android.gms.trustagent.StateApi.START",
"com.google.android.gms.trustagent.trustlet.trustletmanagerservice.BIND",
"com.google.android.gms.trustlet.bluetooth.service.BIND",
"com.google.android.gms.trustlet.connectionlessble.service.BIND",
"com.google.android.gms.trustlet.face.service.BIND",
"com.google.android.gms.trustlet.nfc.service.BIND",
"com.google.android.gms.trustlet.onbody.service.BIND",
"com.google.android.gms.trustlet.place.service.BIND",
"com.google.android.gms.trustlet.voiceunlock.service.BIND",
"com.google.android.gms.udc.service.START",
"com.google.android.gms.update.START_API_SERVICE",
"com.google.android.gms.update.START_SERVICE",
"com.google.android.gms.update.START_SINGLE_USER_API_SERVICE",
"com.google.android.gms.update.START_TV_API_SERVICE",
"com.google.android.gms.usagereporting.service.START",
"com.google.android.gms.userlocation.service.START",
"com.google.android.gms.vehicle.cabin.service.START",
"com.google.android.gms.vehicle.climate.service.START",
"com.google.android.gms.vehicle.info.service.START",
"com.google.android.gms.wallet.service.BIND",
"com.google.android.gms.walletp2p.service.firstparty.BIND",
"com.google.android.gms.walletp2p.service.zeroparty.BIND",
"com.google.android.gms.wearable.BIND",
"com.google.android.gms.wearable.BIND_LISTENER",
"com.google.android.gms.wearable.DATA_CHANGED",
"com.google.android.gms.wearable.MESSAGE_RECEIVED",
"com.google.android.gms.wearable.NODE_CHANGED",
"com.google.android.gsf.action.GET_GLS",
"com.google.android.location.settings.LOCATION_REPORTING_SETTINGS",
"com.google.android.mdd.service.START",
"com.google.android.mdh.service.listener.START",
"com.google.android.mdh.service.START",
"com.google.android.mobstore.service.START",
"com.google.firebase.auth.api.gms.service.START",
"com.google.firebase.dynamiclinks.service.START",
"com.google.iid.TOKEN_REQUEST",
"com.google.android.gms.location.places.ui.PICK_PLACE",
)
/**
* All content provider authorities.
*/
val AUTHORITIES = setOf(
"com.google.android.gms.auth.accounts",
"com.google.android.gms.chimera",
"com.google.android.gms.fonts",
"com.google.android.gms.phenotype",
"com.google.android.gsf.gservices",
"com.google.settings",
)
}
/**
* Abstract resource patch that allows Google apps to run without root and under a different package name
* by using GmsCore instead of Google Play Services.
@ -510,129 +214,139 @@ private object Constants {
* @param executeBlock The additional execution block of the patch.
* @param block The additional block to build the patch.
*/
fun gmsCoreSupportResourcePatch( // This is here only for binary compatibility.
fun gmsCoreSupportResourcePatch(
fromPackageName: String,
toPackageName: String,
spoofedPackageSignature: String,
gmsCoreVendorGroupIdOption: Option<String>,
executeBlock: ResourcePatchContext.() -> Unit = {},
block: ResourcePatchBuilder.() -> Unit = {},
) = gmsCoreSupportResourcePatch(
fromPackageName,
toPackageName,
spoofedPackageSignature,
gmsCoreVendorGroupIdOption,
true,
executeBlock,
block
)
/**
* Abstract resource patch that allows Google apps to run without root and under a different package name
* by using GmsCore instead of Google Play Services.
*
* @param fromPackageName The package name of the original app.
* @param toPackageName The package name to fall back to if no custom package name is specified in patch options.
* @param spoofedPackageSignature The signature of the package to spoof to.
* @param gmsCoreVendorGroupIdOption The option to get the vendor group ID of GmsCore.
* @param addStringResources If the GmsCore shared strings should be added to the patched app.
* @param executeBlock The additional execution block of the patch.
* @param block The additional block to build the patch.
*/
// TODO: On the next major release make this public and delete the public overloaded constructor.
internal fun gmsCoreSupportResourcePatch(
fromPackageName: String,
toPackageName: String,
spoofedPackageSignature: String,
gmsCoreVendorGroupIdOption: Option<String>,
addStringResources: Boolean = true,
executeBlock: ResourcePatchContext.() -> Unit = {},
block: ResourcePatchBuilder.() -> Unit = {},
) = resourcePatch {
dependsOn(
changePackageNamePatch,
addResourcesPatch,
)
val gmsCoreVendorGroupId by gmsCoreVendorGroupIdOption
val gmsCoreVendorGroupId = gmsCoreVendorGroupIdOption.value!!
execute {
// Some patches don't use shared String resources so there's no need to add them.
if (addStringResources) {
addResources("shared", "misc.gms.gmsCoreSupportResourcePatch")
}
addResources("shared", "misc.gms.gmsCoreSupportResourcePatch")
/**
* Add metadata to manifest to support spoofing the package name and signature of GmsCore.
*/
fun addSpoofingMetadata() {
fun Node.adoptChild(
tagName: String,
block: Element.() -> Unit,
) {
val child = ownerDocument.createElement(tagName)
child.block()
appendChild(child)
document("AndroidManifest.xml").use { document ->
document.getElementsByTagName("permission").asSequence().forEach { node ->
val nameElement = node.attributes.getNamedItem("android:name")
nameElement.textContent = toPackageName + nameElement.textContent
}
document("AndroidManifest.xml").use { document ->
val applicationNode =
document
.getElementsByTagName("application")
.item(0)
// Spoof package name and signature.
applicationNode.adoptChild("meta-data") {
setAttribute("android:name", "$gmsCoreVendorGroupId.android.gms.SPOOFED_PACKAGE_NAME")
setAttribute("android:value", fromPackageName)
}
applicationNode.adoptChild("meta-data") {
setAttribute("android:name", "$gmsCoreVendorGroupId.android.gms.SPOOFED_PACKAGE_SIGNATURE")
setAttribute("android:value", spoofedPackageSignature)
}
// GmsCore presence detection in extension.
applicationNode.adoptChild("meta-data") {
// TODO: The name of this metadata should be dynamic.
setAttribute("android:name", "app.revanced.MICROG_PACKAGE_NAME")
setAttribute("android:value", "$gmsCoreVendorGroupId.android.gms")
document.getElementsByTagName("uses-permission").asSequence().forEach { node ->
val nameElement = node.attributes.getNamedItem("android:name")
if (nameElement.textContent in GMS_PERMISSIONS) {
nameElement.textContent.replace("com.google", gmsCoreVendorGroupId)
}
}
}
/**
* Patch the manifest to support GmsCore.
*/
fun patchManifest() {
val packageName = setOrGetFallbackPackageName(toPackageName)
document.getElementsByTagName("provider").asSequence().forEach { node ->
val providerElement = node.attributes.getNamedItem("android:authorities")
val transformations = mapOf(
"package=\"$fromPackageName" to "package=\"$packageName",
"android:authorities=\"$fromPackageName" to "android:authorities=\"$packageName",
"$fromPackageName.permission.C2D_MESSAGE" to "$packageName.permission.C2D_MESSAGE",
"$fromPackageName.DYNAMIC_RECEIVER_NOT_EXPORTED_PERMISSION" to "$packageName.DYNAMIC_RECEIVER_NOT_EXPORTED_PERMISSION",
"com.google.android.c2dm" to "$gmsCoreVendorGroupId.android.c2dm",
"com.google.android.libraries.photos.api.mars" to "$gmsCoreVendorGroupId.android.apps.photos.api.mars",
"</queries>" to "<package android:name=\"$gmsCoreVendorGroupId.android.gms\"/></queries>",
)
providerElement.textContent = providerElement.textContent.split(";")
.joinToString(";") { authority ->
if (authority.startsWith("com.google")) {
authority.replace("com.google", gmsCoreVendorGroupId)
} else {
"$gmsCoreVendorGroupId.$authority"
}
}
}
val manifest = get("AndroidManifest.xml")
manifest.writeText(
transformations.entries.fold(manifest.readText()) { acc, (from, to) ->
acc.replace(
from,
to,
document.getNode("manifest")
.attributes.getNamedItem("package").textContent =
setOrGetFallbackPackageName(toPackageName)
document.getNode("queries").appendChild(
document.createElement("package").apply {
attributes.setNamedItem(
document.createAttribute("android:name").apply {
textContent = "$gmsCoreVendorGroupId.android.gms"
},
)
},
)
}
patchManifest()
addSpoofingMetadata()
val applicationNode = document.getNode("application")
// Spoof package name and signature.
applicationNode.appendChild(
document.createElement("meta-data").apply {
setAttribute(
"android:name",
"$gmsCoreVendorGroupId.android.gms.SPOOFED_PACKAGE_NAME",
)
setAttribute("android:value", fromPackageName)
},
)
applicationNode.appendChild(
document.createElement("meta-data").apply {
setAttribute(
"android:name",
"$gmsCoreVendorGroupId.android.gms.SPOOFED_PACKAGE_SIGNATURE",
)
setAttribute("android:value", spoofedPackageSignature)
},
)
// GmsCore presence detection in extension.
applicationNode.appendChild(
document.createElement("meta-data").apply {
// TODO: The name of this metadata should be dynamic.
setAttribute("android:name", "app.revanced.MICROG_PACKAGE_NAME")
setAttribute("android:value", "$gmsCoreVendorGroupId.android.gms")
},
)
}
executeBlock()
}
block()
}
private object Constants {
val GMS_PERMISSIONS = setOf(
"com.google.android.providers.gsf.permission.READ_GSERVICES",
"com.google.android.c2dm.permission.RECEIVE",
"com.google.android.c2dm.permission.SEND",
"com.google.android.gtalkservice.permission.GTALK_SERVICE",
"com.google.android.googleapps.permission.GOOGLE_AUTH",
"com.google.android.googleapps.permission.GOOGLE_AUTH.cp",
"com.google.android.googleapps.permission.GOOGLE_AUTH.local",
"com.google.android.googleapps.permission.GOOGLE_AUTH.mail",
"com.google.android.googleapps.permission.GOOGLE_AUTH.writely",
"com.google.android.gms.permission.ACTIVITY_RECOGNITION",
"com.google.android.gms.permission.AD_ID",
"com.google.android.gms.permission.AD_ID_NOTIFICATION",
"com.google.android.gms.auth.api.phone.permission.SEND",
"com.google.android.gms.permission.CAR_INFORMATION",
"com.google.android.gms.permission.CAR_SPEED",
"com.google.android.gms.permission.CAR_FUEL",
"com.google.android.gms.permission.CAR_MILEAGE",
"com.google.android.gms.permission.CAR_VENDOR_EXTENSION",
"com.google.android.gms.locationsharingreporter.periodic.STATUS_UPDATE",
"com.google.android.gms.auth.permission.GOOGLE_ACCOUNT_CHANGE",
)
val GMS_AUTHORITIES = setOf(
"google.android.gms.fileprovider",
"com.google.android.gms.auth.accounts",
"com.google.android.gms.chimera",
"com.google.android.gms.fonts",
"com.google.android.gms.phenotype",
"com.google.android.gsf.gservices",
"com.google.settings",
"subscribedfeeds",
)
val APP_PERMISSIONS = mutableSetOf<String>()
val APP_AUTHORITIES = mutableSetOf<String>()
}

View file

@ -6,6 +6,8 @@ import app.revanced.patches.all.misc.resources.addResourcesPatch
import app.revanced.patches.shared.castContextFetchFingerprint
import app.revanced.patches.shared.misc.gms.gmsCoreSupportPatch
import app.revanced.patches.shared.misc.settings.preference.IntentPreference
import app.revanced.patches.shared.misc.settings.preference.PreferenceScreenPreference
import app.revanced.patches.shared.misc.settings.preference.SwitchPreference
import app.revanced.patches.shared.primeMethodFingerprint
import app.revanced.patches.youtube.layout.buttons.overlay.hidePlayerOverlayButtonsPatch
import app.revanced.patches.youtube.misc.extension.sharedExtensionPatch
@ -39,7 +41,7 @@ val gmsCoreSupportPatch = gmsCoreSupportPatch(
"20.07.39",
"20.13.41",
"20.14.43",
)
),
)
}
@ -56,18 +58,24 @@ private fun gmsCoreSupportResourcePatch(
val gmsCoreVendorGroupId by gmsCoreVendorGroupIdOption
PreferenceScreen.MISC.addPreferences(
IntentPreference(
"microg_settings",
intent = IntentPreference.Intent("", "org.microg.gms.ui.SettingsActivity") {
"$gmsCoreVendorGroupId.android.gms"
}
)
PreferenceScreenPreference(
"revanced_gms_core_screen",
preferences = setOf(
SwitchPreference("revanced_gms_core_check_updates"),
IntentPreference(
"revanced_gms_core_settings",
intent = IntentPreference.Intent("", "org.microg.gms.ui.SettingsActivity") {
"$gmsCoreVendorGroupId.android.gms"
},
),
),
),
)
}
},
) {
dependsOn(
addResourcesPatch,
settingsPatch,
accountCredentialsInvalidTextPatch
accountCredentialsInvalidTextPatch,
)
}

View file

@ -101,23 +101,31 @@ To translate new languages or improve the existing translations, visit translate
and changes made here must also be made there. -->
</patch>
<patch id="misc.gms.gmsCoreSupportResourcePatch">
<string name="microg_settings_title">GmsCore Settings</string>
<string name="microg_settings_summary">Settings for GmsCore</string>
<string name="revanced_gms_core_screen_title">GmsCore</string>
<string name="revanced_gms_core_screen_summary">Settings related to GmsCore</string>
<string name="revanced_gms_core_check_updates_title">Check for GmsCore updates</string>
<string name="revanced_gms_core_check_updates_summary_on">Checking for updates is enabled</string>
<string name="revanced_gms_core_check_updates_summary_off">Checking for updates is disabled</string>
<string name="revanced_gms_core_settings_title">Open GmsCore Settings</string>
<string name="revanced_gms_core_settings_summary">Settings of GmsCore</string>
<!-- Translations of this should not be longer than the original English text, otherwise the text can be clipped and not entirely shown. -->
<string name="gms_core_toast_not_installed_message">MicroG GmsCore is not installed. Install it.</string>
<string name="gms_core_dialog_title">Action needed</string>
<string name="gms_core_dialog_not_whitelisted_not_allowed_in_background_message">"MicroG GmsCore does not have permission to run in the background.
<string name="revanced_gms_core_toast_not_installed_message">MicroG GmsCore is not installed. Install it.</string>
<string name="revanced_gms_core_dialog_title">Action needed</string>
<string name="revanced_gms_core_toast_update_check_failed_message">Failed to check for MicroG GmsCore updates</string>
<string name="revanced_gms_core_update_available_message">A new version (%s) of MicroG GmsCore is available. Currently, you are using version %s.</string>
<string name="revanced_gms_core_dialog_not_whitelisted_not_allowed_in_background_message">"MicroG GmsCore does not have permission to run in the background.
Follow the \"Don\'t kill my app\" guide for your phone, and apply the instructions to your MicroG installation.
This is required for the app to work."</string>
<string name="gms_core_dialog_open_website_text">Open website</string>
<string name="gms_core_dialog_not_whitelisted_using_battery_optimizations_message">"MicroG GmsCore battery optimizations must be disabled to prevent issues.
<string name="revanced_gms_core_dialog_open_website_text">Open website</string>
<string name="revanced_gms_core_dialog_cancel_text">Cancel</string>
<string name="revanced_gms_core_dialog_not_whitelisted_using_battery_optimizations_message">"MicroG GmsCore battery optimizations must be disabled to prevent issues.
Disabling battery optimizations for MicroG will not negatively affect battery usage.
Tap the continue button and allow optimization changes."</string>
<string name="gms_core_dialog_continue_text">Continue</string>
<string name="revanced_gms_core_dialog_continue_text">Continue</string>
</patch>
<patch id="misc.fix.playback.spoofVideoStreamsPatch">
<string name="revanced_spoof_video_streams_screen_title">Spoof video streams</string>