Skip to content

Increase testing coverage and maintainability of android manifest parsing logic #174070

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 21 commits into
base: master
Choose a base branch
from

Conversation

reidbaker
Copy link
Contributor

@reidbaker reidbaker commented Aug 19, 2025

Related to: #166550
Follow up to #173794 to implement suggested improvements and with strictly human authored tests changes.

Pre-launch Checklist

  • I read the [Contributor Guide] and followed the process outlined there for submitting PRs.
  • I read the [Tree Hygiene] wiki page, which explains my responsibilities.
  • I read and followed the [Flutter Style Guide], including [Features we expect every widget to implement].
  • I signed the [CLA].
  • I listed at least one issue that this PR fixes in the description above.
  • I updated/added relevant documentation (doc comments with ///).
  • I added new tests to check the change I am making, or this PR is [test-exempt].
  • I followed the [breaking change policy] and added [Data Driven Fixes] where supported.
  • All existing and new tests are passing.

@reidbaker reidbaker requested a review from a team as a code owner August 19, 2025 20:31
@github-actions github-actions bot added platform-android Android applications specifically tool Affects the "flutter" command-line tool. See also t: labels. labels Aug 19, 2025
Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request is a great improvement. It refactors the Android manifest parsing logic for deeplinks into a dedicated, modern Gradle task, which significantly enhances maintainability and testability. The addition of a comprehensive test suite with a manifest builder is also excellent. My feedback focuses on further improving maintainability by leveraging Kotlin's features for immutability in your data classes, which is a best practice and aligns with the goals of this PR.

Comment on lines +14 to +21
@VisibleForTesting
var scheme: String?,
@VisibleForTesting
var host: String?,
@VisibleForTesting
var path: String?,
private var intentFilterCheck: IntentFilterCheck
@VisibleForTesting
var intentFilterCheck: IntentFilterCheck
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

These properties do not appear to be modified after the Deeplink object is created. You can make them immutable by using val instead of var. This improves maintainability, makes the class thread-safe, and also resolves the TODO on line 12.1

Since val properties are public by default, you can also remove the @VisibleForTesting annotation.

    val scheme: String?,
    val host: String?,
    val path: String?,
    val intentFilterCheck: IntentFilterCheck

Style Guide References

Footnotes

  1. The Android Kotlin Style Guide recommends preferring val over var for properties that are not reassigned after initialization to ensure immutability.

Comment on lines +11 to +16
class IntentFilterCheck(
var hasAutoVerify: Boolean = false,
var hasActionView: Boolean = false,
var hasDefaultCategory: Boolean = false,
var hasBrowsableCategory: Boolean = false
) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

This class can be converted to a data class with immutable val properties. This improves maintainability and makes instances of this class truly immutable.1

This change would require adjusting the instantiation logic in DeepLinkJsonFromManifestTaskHelper.kt to gather all boolean values before creating the IntentFilterCheck instance, which would also be an improvement.

Suggested change
class IntentFilterCheck(
var hasAutoVerify: Boolean = false,
var hasActionView: Boolean = false,
var hasDefaultCategory: Boolean = false,
var hasBrowsableCategory: Boolean = false
) {
data class IntentFilterCheck(
val hasAutoVerify: Boolean = false,
val hasActionView: Boolean = false,
val hasDefaultCategory: Boolean = false,
val hasBrowsableCategory: Boolean = false
) {

Style Guide References

Footnotes

  1. The Android Kotlin Style Guide recommends preferring val over var for properties that are not reassigned after initialization to ensure immutability. Using a data class also provides useful generated methods like equals(), hashCode(), and toString().

Comment on lines 98 to 119
val intentFilterCheck = IntentFilterCheck()
if (appLinkIntent.attribute("android:autoVerify") == MANIFEST_VALUE_TRUE) {
intentFilterCheck.hasAutoVerify = true
}

val actionItems: List<Node> =
appLinkIntent.children().filterIsInstance<Node>().filter { item ->
item.name() == "action"
}

intentFilterCheck.hasActionView =
actionItems.any { action ->
action.attribute(MANIFEST_NAME_KEY) == "android.intent.action.VIEW"
}
val categoryItems: List<Node> =
appLinkIntent.children().filterIsInstance<Node>().filter { item ->
item.name() == "category"
}
intentFilterCheck.hasDefaultCategory =
categoryItems.any { category -> category.attribute(MANIFEST_NAME_KEY) == "android.intent.category.DEFAULT" }
intentFilterCheck.hasBrowsableCategory =
categoryItems.any { category -> category.attribute(MANIFEST_NAME_KEY) == "android.intent.category.BROWSABLE" }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

To support making IntentFilterCheck an immutable data class, you can refactor this block to first determine the values for its properties, and then create an immutable instance in a single call. This improves readability and maintainability by separating the logic for determining the checks from the object creation.1

                val hasAutoVerify = appLinkIntent.attribute("android:autoVerify") == MANIFEST_VALUE_TRUE

                val actionItems: List<Node> =
                    appLinkIntent.children().filterIsInstance<Node>().filter { item ->
                        item.name() == "action"
                    }
                val hasActionView = actionItems.any { action ->
                        action.attribute(MANIFEST_NAME_KEY) == "android.intent.action.VIEW"
                    }

                val categoryItems: List<Node> =
                    appLinkIntent.children().filterIsInstance<Node>().filter { item ->
                        item.name() == "category"
                    }
                val hasDefaultCategory = categoryItems.any { category -> category.attribute(MANIFEST_NAME_KEY) == "android.intent.category.DEFAULT" }
                val hasBrowsableCategory = categoryItems.any { category -> category.attribute(MANIFEST_NAME_KEY) == "android.intent.category.BROWSABLE" }

                val intentFilterCheck = IntentFilterCheck(
                    hasAutoVerify = hasAutoVerify,
                    hasActionView = hasActionView,
                    hasDefaultCategory = hasDefaultCategory,
                    hasBrowsableCategory = hasBrowsableCategory
                )

Style Guide References

Footnotes

  1. The Android Kotlin Style Guide recommends preferring val over var for properties that are not reassigned after initialization to ensure immutability.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
platform-android Android applications specifically tool Affects the "flutter" command-line tool. See also t: labels.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant