diff --git a/tools/aapt2/cmd/Link.cpp b/tools/aapt2/cmd/Link.cpp index 0910040fb07ad..db42e7cb3e021 100644 --- a/tools/aapt2/cmd/Link.cpp +++ b/tools/aapt2/cmd/Link.cpp @@ -2120,6 +2120,12 @@ int Link(const std::vector& args, IDiagnostics* diagnostics) { .OptionalFlag("--version-name", "Version name to inject into the AndroidManifest.xml if none is present.", &options.manifest_fixer_options.version_name_default) + .OptionalSwitch("--replace-version", + "If --version-code and/or --version-name are specified, these\n" + "values will replace any value already in the manifest. By\n" + "default, nothing is changed if the manifest already defines\n" + "these attributes.", + &options.manifest_fixer_options.replace_version) .OptionalFlag("--compile-sdk-version-code", "Version code (integer) to inject into the AndroidManifest.xml if none is\n" "present.", diff --git a/tools/aapt2/link/ManifestFixer.cpp b/tools/aapt2/link/ManifestFixer.cpp index bfff1487d4be9..ee4e702889948 100644 --- a/tools/aapt2/link/ManifestFixer.cpp +++ b/tools/aapt2/link/ManifestFixer.cpp @@ -261,6 +261,9 @@ bool ManifestFixer::BuildRules(xml::XmlActionExecutor* executor, manifest_action.Action(FixCoreAppAttribute); manifest_action.Action([&](xml::Element* el) -> bool { if (options_.version_name_default) { + if (options_.replace_version) { + el->RemoveAttribute(xml::kSchemaAndroid, "versionName"); + } if (el->FindAttribute(xml::kSchemaAndroid, "versionName") == nullptr) { el->attributes.push_back( xml::Attribute{xml::kSchemaAndroid, "versionName", @@ -269,6 +272,9 @@ bool ManifestFixer::BuildRules(xml::XmlActionExecutor* executor, } if (options_.version_code_default) { + if (options_.replace_version) { + el->RemoveAttribute(xml::kSchemaAndroid, "versionCode"); + } if (el->FindAttribute(xml::kSchemaAndroid, "versionCode") == nullptr) { el->attributes.push_back( xml::Attribute{xml::kSchemaAndroid, "versionCode", diff --git a/tools/aapt2/link/ManifestFixer.h b/tools/aapt2/link/ManifestFixer.h index 7d6fad2f09187..98d06fd776d70 100644 --- a/tools/aapt2/link/ManifestFixer.h +++ b/tools/aapt2/link/ManifestFixer.h @@ -44,10 +44,12 @@ struct ManifestFixerOptions { // . Maybe rename_instrumentation_target_package; - // The version name to set if 'android:versionName' is not defined in . + // The version name to set if 'android:versionName' is not defined in or if + // replace_version is set. Maybe version_name_default; - // The version code to set if 'android:versionCode' is not defined in . + // The version code to set if 'android:versionCode' is not defined in or if + // replace_version is set. Maybe version_code_default; // The version of the framework being compiled against to set for 'android:compileSdkVersion' in @@ -65,6 +67,9 @@ struct ManifestFixerOptions { // Whether to inject the android:debuggable="true" flag into the manifest bool debug_mode = false; + + // Whether to replace the manifest version with the the command line version + bool replace_version = false; }; // Verifies that the manifest is correctly formed and inserts defaults where specified with diff --git a/tools/aapt2/link/ManifestFixer_test.cpp b/tools/aapt2/link/ManifestFixer_test.cpp index 5f406e81f65da..5bc004d62ff2d 100644 --- a/tools/aapt2/link/ManifestFixer_test.cpp +++ b/tools/aapt2/link/ManifestFixer_test.cpp @@ -349,6 +349,136 @@ TEST_F(ManifestFixerTest, UseDefaultVersionNameAndCode) { EXPECT_THAT(attr->value, StrEq("0x10000000")); } +TEST_F(ManifestFixerTest, DontUseDefaultVersionNameAndCode) { +ManifestFixerOptions options; +options.version_name_default = std::string("Beta"); +options.version_code_default = std::string("0x10000000"); + +std::unique_ptr doc = VerifyWithOptions(R"EOF( + )EOF", + options); +ASSERT_THAT(doc, NotNull()); + +xml::Element* manifest_el = doc->root.get(); +ASSERT_THAT(manifest_el, NotNull()); + +xml::Attribute* attr = + manifest_el->FindAttribute(xml::kSchemaAndroid, "versionName"); +ASSERT_THAT(attr, NotNull()); +EXPECT_THAT(attr->value, StrEq("Alpha")); + +attr = manifest_el->FindAttribute(xml::kSchemaAndroid, "versionCode"); +ASSERT_THAT(attr, NotNull()); +EXPECT_THAT(attr->value, StrEq("0x20000000")); +} + +TEST_F(ManifestFixerTest, ReplaceVersionNameAndCode) { +ManifestFixerOptions options; +options.replace_version = true; +options.version_name_default = std::string("Beta"); +options.version_code_default = std::string("0x10000000"); + +std::unique_ptr doc = VerifyWithOptions(R"EOF( + )EOF", + options); +ASSERT_THAT(doc, NotNull()); + +xml::Element* manifest_el = doc->root.get(); +ASSERT_THAT(manifest_el, NotNull()); + +xml::Attribute* attr = + manifest_el->FindAttribute(xml::kSchemaAndroid, "versionName"); +ASSERT_THAT(attr, NotNull()); +EXPECT_THAT(attr->value, StrEq("Beta")); + +attr = manifest_el->FindAttribute(xml::kSchemaAndroid, "versionCode"); +ASSERT_THAT(attr, NotNull()); +EXPECT_THAT(attr->value, StrEq("0x10000000")); +} + +TEST_F(ManifestFixerTest, ReplaceVersionName) { +ManifestFixerOptions options; +options.replace_version = true; +options.version_name_default = std::string("Beta"); + +std::unique_ptr doc = VerifyWithOptions(R"EOF( + )EOF", + options); +ASSERT_THAT(doc, NotNull()); + +xml::Element* manifest_el = doc->root.get(); +ASSERT_THAT(manifest_el, NotNull()); + +xml::Attribute* attr = + manifest_el->FindAttribute(xml::kSchemaAndroid, "versionName"); +ASSERT_THAT(attr, NotNull()); +EXPECT_THAT(attr->value, StrEq("Beta")); + +attr = manifest_el->FindAttribute(xml::kSchemaAndroid, "versionCode"); +ASSERT_THAT(attr, NotNull()); +EXPECT_THAT(attr->value, StrEq("0x20000000")); +} + +TEST_F(ManifestFixerTest, ReplaceVersionCode) { +ManifestFixerOptions options; +options.replace_version = true; +options.version_code_default = std::string("0x10000000"); + +std::unique_ptr doc = VerifyWithOptions(R"EOF( + )EOF", + options); +ASSERT_THAT(doc, NotNull()); + +xml::Element* manifest_el = doc->root.get(); +ASSERT_THAT(manifest_el, NotNull()); + +xml::Attribute* attr = + manifest_el->FindAttribute(xml::kSchemaAndroid, "versionName"); +ASSERT_THAT(attr, NotNull()); +EXPECT_THAT(attr->value, StrEq("Alpha")); + +attr = manifest_el->FindAttribute(xml::kSchemaAndroid, "versionCode"); +ASSERT_THAT(attr, NotNull()); +EXPECT_THAT(attr->value, StrEq("0x10000000")); +} + +TEST_F(ManifestFixerTest, DontReplaceVersionNameOrCode) { +ManifestFixerOptions options; +options.replace_version = true; + +std::unique_ptr doc = VerifyWithOptions(R"EOF( +)EOF", + options); +ASSERT_THAT(doc, NotNull()); + +xml::Element* manifest_el = doc->root.get(); +ASSERT_THAT(manifest_el, NotNull()); + +xml::Attribute* attr = + manifest_el->FindAttribute(xml::kSchemaAndroid, "versionName"); +ASSERT_THAT(attr, NotNull()); +EXPECT_THAT(attr->value, StrEq("Alpha")); + +attr = manifest_el->FindAttribute(xml::kSchemaAndroid, "versionCode"); +ASSERT_THAT(attr, NotNull()); +EXPECT_THAT(attr->value, StrEq("0x20000000")); +} + TEST_F(ManifestFixerTest, EnsureManifestAttributesAreTyped) { EXPECT_THAT(Verify(""), IsNull()); EXPECT_THAT(Verify(""), IsNull()); diff --git a/tools/aapt2/xml/XmlDom.cpp b/tools/aapt2/xml/XmlDom.cpp index b6cd086975453..acd07c2876c83 100644 --- a/tools/aapt2/xml/XmlDom.cpp +++ b/tools/aapt2/xml/XmlDom.cpp @@ -423,6 +423,15 @@ const Attribute* Element::FindAttribute(const StringPiece& ns, const StringPiece return nullptr; } +void Element::RemoveAttribute(const StringPiece& ns, const StringPiece& name) { + auto new_attr_end = std::remove_if(attributes.begin(), attributes.end(), + [&](const Attribute& attr) -> bool { + return ns == attr.namespace_uri && name == attr.name; + }); + + attributes.erase(new_attr_end, attributes.end()); +} + Attribute* Element::FindOrCreateAttribute(const StringPiece& ns, const StringPiece& name) { Attribute* attr = FindAttribute(ns, name); if (attr == nullptr) { diff --git a/tools/aapt2/xml/XmlDom.h b/tools/aapt2/xml/XmlDom.h index 8f3829611f30e..a5b2d10fc9e06 100644 --- a/tools/aapt2/xml/XmlDom.h +++ b/tools/aapt2/xml/XmlDom.h @@ -102,6 +102,8 @@ class Element : public Node { const android::StringPiece& name) const; Attribute* FindOrCreateAttribute(const android::StringPiece& ns, const android::StringPiece& name); + void RemoveAttribute(const android::StringPiece& ns, + const android::StringPiece& name); Element* FindChild(const android::StringPiece& ns, const android::StringPiece& name); const Element* FindChild(const android::StringPiece& ns, const android::StringPiece& name) const;