Dev

Shipping a macOS App to the Mac App Store (3): Upload Settings and App Store Connect Registration

The Path That Sends a Build to the App Store In Part 1 we created the MAS build target, and in Part 2 we created the configuration files and code branching that separate the two channels. The FocusTimer MAS target is now in a shape that can be put on the App Store. In this final part, we’ll set up the path for uploading that build to App Store Connect, and cover how to verify the two channels so they stay unbroken going forward, wrapping up the series. ...

May 19, 2026 · 5 min · 1028 words · Juhyun Lee
한국어 日本語 简体中文 Bahasa Indonesia Español Français Português Tiếng Việt 繁體中文
Dev

Shipping a macOS App to the Mac App Store (2): Splitting Configuration and Code Between Channels

Making the Target Truly “MAS-Specific” In Part 1, we registered a MAS-only Bundle ID and duplicated the FocusTimer MAS build target. But that target is still just a copy of the direct distribution target. A MAS build has to differ from the direct distribution build in three ways. Entitlements — only the minimum set appropriate for the App Store Info.plist — drop the Sparkle keys, add App Store metadata Code — branch so it compiles even without Sparkle In this post, we’ll split all three. ...

May 18, 2026 · 7 min · 1297 words · Juhyun Lee
한국어 日本語 简体中文 Bahasa Indonesia Español Français Português Tiếng Việt 繁體中文
Dev

Shipping a macOS App to the Mac App Store (1): Creating a Separate Build Target

Another Distribution Channel — the Mac App Store The previous series covered the one-time setup for distributing a macOS app directly with a Developer ID. Once you have certificates, notarization, Sparkle automatic updates, and a hosted update feed in place, you can let users download a .dmg file directly without going through the App Store. This series covers the one-time setup for putting that same app on the Mac App Store (MAS) as well. The two distribution methods are not an either/or choice. You can run a single app through both the direct distribution channel and the App Store channel at the same time. The App Store has Apple handle payments, refunds, and search visibility on your behalf, and it carries higher user trust, so running it alongside direct distribution is a common choice. ...

May 17, 2026 · 7 min · 1430 words · Juhyun Lee
한국어 日本語 简体中文 Bahasa Indonesia Español Français Português Tiếng Việt 繁體中文
Dev

Distributing a macOS App Yourself (3): Hosting the Update Feed and Build Settings

The Last Piece — Where to Put the Updates In Part 1 we prepared the Developer ID certificate and notarization, and in Part 2 we prepared the Sparkle signing key. That means we now have a way to sign the app, notarize it, and verify the authenticity of updates. But the location pointed to by SUFeedURL (https://updates.example.com/appcast.xml), which we wrote into the app’s Info.plist in Part 2, still has nothing in it. In this final part, we’ll host the update feed that goes in that spot and finish the build settings, completing the entire one-time setup. ...

May 16, 2026 · 7 min · 1457 words · Juhyun Lee
한국어 日本語 简体中文 Bahasa Indonesia Español Français Português Tiếng Việt 繁體中文
Dev

Distributing a macOS App Yourself (2): Creating the Sparkle Auto-Update Signing Key

Automatic Updates, and Why You Need One More Layer of Signing In Part 1, we finished setting up the Developer ID certificate and notarization. With that, you’re ready to deliver the app to users for the first time. But an app isn’t done after a single release — you have to keep shipping new versions that fix bugs and add features. For a Mac App Store app, the App Store handles updates for you. A directly distributed app doesn’t get that, so you have to build an automatic-update feature into the app yourself. On macOS, the de facto standard for this role is the open-source framework Sparkle. With Sparkle in place, the app periodically checks an “update feed (appcast),” and if a new version exists, it notifies the user, downloads it, and installs it. ...

May 15, 2026 · 7 min · 1372 words · Juhyun Lee
한국어 日本語 简体中文 Bahasa Indonesia Español Français Português Tiếng Việt 繁體中文