feat(GmsCore support): Reduce amount of necessary changes and add update check (#6582)
This commit is contained in:
parent
6f70167369
commit
650e6a2710
9 changed files with 571 additions and 696 deletions
|
|
@ -27,5 +27,4 @@ private fun gmsCoreSupportResourcePatch(
|
|||
toPackageName = REVANCED_MAGAZINES_PACKAGE_NAME,
|
||||
spoofedPackageSignature = "24bb24c05e47e0aefa68a58a766179d9b613a666",
|
||||
gmsCoreVendorGroupIdOption = gmsCoreVendorGroupIdOption,
|
||||
addStringResources = false,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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>()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue