channel: master
version: 1.2.0
source-ref: D:\code\open_source\ant-chrome master
source-commit: f3d7ec5
merged-public-base: 3d264eb
macOS Publish Plan
Purpose
This document defines the macOS packaging plan for Ant Browser.
The goal is to turn the current codebase into a macOS build that can:
- build on a native macOS machine
- launch from
/Applications - keep user-writable state outside the
.appbundle - bundle required proxy runtime binaries
- avoid breaking existing Windows and Linux packaging flows
Current Entry Command
The initial internal-build script can be invoked on a real Mac with:
bash publish/mac/publish-mac.sh --arch arm64
For the first iteration, arm64 is the recommended target.
If no physical Mac is available, use the manual GitHub Actions workflow:
Actions -> Publish macOS Package -> Run workflow
The workflow builds the same arm64 internal package on a macOS runner and uploads the generated files from publish/output/ as an artifact. The optional version input overrides the package version for that run.
This is a plan document only. It does not mean macOS packaging is already implemented.
Current Status
The repository already has:
- Windows packaging flow
- Linux packaging flow
- partial Darwin runtime compatibility in backend code
- initial
publish/mac/publish-mac.shscaffold for internal test builds - initial
publish/config.init.mac.yamltemplate - committed Darwin runtime binaries under
bin/darwin-amd64/andbin/darwin-arm64/ - Darwin runtime entries in
publish/runtime-manifest.json - Darwin runtime source lock entries in
publish/runtime-sources.json
The repository does not yet have:
- signing / notarization flow
The repository now includes the first macOS writable-state implementation for app bundle roots:
- when the app root is inside
.app/Contents/MacOSor.app/Contents/Resources - writable state is redirected to
~/Library/Application Support/ant-browser bin/stays in the app bundle- config, chrome, and data move to the user state root
Current Implementation Note
The current initial macOS packaging scaffold intentionally places helper binaries and seed files under:
Ant Browser.app/Contents/MacOS/binAnt Browser.app/Contents/MacOS/config.yamlAnt Browser.app/Contents/MacOS/chrome/README.md
This is not the prettiest final bundle layout, but it matches the current runtime path resolution and avoids a larger refactor in Phase 1.
After the first internal build is stable, the bundle layout can be reviewed and moved toward Contents/Resources if needed.
Why macOS Looks More Complex
macOS is not difficult because of Wails alone. The real complexity comes from four areas:
- Installed
.appbundles under/Applicationsshould be treated as read-only. - User data must not be written inside the
.appbundle. - External helper binaries such as
xrayandsing-boxmust exist for Darwin and must be bundled correctly. - Public distribution usually requires code signing and notarization, otherwise Gatekeeper may block launch.
Recommended Scope
Phase 1: Internal Test Build
Target:
darwin/arm64first- output
.appand.zip - unsigned build is acceptable for internal testing
Why:
- Apple Silicon is the mainstream macOS target now
- it keeps the first version smaller and easier to verify
- it avoids spending time on Intel support before the runtime path is stable
Phase 2: Public Distribution Build
Target:
- signed
.app - notarized
.zipor.dmg - optional
darwin/amd64or universal build
Why:
- end users expect double-click install and normal launch
- unsigned apps and embedded helper binaries are more likely to be blocked
Recommended Runtime Layout
App Bundle
Recommended structure inside the built app:
Ant Browser.app/Contents/MacOS/ant-chromeAnt Browser.app/Contents/Resources/bin/xrayAnt Browser.app/Contents/Resources/bin/sing-box- optional placeholder
chrome/README.mdif you want to keep behavior aligned with Linux
User-Writable State
Recommended macOS state root:
~/Library/Application Support/ant-browser
Recommended contents under the state root:
config.yamlproxies.yamldata/chrome/
Rule:
- runtime binaries stay in the app bundle
- config, database, browser cores, logs, and profile data stay in the user state root
Code Changes Required
1. Add macOS Writable State Handling
Current Linux detached-state logic only activates on Linux:
backend/internal/apppath/apppath.go
Required change:
- extend path detection so installed macOS apps also use a detached writable state root
- recommended trigger: when
GOOS=darwinand app root is not writable, or when running from an.appbundle
Expected result:
- app launch from
/Applicationsdoes not try to write config/data into the bundle
2. Add Darwin Runtime Binaries
Current runtime manifest has Windows and Linux only:
publish/runtime-manifest.json
Required additions:
bin/darwin-arm64/xraybin/darwin-arm64/sing-box- optional
bin/darwin-amd64/xray - optional
bin/darwin-amd64/sing-box - manifest hash entries for the new targets
Status:
- implemented for both
darwin-arm64anddarwin-amd64 - files are committed into the repository
- runtime manifest verification now works for both Darwin targets
Related scripts to extend:
tools/runtime/sync-runtime.pytools/runtime/update-runtime-manifest.pytools/runtime/verify-runtime.sh
3. Add macOS Publish Script
New file to add:
publish/mac/publish-mac.sh
Recommended responsibilities:
- verify host is macOS
- verify target arch (
arm64first) - install frontend dependencies
- build frontend
- run
wails build -platform darwin/arm64 - place runtime binaries into the app bundle
- optionally archive to
.zip - optionally sign and notarize when environment variables are provided
Current scaffold status:
- implemented as an unsigned internal-build script
- outputs
.appplus.zip - requires a native macOS host
- intentionally does not attempt notarization yet
4. Add macOS Runtime Placement Logic
The app currently resolves most paths through shared runtime helpers, which is good.
Files likely involved:
backend/app.gobackend/app_paths.gobackend/app_utils.gobackend/internal/browser/types.gobackend/internal/proxy/xray.gobackend/internal/proxy/singbox.gomain.go
Goal:
- all writable files go to the user state root
- helper binaries continue to resolve from the app bundle
5. Signing and Notarization
This is not required for a first internal test build, but is required for a serious public release.
Needed later:
- Apple Developer certificate
codesignnotarytool- entitlements if runtime behavior requires them
Typical flow:
- sign helper binaries
- sign the
.app - zip or build dmg
- notarize
- staple
Recommended Implementation Order
- Deliver
darwin/arm64internal test build only. - Add macOS detached state root.
- Add Darwin runtime binaries and manifest support.
- Add
publish/mac/publish-mac.sh. - Verify launch from
/Applications. - Verify browser core placement under user state root.
- Verify proxy runtime launch on macOS.
- Add signing and notarization only after the unsigned build is stable.
- Decide whether
darwin/amd64is worth supporting.
Validation Checklist
The macOS work should not be considered complete until all items below are verified on a real Mac.
Packaging
- build completes on native macOS
- output
.appexists - output
.zipor.dmgexists - bundled helper binaries are executable
First Launch
- app launches from Finder
- app launches after copying to
/Applications - first launch creates
~/Library/Application Support/ant-browser config.yamlis seeded correctly- database and
data/are created under the user state root
Browser Core
- manually placed browser core can be detected
- browser core path persists in config or database
- browser instance can actually start
Proxy Runtime
xraycan be launched from the app bundlesing-boxcan be launched from the app bundle- work directories are created under the user state root
Exit Behavior
- window close works
- explicit quit works
- no stuck background process remains after quit
Regression Safety
- Windows packaging still builds
- Linux packaging still builds
- Linux detached state behavior still works
Difficulty Assessment
Internal Test Build
Difficulty: medium
Main blockers:
- mac runtime binaries
- detached writable state
- mac packaging script
Public Release Build
Difficulty: medium-high
Main blockers:
- signing
- notarization
- quarantine / Gatekeeper behavior
- helper binary signing order
Suggested First Deliverable
The safest first milestone is:
- macOS
arm64 - native build on a real Mac
- unsigned
.app - zipped artifact for internal testing
- detached writable state under
~/Library/Application Support/ant-browser - bundled
xrayandsing-box
Do not start with:
- universal binary
- dmg beautification
- public distribution
- Intel support
Those can come after the app is proven stable on one Mac target first.
Files Expected To Be Added Or Updated
Likely new files:
publish/mac/publish-mac.shpublish/mac/README.md
Likely updated files:
backend/internal/apppath/apppath.gobackend/internal/apppath/apppath_test.gobackend/runtime_paths.gobackend/app.gomain.gopublish/runtime-manifest.jsonpublish/runtime-sources.jsontools/runtime/sync-runtime.pytools/runtime/update-runtime-manifest.pytools/runtime/verify-runtime.sh
Decision Record
Current recommendation:
- do macOS
arm64first - solve writable state before touching signing
- keep Windows and Linux publish flows unchanged unless shared runtime code needs extension
- treat public notarized distribution as Phase 2, not Phase 1