Skip to content

Instantly share code, notes, and snippets.

@herisulistiyanto
Last active September 12, 2022 08:18
Show Gist options
  • Save herisulistiyanto/1ef3599d3a250b2e5bbeb5ace15ddfaf to your computer and use it in GitHub Desktop.
Save herisulistiyanto/1ef3599d3a250b2e5bbeb5ace15ddfaf to your computer and use it in GitHub Desktop.
manifest-checker.gradle
import org.w3c.dom.Node
/**
* This function will check child nodes from the AndroidManifest.xml file
* whether the nodes (activity, service, receiver) which contains "intent-filter" tag
* has the "android:exported" attribute or not.
* @param manifestFile
* @return List of nodes which doesn't have "android:exported" attribute
*/
def collectMissingAndroidExportedComponents(File manifestFile) {
List<Node> nodesFromDependencies = new ArrayList<>()
def reader = manifestFile.newReader()
def document = groovy.xml.DOMBuilder.parse(reader)
def application = document.getElementsByTagName("application").item(0)
if (application != null) {
println "[MANIFEST-CHECK] Searching for activities, services and receivers with intent filters..."
application.childNodes.each { child ->
def childNodeName = child.nodeName
if (childNodeName == "activity" ||
childNodeName == "activity-alias" ||
childNodeName == "service" ||
childNodeName == "receiver"
) {
def attributes = child.getAttributes()
if (attributes.getNamedItem("android:exported") == null) {
def intentFilters = child.childNodes.findAll {
it.nodeName == "intent-filter"
}
if (intentFilters.size() > 0) {
nodesFromDependencies.add(child)
}
}
}
}
}
return nodesFromDependencies
}
/**
* This function will print the information of the missing android:exported components
* @param nodes
* @return
*/
def printNodeResultInfo(List<Node> nodes) {
if (nodes.size() > 0) {
println "[MANIFEST-CHECK] Found ${nodes.size()} missing android:exported attribute(s):"
nodes.each { node ->
def attributes = node.getAttributes()
def nodeName = node.nodeName
def nodeValue = attributes.getNamedItem("android:name").nodeValue
println "[MANIFEST-CHECK]\t|----> ${nodeName.toUpperCase()} : ${nodeValue}"
}
}
}
/**
* This task will check the AndroidManifest.xml from the build directory (merged_manifests)
* whether the nodes (activity, service, receiver) which contains "intent-filter" tag
* has the "android:exported" attribute or not.
*/
task checkMissingExport {
doLast {
def root = new File(project.buildDir, "")
if (root.isDirectory()) {
def children = root.listFiles()
for (def i = 0; i < children.size(); i++) {
File child = children[i]
if (child.isDirectory()) {
def mergedManifestDir = new File(child, "merged_manifests")
if (mergedManifestDir.exists() && mergedManifestDir.isDirectory()) {
def manifestFiles = mergedManifestDir
.listFiles()
.findAll { directoryChild ->
directoryChild.isDirectory() &&
(new File(directoryChild, "AndroidManifest.xml")).exists()
}
.stream()
.map { directoryWithManifest ->
new File(directoryWithManifest, "AndroidManifest.xml")
}.toArray()
if (manifestFiles.size() > 0) {
File mergedManifest = manifestFiles[0]
if (mergedManifest.exists() && mergedManifest.isFile()) {
List<Node> missingComponents = collectMissingAndroidExportedComponents(mergedManifest)
if (missingComponents.size() > 0) {
println "[MANIFEST-CHECK] Found missing android:exported components in merged manifest: ${mergedManifest.absolutePath}"
printNodeResultInfo(missingComponents)
} else {
println "[MANIFEST-CHECK] OK, No missing android:exported attribute found"
}
}
}
}
}
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment