Welcome folks, last time we wrote a lint check for making sure that all of our EditText have the android:inputType attribute.
This time we will be writing a check which works on our AndroidManifest.xml file. This check will ensure that our application tag has a child meta-data tag with attribute android:name="android.webkit.WebView.MetricsOptOut". Read the background for that here.
If you haven't yet then first go through the last post otherwise you might not understand many things as we will be building upon what we have created in that post.
Changes to add to last project
We will be building upon the lint-checks module we created last time. We would need to make following changes:
- Add a new issue and detector pertaining to this manifest check
- Register the new issue in
LintRegistryclass
Create the detector
Create a class named WebViewMetricsMetaTagDetector which extends from ManifestDetector
class WebViewMetricsMetaTagDetector : ManifestDetector() {
...
}
Now to define the Issue.
companion object {
@JvmStatic
internal val ISSUE_MISSING_WEBVIEW_METRICS_META_TAG = Issue.create(
id = "MissingWebViewMetricsMetaTag",
briefDescription = "Specify whether you want to opt-out of metrics tracking via WebView.",
explanation = "WebView can upload diagnostic data to Google. You can opt-out by specifying a `meta-data` tag under your `application` tag in manifest.",
category = Category.SECURITY,
priority = 8,
severity = Severity.ERROR,
implementation = Implementation(
WebViewMetricsMetaTagDetector::class.java,
Scope.MANIFEST_SCOPE
)
).addMoreInfo("https://developer.android.com/guide/webapps/managing-webview#metrics")
}
The things that have changed here are:
id,briefDescriptionandexplanationfor the issue.- Scope inside the Implementation object passed against
implementationparameter. We changed fromScope.ALL_RESOURCES_SCOPEtoScope.MANIFEST_SCOPE.
We now override the 2 required methods:
override fun getApplicableElements(): Collection<String>? {
return listOf(
SdkConstants.TAG_APPLICATION
)
}
override fun visitElement(context: XmlContext, element: Element) {
val containsWebViewMetricsOptOutTag = element.childNodes
.toList()
.filter { it.nodeName == "meta-data" }
.any { node ->
node.attributes.toPairedNameValueList().filter { attribute ->
attribute.first == "android:name" && attribute.second == "android.webkit.WebView.MetricsOptOut"
}.isNotEmpty()
}
if (!containsWebViewMetricsOptOutTag) {
context.report(
issue = ISSUE_MISSING_WEBVIEW_METRICS_META_TAG,
location = context.getLocation(element),
message = ISSUE_MISSING_WEBVIEW_METRICS_META_TAG.getExplanation(TextFormat.TEXT)
)
}
}
In the visitElement method, we are traversing through all children of <application> and checking that a meta-data tag with attribute android:name="android.webkit.WebView.MetricsOptOut" exists. If it does not exist then we raise our issue ISSUE_MISSING_WEBVIEW_METRICS_META_TAG.
Register the new issue
The last thing we need to do now is to add the above created issue in our LintRegistry class.
class LintRegistry : IssueRegistry() {
override val api: Int
get() = CURRENT_API
override val issues: List<Issue>
get() = listOf(
InputTypeDetector.ISSUE_MISSING_INPUT_TYPE,
WebViewMetricsMetaTagDetector.ISSUE_MISSING_WEBVIEW_METRICS_META_TAG // We added this line
)
}
Run the lint checks
There we are done, now to run the lint checks using gradle
./gradlew lint
Want to discuss this or any other interesting thing, hit me up on Twitter @varun_barad.