Last active
September 12, 2022 08:18
-
-
Save herisulistiyanto/1ef3599d3a250b2e5bbeb5ace15ddfaf to your computer and use it in GitHub Desktop.
manifest-checker.gradle
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 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