Skip to content

Commit

Permalink
feat: support completely custom AppxManifest.xml (#8609)
Browse files Browse the repository at this point in the history
  • Loading branch information
iongion authored Dec 27, 2024
1 parent 1d0feb9 commit d672b04
Show file tree
Hide file tree
Showing 9 changed files with 303 additions and 2 deletions.
5 changes: 5 additions & 0 deletions .changeset/brown-pears-beg.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"app-builder-lib": minor
---

feat: support completely custom AppxManifest.xml
2 changes: 1 addition & 1 deletion .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,4 @@
}
}
]
}
}
4 changes: 4 additions & 0 deletions packages/app-builder-lib/scheme.json
Original file line number Diff line number Diff line change
Expand Up @@ -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": [
Expand Down
27 changes: 27 additions & 0 deletions packages/app-builder-lib/src/options/AppXOptions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
8 changes: 7 additions & 1 deletion packages/app-builder-lib/src/targets/AppxTarget.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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"`])
Expand Down Expand Up @@ -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
Expand Down
47 changes: 47 additions & 0 deletions test/fixtures/test-app-one/build/custom-manifest.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
<?xml version="1.0" encoding="utf-8"?>
<!--suppress XmlUnusedNamespaceDeclaration -->
<Package
xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10"
xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10"
xmlns:desktop="http://schemas.microsoft.com/appx/manifest/desktop/windows10"
xmlns:desktop2="http://schemas.microsoft.com/appx/manifest/desktop/windows10/2"
xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities"
>
<!-- use single quotes to avoid double quotes escaping in the publisher value -->
<Identity Name="${identityName}"
ProcessorArchitecture="${arch}"
Publisher='${publisher}'
Version="${version}" />
<Properties>
<DisplayName>${displayName}</DisplayName>
<PublisherDisplayName>${publisherDisplayName}</PublisherDisplayName>
<Description>${description}</Description>
<Logo>${logo}</Logo>
</Properties>
<Resources>
${resourceLanguages}
</Resources>
<Dependencies>
<TargetDeviceFamily Name="Windows.Desktop" MinVersion="${minVersion}" MaxVersionTested="${maxVersionTested}" />
</Dependencies>
<Capabilities>
<Capability Name="internetClient"/>
<Capability Name="privateNetworkClientServer"/>
<rescap:Capability Name="runFullTrust"/>
</Capabilities>
<Applications>
<Application Id="${applicationId}" Executable="${executable}" EntryPoint="Windows.FullTrustApplication">
<uap:VisualElements
BackgroundColor="${backgroundColor}"
DisplayName="${displayName}"
Square150x150Logo="${square150x150Logo}"
Square44x44Logo="${square44x44Logo}"
Description="${description}">
${lockScreen}
${defaultTile}
${splashScreen}
</uap:VisualElements>
${extensions}
</Application>
</Applications>
</Package>
50 changes: 50 additions & 0 deletions test/fixtures/test-app-one/build/custom-template-manifest.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<?xml version="1.0" encoding="utf-8"?>
<!--suppress XmlUnusedNamespaceDeclaration -->
<Package
xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10"
xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10"
xmlns:desktop="http://schemas.microsoft.com/appx/manifest/desktop/windows10"
xmlns:desktop2="http://schemas.microsoft.com/appx/manifest/desktop/windows10/2"
xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities">
<!-- use single quotes to avoid double quotes escaping in the publisher value -->
<Identity Name="${identityName}"
ProcessorArchitecture="${arch}"
Publisher='${publisher}'
Version="${version}" />
<Properties>
<DisplayName>${displayName}</DisplayName>
<PublisherDisplayName>${publisherDisplayName}</PublisherDisplayName>
<Description>${description}</Description>
<Logo>${logo}</Logo>
</Properties>
<Resources>
${resourceLanguages}
</Resources>
<Dependencies>
<TargetDeviceFamily Name="Windows.Desktop" MinVersion="${minVersion}" MaxVersionTested="${maxVersionTested}" />
</Dependencies>
<Capabilities>
<rescap:Capability Name="runFullTrust"/>
</Capabilities>
<Applications>
<Application Id="${applicationId}" Executable="${executable}" EntryPoint="Windows.FullTrustApplication">
<uap:VisualElements
BackgroundColor="${backgroundColor}"
DisplayName="${displayName}"
Square150x150Logo="${square150x150Logo}"
Square44x44Logo="${square44x44Logo}"
Description="${description}">
${lockScreen}
${defaultTile}
${splashScreen}
</uap:VisualElements>
<!-- <Extensions>
<desktop2:Extension Category="windows.firewallRules">
<desktop2:FirewallRules Executable="${executable}">
<desktop2:Rule Direction="in" Profile="private" IPProtocol="TCP" LocalPortMin="22022" LocalPortMax="24044"/>
</desktop2:FirewallRules>
</desktop2:Extension>
</Extensions> -->
</Application>
</Applications>
</Package>
129 changes: 129 additions & 0 deletions test/snapshots/windows/appxTest.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,135 @@ exports[`certificateSubjectName 1`] = `
}
`;

exports[`custom raw appmanifest.xml 1`] = `
"<?xml version="1.0" encoding="utf-8"?>
<!--suppress XmlUnusedNamespaceDeclaration -->
<Package
xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10"
xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10"
xmlns:desktop="http://schemas.microsoft.com/appx/manifest/desktop/windows10"
xmlns:desktop2="http://schemas.microsoft.com/appx/manifest/desktop/windows10/2"
xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities"
>
<!-- use single quotes to avoid double quotes escaping in the publisher value -->
<Identity Name="TestApp"
ProcessorArchitecture="x64"
Publisher='CN=ms'
Version="1.1.0.0" />
<Properties>
<DisplayName>Test App ßW</DisplayName>
<PublisherDisplayName>Foo Bar</PublisherDisplayName>
<Description>Test Application (test quite “ #378)</Description>
<Logo>assets\\StoreLogo.png</Logo>
</Properties>
<Resources>
<Resource Language="en-US" />
</Resources>
<Dependencies>
<TargetDeviceFamily Name="Windows.Desktop" MinVersion="10.0.14316.0" MaxVersionTested="10.0.14316.0" />
</Dependencies>
<Capabilities>
<Capability Name="internetClient"/>
<Capability Name="privateNetworkClientServer"/>
<rescap:Capability Name="runFullTrust"/>
</Capabilities>
<Applications>
<Application Id="TestApp" Executable="app\\Test App ßW.exe" EntryPoint="Windows.FullTrustApplication">
<uap:VisualElements
BackgroundColor="#464646"
DisplayName="Test App ßW"
Square150x150Logo="assets\\Square150x150Logo.png"
Square44x44Logo="assets\\Square44x44Logo.png"
Description="Test Application (test quite “ #378)">
<uap:DefaultTile Wide310x150Logo="assets\\Wide310x150Logo.png" />
</uap:VisualElements>
</Application>
</Applications>
</Package>
"
`;

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`] = `
"<?xml version="1.0" encoding="utf-8"?>
<!--suppress XmlUnusedNamespaceDeclaration -->
<Package
xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10"
xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10"
xmlns:desktop="http://schemas.microsoft.com/appx/manifest/desktop/windows10"
xmlns:desktop2="http://schemas.microsoft.com/appx/manifest/desktop/windows10/2"
xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities">
<!-- use single quotes to avoid double quotes escaping in the publisher value -->
<Identity Name="TestApp"
ProcessorArchitecture="x64"
Publisher='CN=ms'
Version="1.1.0.0" />
<Properties>
<DisplayName>Test App ßW</DisplayName>
<PublisherDisplayName>Foo Bar</PublisherDisplayName>
<Description>Test Application (test quite “ #378)</Description>
<Logo>assets\\StoreLogo.png</Logo>
</Properties>
<Resources>
<Resource Language="en-US" />
</Resources>
<Dependencies>
<TargetDeviceFamily Name="Windows.Desktop" MinVersion="10.0.14316.0" MaxVersionTested="10.0.14316.0" />
</Dependencies>
<Capabilities>
<rescap:Capability Name="runFullTrust"/>
</Capabilities>
<Applications>
<Application Id="TestApp" Executable="app\\Test App ßW.exe" EntryPoint="Windows.FullTrustApplication">
<uap:VisualElements
BackgroundColor="#464646"
DisplayName="Test App ßW"
Square150x150Logo="assets\\Square150x150Logo.png"
Square44x44Logo="assets\\Square44x44Logo.png"
Description="Test Application (test quite “ #378)">
<uap:DefaultTile Wide310x150Logo="assets\\Wide310x150Logo.png" />
</uap:VisualElements>
<!-- <Extensions>
<desktop2:Extension Category="windows.firewallRules">
<desktop2:FirewallRules Executable="app\\Test App ßW.exe">
<desktop2:Rule Direction="in" Profile="private" IPProtocol="TCP" LocalPortMin="22022" LocalPortMax="24044"/>
</desktop2:FirewallRules>
</desktop2:Extension>
</Extensions> -->
</Application>
</Applications>
</Package>
"
`;

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": [
Expand Down
33 changes: 33 additions & 0 deletions test/src/windows/appxTest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 =
Expand Down Expand Up @@ -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()
},
},
})
)

0 comments on commit d672b04

Please sign in to comment.