Home iOS & Swift Books Catalyst by Tutorials

Third-Party Distribution Written by Marin Bencevic

If you’re reading this chapter, you’re probably considering taking destiny into your own hands and releasing your app without the App Store.

It’s dangerous to walk that road alone! Take this chapter as a guide. It will talk you through preparing your app so anyone can download it and install it. You’ll learn how to notarize your app, how to create a DMG file for your app and also some tips on surviving the harsh world of 3rd party macOS app distribution.

Note: In case you’re wondering, push notifications and CloudKit will still work, even if you’re not distributing your apps on the App Store.

Before you get started with distributing apps, you’ll need an Apple ID enrolled in the Apple Developer Program. Yes, even though you’re not using the App Store, you still need a developer account.

The process of distributing apps is complicated by an annoying but useful macOS feature called Gatekeeper. Gatekeeper constantly checks the apps you’re running, making sure there’s nothing shady inside of them. Have you ever launched an app only to be surprised by an alert telling you the app is from an unidentified developer? That’s Gatekeeper.

You’ve probably noticed not all apps cause this alert to pop up. It usually happens with less-popular or non-native apps. The ones that don’t pop up the alert are properly signed and notarized. In the next section, you’ll do that for your app to make sure Gatekeeper lets your users run it.

Signed, notarized and delivered

Note: To learn more about what code signing is and how it works, take a look at Chapter 13, “Releasing on the App Store”.

For other people to run your app, you’ll need to sign it with a Developer ID certificate. That’s a special kind of certificate that lets you distribute your app outside the App Store. Only the Account Holder of your Apple Developer account can create this certificate.

If you have a personal Apple Developer account, you’re already the Account Holder. If you’re in a team, check your role by going to App Store Connect’s Users and Access section: apple.co/2Da59iB. If you see yourself in the Account Holder tab, you’re good.

If you’re not the Account Holder, you’ll have to ask the Account Holder to export a macOS Developer ID Application certificate for you. They can do that from Xcode. Apple provides easy-to-follow instructions on how to export certificates: apple.co/2mj29Mh.

Signing, however, is not enough. You also need to notarize the app. Notarization is a process where you send your app to Apple and let them perform automatic checks on it to make sure it’s not doing anything malicious. Once Apple confirms the app is okay, they give your app a ticket. This ticket tells Gatekeeper to relax when a user opens your app, because Apple checked it.

Think of notarization as an airport security check: Your app needs to go through TSA before it can fly across the world to your users’ Macs.

In the last chapter, I mentioned code signing guarantees you made your app and haven’t changed it since you signed it. The latter part is important for notarization: Whenever your app changes, you need to renotarize the app’s binary.

Keep in mind that notarization is an automatic process that usually takes a couple of minutes. It’s much more relaxed than App Review and you should expect your app to go through notarization without any issues unless you’re doing something very suspicious.

Apple made notarization easy; you can do everything in Xcode. Open your app in Xcode.

The first thing you need to do is make an archive of your app. Before you do that, make sure your project compiles without any errors. Then, in the menu bar go to Product ▸ Destination and make sure you’ve selected My Mac. Click Product ▸ Archive. This compiles your app and creates an executable that you can notarize. Depending on the size of your app, this process might take a few minutes — you can think of a cool website domain while you wait. :]

Once it’s finished archiving, Xcode will open the Organizer. In the sidebar, you should see your app under macOS Apps. If you just created an archive, your app should be selected, but you can come back here later and select the app and all your archives will be listed.

Now that you have an archive, the next steps are signing and notarization. Xcode automatically does this in one fell swoop.

Note: To notarize your app, you need to have Hardened Runtime enabled. The Hardened Runtime locks down the app and protects your users from exploits. It’s enabled by default for Catalyst apps, so unless you disabled it manually, you should be fine. You can see it in Xcode in the Signing & Capabilities tab of your app target’s settings.

Click Distribute App. In the screen that pops up, select Developer ID and click Next. Select Upload and click Next. In the next screen, select Automatically manage signing.

Note: At this point, Xcode might show an error saying that you either don’t have a Developer ID certificate or you don’t have its private key. If that’s the case, contact your Account Holder and make sure they export a new Developer ID Application certificate by following Apple’s instructions: apple.co/2mj29Mh.

Once signed, you’ll get a summary.

Click Upload and Xcode will start uploading the archive to the notary service.

Now you wait. If you’ve decided on your domain, maybe you can brainstorm some website design ideas at this point. :]

You can check your app’s status in the Organizer. If you closed the window, you can open it by selecting Window ▸ Organizer. You’ll see the status under the Status column. You can also click on Show Status Log to see what’s been going on.

Once notarization completes, it will change to Ready to distribute. If something goes wrong, the status will change to Rejected. In that case, you can click on Show Status Log to see why the notarization service rejected your app.

Now that you have a notarized app, you can export the binary you’ll share with your users. Click Export Notarized App from the right sidebar. Select a location on disk and you’ll have your app!

While you could distribute this app as it is, most developers choose to distribute their apps as compressed disk images, aka DMG files. In the next section, you’ll see how and why you’d do that.

Creating a DMG file

If you’ve ever downloaded a macOS app, chances are it came in a .dmg file, which is short for Disk Image. When you double-click a .dmg file, it mounts a new disk that contains the app and sometimes additional files like a read-me document.

Packaging your apps in .dmg files has several advantages:

  • It lets the user easily install the app by dragging and dropping it to Applications.
  • Since apps (.app files) are something between a file and a folder, packing them up into a .dmg makes sure they appear as a single file to web browsers.
  • You can password-protect .dmg files.
  • .dmg files can contain additional files like read-me documents, licensing information etc.

.dmg files often contain an alias to the user’s Applications folder. This lets users easily drag your app right into Applications without having to look for the folder. Apple heavily recommends that you instruct users to move your app to Applications. Running the app straight from the DMG might lead to unexpected behavior and could compromise the user’s security.

Disk images often include a custom background image to instruct the user to drag and drop the app. In this section, you’ll make your very own disk image with an alias to the Applications folder, as well as a custom image.

To make a new disk image, open up Disk Utility. Click File ▸ New Image ▸ Blank Image…. Enter a file name and fill out the Name text field. Usually, these two values are the same. Next, for the Size, enter a size that is slightly larger than your app. You’ll trim the extra size later. You can leave the default values for the other settings and click Save.

If you go into Finder, you’ll see that your new disk image has been mounted. Click on your disk image in the sidebar.

Any Finder settings that you change for this disk image will get saved and loaded when users mount your disk image. This includes things like the size of the window, which Finder views and tabs the app shows and other view options. This is all saved on the disk image in a hidden file called .DS_Store.

Cleaning up your window

First, let’s clean up the window. Press Command-1 to view the disk image as a grid of icons. Then, in the View menu, hide everything that isn’t already hidden by clicking Hide Toolbar, Hide Path Bar and Hide Status Bar. You should see a completely blank window.

Note: Depending on your Finder defaults, some of these may already be hidden. Just make sure all the bars are hidden and your window looks like the screenshot.

The next step is to add a custom background image. Press Command-Shift-. to show hidden files. Create a new folder in the disk image named .background. If a dialog pops up saying the folder will be invisible, click OK — an invisible folder is exactly what you need.

If you don’t have a background image, you can find one in this chapter’s materials. In a new Finder window, navigate to the starter folder of this chapter’s materials. Copy over background.png to the newly-created .background folder.

Next, click View ▸ Show View Options. Make sure you’ve checked Always open in icon view. Set the Icon size to 80×80 and slide the Grid spacing slider all the way to the right. For Background, select Picture and, from a new Finder window, drag over background.png from the .background folder. While dragging, make sure the disk image is the currently active window.

Close the view options window and resize the disk image window so you can’t see the edges of the background picture. Press Command-Shift-. again to hide the files.

Adding your app

Now that the window looks nice, it’s time to add your app and an alias to Applications. From a different Finder window, copy your exported app to the disk image and position it in the left box.

Next, navigate to the root directory of your macOS disk. You can do this from Terminal by typing open /. Right-click on Applications and click on Make Alias. This creates a new folder that acts as a pointer to Applications. Copy the alias to the disk image and position the icon inside the box on the right.

Hey, that’s a nice looking .dmg you made! Since you worked hard on setting everything up perfectly, you wouldn’t want those pesky users changing things. That’s why the next step is to make the image read-only.

Go back into Disk Utility and eject your disk image by clicking the little eject button next to the image in the sidebar. Then, in the menu bar, click Images ▸ Convert… and select the image you just set up. Name the file anything you like — you can change this later. For the Image Format, select read-only and click Convert. This makes sure nobody can change the image and also trims all the excess space.

You now have a DMG that you can share with your customers! But unfortunately they won’t get far with this DMG. Your users won’t be able to run unsigned software. If you’re thinking, “I just signed my app!” — you’re right. But, the .dmg file is also a piece of software and needs to be signed and notarized just like your app.

Notarizing disk images

You can sign and notarize a .dmg file pretty quickly, just by using the command line. You’ll begin by signing the .dmg file.

Before you start, open Keychain Access and, in the top-right corner, search for “developer id”. You should see a certificate named “Developer ID Application: Team Name (ID)”. Click on the certificate and copy the whole name in bold at the top of the window, including the team ID.

Now, open Terminal and use cd to navigate to the folder where you saved your converted disk image. Enter the following command to sign the disk image:

codesign \
  -s "Developer ID Application: Ray Wenderlich (3G4T3B2D7X)" \

Replace the text inside the quotation marks by pasting the name of your certificate; make sure the file name matches your disk image. If everything goes correctly, you won’t see any output.

For this next step, you’ll need an app-specific password for your Apple ID. Head over to appleid.apple.com and sign in with your Apple ID. Under Security, click Generate password… under APP-SPECIFIC PASSWORDS and name it altool. Copy the password to a secure location, you’ll need it for the next step.

Now, you can upload the disk image to Apple’s notarization service. Instead of using Xcode like before, you’ll do it from the command line. Run the following command:

xcrun altool --notarize-app \
  -f Journalyst-converted.dmg \
  --primary-bundle-id com.raywenderlich.Journalyst \
  -u ray@raywenderlich.com

Pre-empting your commands with xcrun makes sure the commands run from your developer directory. The tool you’ll use to notarize your .dmg file is Apple’s altool, a command-line tool that lets you interact with the App Store and Apple’s notary service.

Replace “Journalyst-converted.dmg” with the name of your disk image, then replace the bundle ID with the one for your app. Finally, unless you’re Ray, replace the email with the Apple ID that you use to log into App Store Connect.

You’ll see a prompt for a password. Enter the app-specific password you just copied and wait a few moments for the disk image to upload. Once uploaded, you should see a message similar to this one:

No errors uploading ’Journalyst-converted.dmg’.
RequestUUID = 66accdd9-7d26-4173-8e88-ea53f61b37b0

This confirms that the disk image was uploaded, but it doesn’t automatically mean it was notarized. To check the notarization status, run the following command again, replacing the email with your Apple ID:

xcrun altool --notarization-history 0 \
  -u ray@raywenderlich.com

This shows a table of notarization requests and their statuses. Enter your app-specific password. After waiting for a while and running the command again, you should see the “Status” column change to “success” and “Status Message” change to “Package Approved”:

Date  RequestUUID Status  Status Code Status Message   
----- ----------- ------- ----------- ---------------- 
(...) (...)       success 0           Package Approved 

Note: If notarization failed, you can see more information by entering the following command:

xcrun altool --notarization-info 66accdd9-7d26-4173-8e88-ea53f61b37b0 -u ray@raywenderlich.com

Replace the email with your Apple ID and the ID with the RequestUUID that was output from the --notarize-app command. You’ll see a log file URL that you can open to see a list of issues with your disk image.

A “success” status means that Apple has notarized your disk image and stored a ticket on their servers. You also need to include this ticket in your .dmg file. You can do that by stapling it to the file. Run the following command:

xcrun stapler staple Journalyst-converted.dmg 

You should see a message saying, “The staple and validate action worked!”. The message makes it sound like Apple itself is surprised the action worked. :]

You now have a signed and notarized disk image that contains a signed and notarized app. It’s like a babushka doll of security!

Key points

  • To distribute macOS apps without the App Store, you need to sign the app with a Developer ID certificate.
  • Apps and other software packages need to be notarized to verify they’re malware-free.
  • You can use Xcode to notarize apps.
  • You package apps inside disk images (.dmg files) for easier downloading and installation.
  • Sign .dmg files using the codesign command-line tool.
  • Notarize .dmg files using the altool command-line tool.
  • After notarization, make sure to staple the ticket to the .dmg file by using the stapler utility.

Where to go from here?

Unfortunately, unless you want to distribute your app via email, you’ll also need a website to host and show off your app. If you’re making a paid app, you’ll need to deal with payments and managing licenses. This sounds scary, but there are some tools to help you.

Here are a few tools you can use to manage customers and billing:

  • Paddle (paddle.com/solutions/mac/) lets you manage billing customers both in-app and on your website.
  • Even though it’s not specific to macOS apps, Gumroad (gumroad.com) lets you easily sell stuff online and manage your customers.
  • Braintree (braintreepayments.com) is a company owned by PayPal and also offers an easy way to set up payments.

All of these have ways to integrate them into existing websites and, in some cases, macOS apps.

If you’re not a web developer, don’t fret. There are plenty of tutorials, courses and website builders to get you started. First of all, you already know Swift, so why not use it to build your website? Vapor, a server-side Swift framework, offers a templating engine called Leaf that you can use to build a landing page for your app. Here are three different resources on Vapor and Leaf:

If you’re not into the idea of building out a website with code, you can use website builders like Squarespace (www.squarespace.com) or Webflow (webflow.com). Aside from letting you build a website without knowing anything about web development, these tools also host your website — one less headache to worry about.

As you can see, exporting your app is not enough. You also need to deal with building websites, managing customers and marketing your app. Nobody ever said it would be easy, but indie app development is extremely rewarding. Your success is in your own hands, for better or for worse. We at raywenderlich.com are all rooting for you. Good luck out there! :]

Have a technical question? Want to report a bug? You can ask questions and report bugs to the book authors in our official book forum here.

Have feedback to share about the online reading experience? If you have feedback about the UI, UX, highlighting, or other features of our online readers, you can send them to the design team with the form below:

© 2020 Razeware LLC