Created
August 14, 2025 07:39
-
-
Save Sal7one/af0464aa98f35eca4a93ba15e0ffa193 to your computer and use it in GitHub Desktop.
Remove permission on merge android
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import com.android.build.api.artifact.SingleArtifact | |
androidComponents { | |
onVariants { variant -> | |
val cap = variant.name.replaceFirstChar { if (it.isLowerCase()) it.titlecase() else it.toString() } | |
val manifestProvider = variant.artifacts.get(SingleArtifact.MERGED_MANIFEST) | |
val taskName = "enforceNoUnexpectedPermissions$cap" | |
tasks.register(taskName) { | |
inputs.file(manifestProvider) | |
doLast { | |
val xml = manifestProvider.get().asFile.readText() | |
// Match both <uses-permission> and <uses-permission-sdk-23> | |
val rx = Regex("""<uses-permission(?:-sdk-23)?\s+android:name="([^"]+)"""") | |
val found = rx.findAll(xml).map { it.groupValues[1] }.toSet() | |
// Only allow what you truly need. If you want *no* permissions at all, leave this empty. | |
val allowed = setOf<String>( | |
// e.g. "android.permission.POST_NOTIFICATIONS" | |
) | |
val forbidden = found - allowed | |
if (forbidden.isNotEmpty()) { | |
throw GradleException("Forbidden permissions in ${variant.name}: $forbidden") | |
} | |
} | |
} | |
// Run after manifest merge so it always sees the final result | |
tasks.matching { it.name == "merge${cap}Manifest" } | |
.configureEach { finalizedBy(taskName) } | |
} | |
} |
Author
Sal7one
commented
Aug 14, 2025
Current Solution I use
fun String.cap() = replaceFirstChar { if (it.isLowerCase()) it.titlecase() else it.toString() }
androidComponents {
onVariants { variant ->
val cap = variant.name.cap()
val manifestProvider = variant.artifacts.get(SingleArtifact.MERGED_MANIFEST)
val checkTask = tasks.register("checkNoNetPerm$cap") {
inputs.file(manifestProvider)
doLast {
val manifestFile = manifestProvider.get().asFile
val xml = manifestFile.readText()
// Match regardless of spacing / attribute order / newlines
val rx = Regex(
"""<\s*uses-permission\b[^>]*\bandroid:name\s*=\s*"(android\.permission\.INTERNET|android\.permission\.ACCESS_NETWORK_STATE)"""",
setOf(RegexOption.IGNORE_CASE, RegexOption.DOT_MATCHES_ALL))
if (rx.containsMatchIn(xml)) {
throw GradleException(
"Blocked: merged manifest for ${variant.name} contains a network permission at: $manifestFile"
)
}
}
}
// Run the check after manifest is merged in all paths we care about
// 1) After merge<Variant>Manifest (always exists)
tasks.matching { it.name == "merge${cap}Manifest" }
.configureEach { finalizedBy(checkTask) }
// 2) Make packaging tasks depend on the check (covers assemble/bundle invocations)
tasks.matching { it.name == "package$cap" || it.name == "bundle$cap" }
.configureEach { dependsOn(checkTask) }
// 3) As a catch-all, if your build calls high-level tasks like assemble/bundle:
tasks.matching { it.name == "assemble$cap" || it.name == "bundle$cap" }
.configureEach { dependsOn(checkTask) }
}
}
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment