From 8bf0ca4ef5111eff469b4e34851768031b26fa83 Mon Sep 17 00:00:00 2001 From: Wails Documentation Agent Date: Fri, 24 Apr 2026 23:11:27 +1000 Subject: [PATCH] fix(darwin): sanitize CFBundleIdentifier to comply with Apple requirements CFBundleIdentifier was generated as com.wails.{{.Name}} which could contain spaces and special characters, violating Apple's requirement that bundle identifiers only contain [A-Za-z0-9.-]. Add a safeBundleID template function that lowercases and replaces non-alphanumeric runs with hyphens, then strips leading/trailing dashes. Applied to both Info.plist and Info.dev.plist templates. Fixes #4866 --- .../buildassets/build/darwin/Info.dev.plist | 2 +- v2/pkg/buildassets/build/darwin/Info.plist | 2 +- v2/pkg/buildassets/buildassets.go | 22 ++++++++++++++- v2/pkg/buildassets/safebundleid_test.go | 27 +++++++++++++++++++ 4 files changed, 50 insertions(+), 3 deletions(-) create mode 100644 v2/pkg/buildassets/safebundleid_test.go diff --git a/v2/pkg/buildassets/build/darwin/Info.dev.plist b/v2/pkg/buildassets/build/darwin/Info.dev.plist index 14121ef7c1e..c20334b9321 100644 --- a/v2/pkg/buildassets/build/darwin/Info.dev.plist +++ b/v2/pkg/buildassets/build/darwin/Info.dev.plist @@ -8,7 +8,7 @@ CFBundleExecutable {{.OutputFilename}} CFBundleIdentifier - com.wails.{{.Name}} + com.wails.{{safeBundleID .Name}} CFBundleVersion {{.Info.ProductVersion}} CFBundleGetInfoString diff --git a/v2/pkg/buildassets/build/darwin/Info.plist b/v2/pkg/buildassets/build/darwin/Info.plist index d17a7475c58..4de28875c5b 100644 --- a/v2/pkg/buildassets/build/darwin/Info.plist +++ b/v2/pkg/buildassets/build/darwin/Info.plist @@ -8,7 +8,7 @@ CFBundleExecutable {{.OutputFilename}} CFBundleIdentifier - com.wails.{{.Name}} + com.wails.{{safeBundleID .Name}} CFBundleVersion {{.Info.ProductVersion}} CFBundleGetInfoString diff --git a/v2/pkg/buildassets/buildassets.go b/v2/pkg/buildassets/buildassets.go index 6934b98bd00..b9d53498a04 100644 --- a/v2/pkg/buildassets/buildassets.go +++ b/v2/pkg/buildassets/buildassets.go @@ -8,6 +8,8 @@ import ( iofs "io/fs" "os" "path/filepath" + "regexp" + "strings" "text/template" "github.com/leaanthony/gosod" @@ -107,8 +109,26 @@ type assetData struct { OutputFilename string } +func xmlEscape(s string) string { + var buf bytes.Buffer + template.HTMLEscape(&buf, []byte(s)) + return buf.String() +} + +var nonAlphaNum = regexp.MustCompile(`[^A-Za-z0-9]+`) + +func safeBundleID(s string) string { + result := strings.ToLower(nonAlphaNum.ReplaceAllString(s, "-")) + result = strings.Trim(result, "-") + return result +} + func resolveProjectData(content []byte, projectData *project.Project) ([]byte, error) { - tmpl, err := template.New("").Parse(string(content)) + funcMap := template.FuncMap{ + "xml": xmlEscape, + "safeBundleID": safeBundleID, + } + tmpl, err := template.New("").Funcs(funcMap).Parse(string(content)) if err != nil { return nil, err } diff --git a/v2/pkg/buildassets/safebundleid_test.go b/v2/pkg/buildassets/safebundleid_test.go new file mode 100644 index 00000000000..9a65dcec534 --- /dev/null +++ b/v2/pkg/buildassets/safebundleid_test.go @@ -0,0 +1,27 @@ +package buildassets + +import ( + "testing" +) + +func TestSafeBundleID(t *testing.T) { + tests := []struct { + input string + expected string + }{ + {"My Fab Application", "my-fab-application"}, + {"SimpleApp", "simpleapp"}, + {"App-With-Dashes", "app-with-dashes"}, + {"App_With_Underscores", "app-with-underscores"}, + {"App@#$%^&*()", "app"}, + {"123App", "123app"}, + {" Spaces ", "spaces"}, + {"already-lowercase", "already-lowercase"}, + } + for _, tt := range tests { + got := safeBundleID(tt.input) + if got != tt.expected { + t.Errorf("safeBundleID(%q) = %q, want %q", tt.input, got, tt.expected) + } + } +}