Publish a Mac Catalyst app for Mac App Store distribution

The most common approach to distributing Mac Catalyst apps to users is through the Mac App Store. Apps are submitted to the Mac App Store through an online tool called App Store Connect. Only developers who belong to the Apple Developer Program have access to this tool. Members of the Apple Developer Enterprise Program do not have access. All apps submitted to the Mac App Store require approval from Apple.

Distributing a Mac Catalyst app requires that the app is provisioned using a provisioning profile. Provisioning profiles are files that contain code signing information, as well as the identity of the app and its intended distribution mechanism.

To distribute a .NET Multi-platform App UI (.NET MAUI) Mac Catalyst app, you'll need to build a distribution provisioning profile specific to it. This profile enables the app to be digitally signed for release so that it can be installed on Macs. A distribution provisioning profile contains an App ID and a distribution certificate. You'll need to create a distribution certificate to identify yourself or your organization, if you don't already have one. In addition, you'll need to create a Mac installer certificate to sign your app's installer package for submission to the Mac App Store.

The process for provisioning a .NET MAUI Mac Catalyst app for distribution through the Mac App Store is as follows:

  1. Create a certificate signing request. For more information, see Create a certificate signing request.
  2. Create a distribution certificate. For more information, see Create a distribution certificate.
  3. Create an installer certificate. For more information, see Create an installer certificate.
  4. Create an App ID. For more information, see Create an App ID.
  5. Configure the App ID. For more information, see Configure the App ID.
  6. Create a provisioning profile. For more information, see Create a provisioning profile.
  7. Download your provisioning profile. For more information, see Download your provisioning profile in Xcode.

Then, once provisioning is complete you should prepare your app for publishing and then publish it with the following process:

  1. Add required entitlements to your app. For more information, see Add entitlements.
  2. Update the app's Info.plist file. For more information, see Update Info.plist.
  3. Publish your app using the command line. For more information, see Publish using the command line.

Create a certificate signing request

Before you create a distribution certificate, you'll first need to create a certificate signing request (CSR) in Keychain Access on a Mac:

  1. On your Mac, launch Keychain Access.

  2. In Keychain Access, select the Keychain Access > Certificate Assistant > Request a Certificate from a Certificate Authority... menu item.

  3. In the Certificate Assistant dialog, enter an email address in the User Email Address field.

  4. In the Certificate Assistant dialog, enter a name for the key in the Common Name field.

  5. In the Certificate Assistant dialog, leave the CA Email Address field empty.

  6. In the Certificate Assistant dialog, choose the Saved to disk radio button and select Continue:

    Certificate assistant dialog.

  7. Save the certificate signing request to a known location.

  8. In the Certificate Assistant dialog, select the Done button.

  9. Close Keychain Access.

Create a distribution certificate

The CSR allows you to generate a distribution certificate, which confirms your identity. The distribution certificate must be created using the Apple ID for your Apple Developer Account:

  1. In a web browser, login to your Apple Developer Account.

  2. In your Apple Developer Account, select the Certificates, IDs & Profiles tab.

  3. On the Certificates, Identifiers & Profiles page, select the + button to create a new certificate.

  4. On the Create a New Certificate page, select the Apple Distribution radio button before selecting the Continue button:

    Create an Apple distribution certificate.

  5. On the Create a New Certificate page, select Choose File:

    Upload your certificate signing request for your Apple distribution certificate.

  6. In the Choose Files to Upload dialog, select the certificate request file you previously created (a file with a .certSigningRequest file extension) and then select Upload.

  7. On the Create a New Certificate page, select the Continue button:

    Continue to generate your distribution certificate.

  8. On the Download Your Certificate page, select the Download button:

    Download your Apple distribution certificate.

    The certificate file (a file with a .cer extension) will be downloaded to your chosen location.

  9. On your Mac, double-click the downloaded certificate file to install the certificate to your keychain. The certificate appears in the My Certificates category in Keychain Access, and begins with Apple Distribution:

    Keychain Access showing distribution certificate.

    Note

    Make a note of the full certificate name in Keychain Access. It will be required when signing your app.

Create an installer certificate

The CSR allows you to generate an installer certificate, which is required to sign your app's installer package for submission to the Mac App Store. The installer certificate must be created using the Apple ID for your Apple Developer Account:

  1. In your Apple Developer Account, select the Certificates, IDs & Profiles tab.

  2. On the Certificates, Identifiers & Profiles page, select the + button to create a new certificate.

  3. On the Create a New Certificate page, select the Mac Installer Distribution radio button before selecting the Continue button:

    Create a Mac Installer distribution certificate.

  4. On the Create a New Certificate page, select Choose File:

    Upload your certificate signing request for the Mac installer certificate.

  5. In the Choose Files to Upload dialog, select the certificate request file you previously created (a file with a .certSigningRequest file extension) and then select Upload.

  6. On the Create a New Certificate page, select the Continue button:

    Continue to generate your installer certificate.

  7. On the Download Your Certificate page, select the Download button:

    Download your Mac installer certificate.

    The certificate file (a file with a .cer extension) will be downloaded to your chosen location.

  8. On your Mac, double-click the downloaded certificate file to install the certificate to your keychain. The certificate appears in the My Certificates category in Keychain Access, and begins with 3rd Party Mac Developer Installer:

    Keychain Access showing installer certificate.

    Note

    Make a note of the full certificate name in Keychain Access. It will be required when signing your app.

Create a distribution profile

A distribution provisioning profile enables your .NET MAUI Mac Catalyst app to be digitally signed for release, so that it can be installed on another Mac. A provisioning profile for Mac App Store distribution contains an App ID and a distribution certificate.

Create an App ID

An App ID is required to identify the app that you are distributing. An App ID is similar to a reverse-DNS string, that uniquely identifies an app, and should be identical to the bundle identifier for your app. You can use the same App ID that you used when deploying your app to a device for testing.

There are two types of App ID:

  • Wildcard. A wildcard App ID allows you to use a single App ID to match multiple apps, and typically takes the form com.domainname.*. A wildcard App ID can be used to distribute multiple apps, and should be used for apps that do not enable app-specific capabilities.
  • Explicit. An explicit App ID is unique to a single app, and typically takes the form com.domainname.myid. An explicit App ID allows the distribution of one app, with a matching bundle identifier. Explicit App IDs are typically used for apps that enable app-specific capabilities such as Apple Pay, or Game Center. For more information about capabilities, see Capabilities.

To create a new App ID:

  1. In your Apple Developer Account, navigate to Certificates, IDs & Profiles.

  2. On the Certificates, Identifiers & Profiles page, select the Identifiers tab.

  3. On the Identifiers page, select the + button to create a new App ID.

  4. On the Register a new identifier page, select the App IDs radio button before selecting the Continue button:

    Create an App ID.

  5. On the Register a new identifier page, select App before selecting the Continue button:

    Register an App ID.

  6. On the Register an App ID page, enter a description, and select either the Explicit or Wildcard Bundle ID radio button. Then, enter the Bundle ID for your app in reverse DS format:

    Specify the bundle identifier for the app.

    Important

    The Bundle ID you enter must correspond to the Bundle identifier in the Info.plist file in your app project.

    The bundle identifier for a .NET MAUI app is stored in the project file as the Application ID property:

    • In Visual Studio, in Solution Explorer right-click on your .NET MAUI app project and select Properties. Then, navigate to the MAUI Shared > General tab. The Application ID field lists the bundle identifier.
    • In Visual Studio for Mac, in the Solution Window, right-click on your .NET MAUI app project and select Properties. Then, in the Project Properties window, select the Build > App Info tab. The Application ID field lists the bundle identifier.

    When the value of the Application ID field is updated, the value of the Bundle identifier in the Info.plist will be automatically updated.

  7. On the Register an App ID page, select any capabilities that the app uses. Any capabilities must be configured both on this page and in the Entitlements.plist file in your app project. For more information see Capabilities and Entitlements.

  8. On the Register an App ID page, select the Continue button.

  9. On the Confirm your App ID page, select the Register button.

Configure the App ID

By default, a Mac Catalyst app uses the same bundle ID as an iOS app so you can offer the apps together as a universal purchase on the Mac App Store. Alternatively, you can specify a unique bundle ID to offer the app as a separate product.

To configure the App ID:

  1. In your Apple Developer Account, navigate to Certificates, IDs & Profiles.

  2. On the Certificates, Identifiers & Profiles page, select the Identifiers tab.

  3. On the Identifiers page, select the App ID you just created.

  4. On the Edit your App ID Configuration page, scroll to the bottom of the page and enable the Mac Catalyst capability check-box. Then select the Configure button:

    Enable the Mac Catalyst capability.

  5. In the Configure Bundle ID for Mac Catalyst popup, select the Use existing Mac App ID radio button. In the App ID drop-down, select either the App ID for your Mac Catalyst's partner iOS app, or the the App ID you've created if you're offering the Mac Catalyst app as a separate product. Then, select the Save button:

    Configure the Bundle ID for Mac Catalyst.

  6. In the Edit your App ID Configuration page, select the Save button:

    Save the Mac Catalyst configuration.

  7. In the Modify App Capabilities popup, select the Confirm button:

    Modify the app capabilities.

Create a provisioning profile

Once the App ID has been created and configured, you should create a distribution provisioning profile. This profile enables the app to be digitally signed for release so that it can be installed on Macs.

To create a provisioning profile for Mac App Store distribution:

  1. In the Certificates, Identifiers & Profiles page of your Apple Developer Account, select the Profiles tab.

  2. In the Profiles tab, click the + button to create a new profile.

  3. In the Register a New Provisioning Profile page, select the Mac App Store radio button before clicking the Continue button:

    Register a provisioning profile for app store distribution.

  4. In the Generate a Provisioning Profile page, select the Mac radio button. Then, in the App ID drop-down, select the App ID that you previously created before clicking the Continue button:

    Select your App ID.

  5. In the Generate a Provisioning Profile page, select the radio button that corresponds to your distribution certificate before clicking the Continue button:

    Select your distribution certificate.

  6. In the Generate a Provisioning Profile page, enter a name for the provisioning profile before clicking the Generate button:

    Generate the provisioning profile.

    Note

    Make a note of the provisioning profile name, as it will be required when signing your app.

  7. In the Generate a Provisioning Profile page, optionally click the Download button to download your provisioning profile.

    Note

    It's not necessary to download your provisioning profile now. Instead, you will do this in Xcode.

Download your provisioning profile in Xcode

After creating a provisioning profile in your Apple Developer Account, Xcode can download it so that it's available for signing your app:

  1. On your Mac, launch Xcode.

  2. In Xcode, select the Xcode > Preferences... menu item.

  3. In the Preferences dialog, select the Accounts tab.

  4. In the Accounts tab, click the + button to add your Apple Developer Account to Xcode:

    Xcode Accounts dialog in preferences.

  5. In the account type popup, select Apple ID and then click the Continue button:

    Xcode select the type of account you'd like to add popup.

  6. In the sign in popup, enter your Apple ID and click the Next button.

  7. In the sign in popup, enter your Apple ID password and click the Next button:

    Xcode Apple account sign-in.

  8. In the Accounts tab, click the Manage Certificates... button to ensure that your distribution certificate has been downloaded.

  9. In the Accounts tab, click the Download Manual Profiles button to download your provisioning profiles:

    Xcode Apple Developer Program account details.

  10. Wait for the download to complete and then close Xcode.

Add entitlements

Apple's App Sandbox restricts access to system resources and user data in Mac apps, to contain damage if an app becomes compromised. It must be enabled for Mac Catalyst apps that are distributed through the Mac App Store.

This can be accomplished by adding an Entitlements.plist file to the Platforms/MacCatalyst folder of your .NET MAUI app project:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
  <dict>
    <key>com.apple.security.app-sandbox</key>
    <true/>
  </dict>
</plist>

The App Sandbox entitlement is defined using the com.apple.security.app-sandbox key, of type boolean. For information about App Sandbox, see Protecting user data with App Sandbox on developer.apple.com. For information about the App Sandbox entitlement, see App Sandbox Entitlement.

If your app opens outgoing network connections, you'll also need to add the com.apple.security.network.client key, of type boolean, to your Entitlements.plist file:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
  <dict>
    <key>com.apple.security.app-sandbox</key>
    <true/>
    <key>com.apple.security.network.client</key>
    <true/>
  </dict>
</plist>

For information about the outgoing network connections entitlement, see com.apple.security.network.client on developer.apple.com.

Update Info.plist

Before publishing your app, you should update its Info.plist file with additional information to ensure that the app can be uploaded to the Mac App Store, and to help ensure a smooth Mac App Store review process.

Specify the user interface idiom

A Mac Catalyst app can run in the iPad or Mac user interface idiom:

  • The iPad user interface idiom tells macOS to scale the app's user interface to match the Mac display environment while preserving iPad-like appearance.
  • The Mac user interface idiom doesn't scale the app's user interface to match the Mac display environment. Some controls change their size and appearance, and interacting with them feels identical to interacting with AppKit controls.

By default, .NET MAUI Mac Catalyst apps use the iPad user interface idiom. If this is your desired behavior, ensure that the app's Info.plist file only specifies 2 as the value of the UIDeviceFamily key:

<key>UIDeviceFamily</key>
<array>
  <integer>2</integer>
</array>

To adopt the Mac user interface idiom, update the app's Info.plist file to specify 6 as the value of the UIDeviceFamily key:

<key>UIDeviceFamily</key>
<array>
  <integer>6</integer>
</array>

For more information about Mac Catalyst user interface idioms, see Specify the UI idiom for your Mac Catalyst app.

Set the default language and region for the app

Set the CFBundleDevelopmentRegion key in your app's Info.plist to a string that represents the localization native development region:

<key>CFBundleDevelopmentRegion</key>
<string>en</string>

The value of the key should be a language designator, with an optional region designator. For more information, see CFBundleDevelopmentRegion on developer.apple.com.

Set the NSHumanReadableCopyright key in your app's Info.plist to a string that represents the human-readable copyright notice for your app:

<key>NSHumanReadableCopyright</key>
<string>MyMauiApp © 2023</string>

For more information, see NSHumanReadableCopyright on developer.apple.com.

Set the app category

Categories help users discover your app on the Mac App Store. You can set the app's primary category in your Info.plist file:

<key>LSApplicationCategoryType</key>
<string>public.app-category.utilities</string>

For more information, see LSApplicationCategoryType on developer.apple.com.

Note

Your app's primary category must match the primary category you set in App Store Connect.

Declare your app's use of encryption

If your app uses encryption, and you plan to distribute it outside the United States or Canada, it's subject to US export compliance requirements. Every time you submit a version of your app to App Store Connect, it undergoes an encryption export regulations compliance review. To avoid App Store Connect asking you questions to guide you through the review, you can provide the required information in your app's Info.plist file.

This is accomplished by adding the ITSAppUsesNonExemptEncryption key to your app's Info.plist with a boolean value that indicates whether your app uses encryption:

<key>ITSAppUsesNonExemptEncryption</key>
<false/>

For more information, see Complying with Encryption Export Regulations on developer.apple.com.

Publish using the command line

To publish your Mac Catalyst app from the command line on a Mac, open a terminal and navigate to the folder for your .NET MAUI app project. Run the dotnet publish command, providing the following parameters:

Parameter Value
-f or --framework The target framework, which is net8.0-maccatalyst.
-c or --configuration The build configuration, which is Release.
-p:MtouchLink The link mode for the project, which can be None, SdkOnly, or Full.
-p:CreatePackage Set to true so that a package (.pkg) is created for the app at the end of the build.
-p:EnableCodeSigning Set to true so that code signing is enabled.
-p:EnablePackageSigning Set to true so that the package that's created gets signed.
-p:CodesignKey The name of the code signing key. Set to the name of your distribution certificate, as displayed in Keychain Access.
-p:CodesignProvision The provisioning profile to use when signing the app bundle.
-p:CodesignEntitlements The path to the entitlements file that specifies the entitlements the app requires. Set to Platforms\MacCatalyst\Entitlements.plist.
-p:PackageSigningKey The package signing key to use when signing the package. Set to the name of your installer certificate, as displayed in Keychain Access.

Warning

Attempting to publish a .NET MAUI solution will result in the dotnet publish command attempting to publish each project in the solution individually, which can cause issues when you've added other project types to your solution. Therefore, the dotnet publish command should be scoped to your .NET MAUI app project.

Additional build parameters can be specified on the command line, if they aren't provided in a <PropertyGroup> in your project file. The following table lists some of the common parameters:

Parameter Value
-p:ApplicationTitle The user-visible name for the app.
-p:ApplicationId The unique identifier for the app, such as com.companyname.mymauiapp.
-p:ApplicationVersion The version of the build that identifies an iteration of the app.
-p:ApplicationDisplayVersion The version number of the app.

For a full list of build properties, see Project file properties.

Important

Values for all of these parameters don't have to be provided on the command line. They can also be provided in the project file. When a parameter is provided on the command line and in the project file, the command line parameter takes precedence. For more information about providing build properties in your project file, see Define build properties in your project file.

For example, use the following command to build and sign a .pkg on a Mac, for distribution through the Mac App Store:

dotnet publish -f net8.0-maccatalyst -c Release -p:MtouchLink=SdkOnly -p:CreatePackage=true -p:EnableCodeSigning=true -p:EnablePackageSigning=true -p:CodesignKey="Apple Distribution: John Smith (AY2GDE9QM7)" -p:CodesignProvision="MyMauiApp" -p:CodesignEntitlements="Platforms\MacCatalyst\Entitlements.plist" -p:PackageSigningKey="3rd Party Mac Developer Installer: John Smith (AY2GDE9QM7)"

Note

In .NET 8, the dotnet publish command defaults to the Release configuration. Therefore, the build configuration can be omitted from the command line.

Publishing builds, signs, and packages the app, and then copies the .pkg to the bin/Release/net8.0-maccatalyst/publish/ folder. If you publish the app using only a single architecture, it will be published to the bin/Release/net8.0-maccatalyst/{architecture}/publish/ folder.

During the signing process it maybe necessary to enter your login password and allow codesign and productbuild to run:

Allow codesign to sign your app on your Mac. Allow productbuild to sign your app on your Mac.

For more information about the dotnet publish command, see dotnet publish.

Define build properties in your project file

An alternative to specifying build parameters on the command line is to specify them in your project file in a <PropertyGroup>. The following table lists some of the common build properties:

Property Value
<ApplicationTitle> The user-visible name for the app.
<ApplicationId> The unique identifier for the app, such as com.companyname.mymauiapp.
<ApplicationVersion> The version of the build that identifies an iteration of the app.
<ApplicationDisplayVersion> The version number of the app.
<CodesignKey> The name of the code signing key. Set to the name of your distribution certificate, as displayed in Keychain Access.
<CodesignEntitlements> The path to the entitlements file that specifies the entitlements the app requires. Set to Platforms\MacCatalyst\Entitlements.plist.
<CodesignProvision> The provisioning profile to use when signing the app bundle.
<CreatePackage> Set to true so that a package (.pkg) is created for the app at the end of the build.
<EnableCodeSigning> Set to true so that code signing is enabled.
<EnablePackageSigning> Set to true so that the package that's created gets signed.
<MtouchLink> The link mode for the project, which can be None, SdkOnly, or Full.
<PackageSigningKey> The package signing key to use when signing the package. Set to the name of your installer certificate, as displayed in Keychain Access.

For a full list of build properties, see Project file properties.

Important

Values for these build properties don't have to be provided in the project file. They can also be provided on the command line when you publish the app. This enables you to omit specific values from your project file.

The following example shows a typical property group for building and signing your Mac Catalyst app for Mac App Store distribution:

<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Release|net8.0-maccatalyst|AnyCPU'">
  <MtouchLink>SdkOnly</MtouchLink>
  <EnableCodeSigning>True</EnableCodeSigning>
  <EnablePackageSigning>true</EnablePackageSigning>
  <CreatePackage>true</CreatePackage>
  <CodesignKey>Apple Distribution: John Smith (AY2GDE9QM7)</CodesignKey>
  <CodesignProvision>MyMauiApp</CodesignProvision>
  <CodesignEntitlements>Platforms\MacCatalyst\Entitlements.plist</CodesignEntitlements>
  <PackageSigningKey>3rd Party Mac Developer Installer: John Smith (AY2GDE9QM7)</PackageSigningKey>
</PropertyGroup>

This example <PropertyGroup> adds a condition check, preventing the settings from being processed unless the condition check passes. The condition check looks for two items:

  1. The build configuration is set to Release.
  2. The target framework is set to something containing the text net8.0-maccatalyst.
  3. The platform is set to AnyCPU.

If any of these conditions fail, the settings aren't processed. More importantly, the <CodesignKey>, <CodesignProvision>, and <PackageSigningKey> settings aren't set, preventing the app from being signed.

After adding the above property group, the app can be published from the command line on a Mac by opening a terminal and navigating to the folder for your .NET MAUI app project. Then, run the following command:

dotnet build -f net8.0-maccatalyst -c Release

Note

In .NET 8, the dotnet publish command defaults to the Release configuration. Therefore, the build configuration can be omitted from the command line.

Publishing builds, signs, and packages the app, and then copies the .pkg to the bin/Release/net8.0-maccatalyst/publish/ folder.

Upload to the Mac App Store

Once an app was been code signed with an Apple Distribution certificate, it can't be run locally. Instead, it should be uploaded to App Store Connect where it will be re-signed to enable local execution.

To distribute your app through the Mac App Store, or TestFlight, you'll need to create an app record in App Store Connect. This record includes all the information about the app as it will appear in the App Store and all of the information needed to manage the app throughout the distribution process. For more information, see Create an app record on developer.apple.com.

Transporter can be used to submit your app to the Mac App Store. It will also help to identify errors with app packages that stop successful submission.

See also