From d672b04b4746170c07bc39b7b049ab0c584e7a19 Mon Sep 17 00:00:00 2001 From: Ionut Stoica Date: Fri, 27 Dec 2024 21:13:38 +0100 Subject: [PATCH] feat: support completely custom AppxManifest.xml (#8609) --- .changeset/brown-pears-beg.md | 5 + .vscode/launch.json | 2 +- packages/app-builder-lib/scheme.json | 4 + .../src/options/AppXOptions.ts | 27 ++++ .../app-builder-lib/src/targets/AppxTarget.ts | 8 +- .../test-app-one/build/custom-manifest.xml | 47 +++++++ .../build/custom-template-manifest.xml | 50 +++++++ test/snapshots/windows/appxTest.js.snap | 129 ++++++++++++++++++ test/src/windows/appxTest.ts | 33 +++++ 9 files changed, 303 insertions(+), 2 deletions(-) create mode 100644 .changeset/brown-pears-beg.md create mode 100644 test/fixtures/test-app-one/build/custom-manifest.xml create mode 100644 test/fixtures/test-app-one/build/custom-template-manifest.xml diff --git a/.changeset/brown-pears-beg.md b/.changeset/brown-pears-beg.md new file mode 100644 index 00000000000..a637a90a7b7 --- /dev/null +++ b/.changeset/brown-pears-beg.md @@ -0,0 +1,5 @@ +--- +"app-builder-lib": minor +--- + +feat: support completely custom AppxManifest.xml diff --git a/.vscode/launch.json b/.vscode/launch.json index d14b7905ea0..95a34056a89 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -14,4 +14,4 @@ } } ] -} \ No newline at end of file +} diff --git a/packages/app-builder-lib/scheme.json b/packages/app-builder-lib/scheme.json index 2c13de89b76..719f1c38cea 100644 --- a/packages/app-builder-lib/scheme.json +++ b/packages/app-builder-lib/scheme.json @@ -183,6 +183,10 @@ "description": "Relative path to custom extensions xml to be included in an `appmanifest.xml`.", "type": "string" }, + "customManifestPath": { + "description": "(Advanced Option) Relative path to custom `appmanifest.xml` (file name doesn't matter, it'll be renamed) located in build resources directory.\nSupports the following template macros:\n\n- ${publisher}\n- ${publisherDisplayName}\n- ${version}\n- ${applicationId}\n- ${identityName}\n- ${executable}\n- ${displayName}\n- ${description}\n- ${backgroundColor}\n- ${logo}\n- ${square150x150Logo}\n- ${square44x44Logo}\n- ${lockScreen}\n- ${defaultTile}\n- ${splashScreen}\n- ${arch}\n- ${resourceLanguages}\n- ${extensions}\n- ${minVersion}\n- ${maxVersionTested}", + "type": "string" + }, "displayName": { "description": "A friendly name that can be displayed to users. Corresponds to [Properties.DisplayName](https://msdn.microsoft.com/en-us/library/windows/apps/br211432.aspx).\nDefaults to the application product name.", "type": [ diff --git a/packages/app-builder-lib/src/options/AppXOptions.ts b/packages/app-builder-lib/src/options/AppXOptions.ts index 30de2277a08..d5f0ee39d0c 100644 --- a/packages/app-builder-lib/src/options/AppXOptions.ts +++ b/packages/app-builder-lib/src/options/AppXOptions.ts @@ -51,6 +51,33 @@ export interface AppXOptions extends TargetSpecificOptions { */ readonly customExtensionsPath?: string + /** + * (Advanced Option) Relative path to custom `appmanifest.xml` (file name doesn't matter, it'll be renamed) located in build resources directory. + * Supports the following template macros: + * + * - ${publisher} + * - ${publisherDisplayName} + * - ${version} + * - ${applicationId} + * - ${identityName} + * - ${executable} + * - ${displayName} + * - ${description} + * - ${backgroundColor} + * - ${logo} + * - ${square150x150Logo} + * - ${square44x44Logo} + * - ${lockScreen} + * - ${defaultTile} + * - ${splashScreen} + * - ${arch} + * - ${resourceLanguages} + * - ${extensions} + * - ${minVersion} + * - ${maxVersionTested} + */ + readonly customManifestPath?: string + /** * Whether to overlay the app's name on top of tile images on the Start screen. Defaults to `false`. (https://docs.microsoft.com/en-us/uwp/schemas/appxpackage/uapmanifestschema/element-uap-shownameontiles) in the dependencies. * @default false diff --git a/packages/app-builder-lib/src/targets/AppxTarget.ts b/packages/app-builder-lib/src/targets/AppxTarget.ts index d25fbe34fcc..b24c54c6d3f 100644 --- a/packages/app-builder-lib/src/targets/AppxTarget.ts +++ b/packages/app-builder-lib/src/targets/AppxTarget.ts @@ -100,6 +100,7 @@ export default class AppXTarget extends Target { const manifestFile = stageDir.getTempFile("AppxManifest.xml") await this.writeManifest(manifestFile, arch, await this.computePublisherName(), userAssets) + await packager.info.callAppxManifestCreated(manifestFile) mappingList.push(assetInfo.mappings) mappingList.push([`"${vm.toVmFile(manifestFile)}" "AppxManifest.xml"`]) @@ -198,7 +199,12 @@ export default class AppXTarget extends Target { const extensions = await this.getExtensions(executable, displayName) const archSpecificMinVersion = arch === Arch.arm64 ? "10.0.16299.0" : "10.0.14316.0" - const manifest = (await readFile(path.join(getTemplatePath("appx"), "appxmanifest.xml"), "utf8")).replace(/\${([a-zA-Z0-9]+)}/g, (match, p1): string => { + const customManifestPath = await this.packager.getResource(this.options.customManifestPath) + if (customManifestPath) { + log.info({ manifestPath: log.filePath(customManifestPath) }, "custom appx manifest found") + } + const manifestFileContent = await readFile(customManifestPath || path.join(getTemplatePath("appx"), "appxmanifest.xml"), "utf8") + const manifest = manifestFileContent.replace(/\${([a-zA-Z0-9]+)}/g, (match, p1): string => { switch (p1) { case "publisher": return publisher diff --git a/test/fixtures/test-app-one/build/custom-manifest.xml b/test/fixtures/test-app-one/build/custom-manifest.xml new file mode 100644 index 00000000000..e33119189e6 --- /dev/null +++ b/test/fixtures/test-app-one/build/custom-manifest.xml @@ -0,0 +1,47 @@ + + + + + + + ${displayName} + ${publisherDisplayName} + ${description} + ${logo} + + + ${resourceLanguages} + + + + + + + + + + + + + ${lockScreen} + ${defaultTile} + ${splashScreen} + + ${extensions} + + + diff --git a/test/fixtures/test-app-one/build/custom-template-manifest.xml b/test/fixtures/test-app-one/build/custom-template-manifest.xml new file mode 100644 index 00000000000..e091be2da49 --- /dev/null +++ b/test/fixtures/test-app-one/build/custom-template-manifest.xml @@ -0,0 +1,50 @@ + + + + + + + ${displayName} + ${publisherDisplayName} + ${description} + ${logo} + + + ${resourceLanguages} + + + + + + + + + + + ${lockScreen} + ${defaultTile} + ${splashScreen} + + + + + diff --git a/test/snapshots/windows/appxTest.js.snap b/test/snapshots/windows/appxTest.js.snap index bb8a6e09a8a..3745feff081 100644 --- a/test/snapshots/windows/appxTest.js.snap +++ b/test/snapshots/windows/appxTest.js.snap @@ -48,6 +48,135 @@ exports[`certificateSubjectName 1`] = ` } `; +exports[`custom raw appmanifest.xml 1`] = ` +" + + + + + + Test App ßW + Foo Bar + Test Application (test quite “ #378) + assets\\StoreLogo.png + + + + + + + + + + + + + + + + + + + + + + + +" +`; + +exports[`custom raw appmanifest.xml 2`] = ` +{ + "win": [ + { + "arch": "x64", + "file": "Test App ßW 1.1.0.appx", + "safeArtifactName": "TestApp-1.1.0.appx", + }, + ], +} +`; + +exports[`custom template appmanifest.xml 1`] = ` +" + + + + + + Test App ßW + Foo Bar + Test Application (test quite “ #378) + assets\\StoreLogo.png + + + + + + + + + + + + + + + + + + + + + +" +`; + +exports[`custom template appmanifest.xml 2`] = ` +{ + "win": [ + { + "arch": "x64", + "file": "Test App ßW 1.1.0.appx", + "safeArtifactName": "TestApp-1.1.0.appx", + }, + ], +} +`; + exports[`languages and not signed (windows store only) 1`] = ` { "win": [ diff --git a/test/src/windows/appxTest.ts b/test/src/windows/appxTest.ts index 591224af0d2..882d4c2a183 100644 --- a/test/src/windows/appxTest.ts +++ b/test/src/windows/appxTest.ts @@ -3,6 +3,7 @@ import { app, copyTestAsset } from "../helpers/packTester" import * as path from "path" import { mkdir } from "fs/promises" import { isEnvTrue } from "builder-util" +import { readFile } from "fs-extra" // test that we can get info from protected pfx const protectedCscLink = @@ -101,3 +102,35 @@ it( }, }) ) + +it( + "custom template appmanifest.xml", + app({ + targets: Platform.WINDOWS.createTarget(["appx"], Arch.x64), + config: { + appx: { + customManifestPath: "custom-template-manifest.xml", + }, + appxManifestCreated: async filepath => { + const fileContent = await readFile(filepath, "utf-8") + expect(fileContent).toMatchSnapshot() + }, + }, + }) +) + +it( + "custom raw appmanifest.xml", + app({ + targets: Platform.WINDOWS.createTarget(["appx"], Arch.x64), + config: { + appx: { + customManifestPath: "custom-manifest.xml", + }, + appxManifestCreated: async filepath => { + const fileContent = await readFile(filepath, "utf-8") + expect(fileContent).toMatchSnapshot() + }, + }, + }) +)