# Amore > Amore self-publishes macOS apps outside the App Store. One command archives, code signs, notarizes, builds a DMG, uploads it, and updates the Sparkle appcast. It also sells license keys for those apps through your own Stripe account. Amore is a Mac app plus a CLI (`brew install amore`), built by Lucas Fischer. It is free to use, with an Amore+ subscription for unlimited releases, custom domains, analytics, and teams. Open-source apps get every feature for free, forever. Every documentation page and post follows in full. For a linked index instead, see https://amore.computer/llms.txt. # Get Started with Amore Source: https://amore.computer/help/get-started/ There are 4 steps to get started with Amore. 1. [Download Amore](/download) (or install via Homebrew: `brew install amore`) 2. Add your app to Amore. 3. Add Sparkle to your project. 4. Publish your app. ## Video In case you prefer to watch a video, here's this guide as a [video (3:35)](https://cdn.amore.computer/videos/get-started.mp4). ## Add your app to Amore The easiest way to get started with Amore is to drag your app binary (`.app`) into Amore. You will then have to decide if you want to host your app on Amore or self-manage an S3 bucket. It's recommended to select `Amore` because the setup is simpler, you will be able to make use of advanced features and Amore will choose the best defaults for your app. If you prefer to self-manage S3 you can learn more [here](/help/s3-bucket/). ![Create App](/assets/images/help/get-started/create-app.webp) The in-app wizard will take you to through the following steps: 1. Register app with Amore / S3 setup 2. Creating Sparkle keys for signing app updates 3. Adding Sparkle to your project Please follow the instructions inside the app. ## Add Sparkle to your project For your app to be able to fetch and download updates you need to add [*Sparkle*](https://sparkle-project.org/) to your project. Sparkle will need the following 2 entries in your `Info.plist` file to fetch and verify new updates: - Update Feed URL: `SUFeedURL` - Public Key: `SUPublicEDKey` You can find the correct values for these entries in the `Sparkle` settings in Amore. ![Sparkle Settings](/assets/images/help/key-management/key-management.webp) After you added `SUFeedURL` and `SUPublicEDKey` to your `Info.plist` you need to add Sparkle as a package dependency and initialize the Sparkle updater `SPUStandardUpdaterController` class in your source code. ### Add Sparkle Package Dependency 1. In your Xcode project: File › Add Packages… 2. Enter `https://github.com/sparkle-project/Sparkle` as the package repository URL If you use Swift Package Manager (SPM) you can use: ```swift .package(url: "https://github.com/sparkle-project/Sparkle", from: "2.8.1"), ``` ### Initialize Sparkle Initialize the `SPUStandardUpdaterController` in your app's `@main` entry point. Here is an example for a SwiftUI lifecycle project. ```swift import SwiftUI import Sparkle @main struct AmoreApp: App { let updaterController = SPUStandardUpdaterController( startingUpdater: true, updaterDelegate: nil, userDriverDelegate: nil ) var body: some Scene { WindowGroup { ContentView() } .commands { CommandGroup(after: .appInfo) { Button("Check for Updates…") { updaterController.updater.checkForUpdates() } } } } } ``` It is recommend to also add the `Check for Updates...` menu bar button to be able to manually check for new updates. If you don't use the SwiftUI app lifecycle you can add it to your app delegate's (`NSApplicationDelegate`) `didFinishLaunchingWithOptions` method. ### Sandboxing Notes Sparkle requires [additional setup](/help/sparkle-sandboxing) when using the `App Sandbox` entitlement. For simplicity and the sake of getting started with Amore you can remove this entitlement from your app and add the `Hardened Runtime` entitlement instead. ## Publish your app After you added Sparkle and set the correct values in your `Info.plist`, you are ready to distribute your app with Amore. Now you can archive your app and select `Direct Distribution` in the Xcode Organizer to send your app to Apple for notarization. You can follow [these steps](https://developer.apple.com/documentation/security/notarizing-macos-software-before-distribution#Notarize-your-app-automatically-as-part-of-the-distribution-process). Once the app is notarized you can drag and drop your app binary (`.app`) into Amore, optionally write release notes and hit publish. Congrats. You just published your first app with Amore. ![Succes](/assets/images/help/get-started/success.webp) ## Where to go from here? Whenever you want to release a new version of your app, increment the build number and go through the [release process](#publish-your-app) again. To streamline the release process you can set up the [Xcode post-archive action](/help/xcode-post-archive-action/) to let Amore take care of code signing and the notarization process after archiving automatically. If you prefer working from the terminal, the entire workflow — from setup to publishing — can be done via the [Command Line](/help/command-line/) without ever opening the app. For a complete reference project that wires up Sparkle and AmoreLicensing in a small SwiftUI app, see the [Pomodoro example](https://github.com/AmoreComputer/Pomodoro). # Licensing Guide Source: https://amore.computer/help/licensing-guide/ Amore's licensing system lets you issue, activate, and validate license keys for your macOS app. Customers purchase a license through a Stripe-powered checkout, receive their key via email, and activate it in your app. For a complete working reference, see the [Pomodoro example project](https://github.com/AmoreComputer/Pomodoro), a simple SwiftUI app that integrates both Sparkle updates and AmoreLicensing end-to-end. ## Video {% youtube "4QNPWRAxhGY", "Adding AmoreLicensing to a Swift app in Xcode", "Watch licensing go into a real Swift app, start to finish, in about three minutes." %} ## Overview There are 4 steps to set up licensing: 1. [Create a product](#create-a-product) 2. [Connect Stripe](#connect-stripe) 3. [Integrate the AmoreLicensing SDK](#integrate-amorelicensing-sdk) 4. [Share your checkout link](#share-your-checkout-link) Optionally, you can skip the checkout link and [sell from inside your app](/help/in-app-purchases/) instead. ## Create a Product A product defines what you're selling and how licenses behave — the name, device limit, and duration. You can create a product from the Licensing screen in Amore by clicking **New Product**. [Learn more about Product Settings](/help/products/) ## Connect Stripe Amore uses [Stripe](https://stripe.com) to process payments and manage subscriptions. You'll need to add your Stripe secret key and set up a webhook so Amore can issue licenses automatically when a purchase completes. [Learn more about Licensing Settings](/help/licensing/) ## Integrate AmoreLicensing SDK Add the `AmoreKit` Swift package to your project: ```swift .package(url: "https://github.com/AmoreComputer/AmoreKit", from: "0.6"), ``` Add `AmoreLicensing` as a dependency to your target: ```swift .product(name: "AmoreLicensing", package: "AmoreKit") ``` ### Initialize Create an `AmoreLicensing` instance with your public key. You can find the integration code snippet in [Licensing Settings](/help/licensing/). ```swift import AmoreLicensing let licensing = try AmoreLicensing( publicKey: "your-public-key", bundleIdentifier: "com.example.myapp" ) ``` The `bundleIdentifier` parameter defaults to `Bundle.main.bundleIdentifier` if omitted. ### Activate and Deactivate ```swift try await licensing.activate(licenseKey: "XXXX-XXXX-XXXX") try await licensing.deactivate() ``` ### Check Status `AmoreLicensing` is `@Observable`, so you can use `status` directly in SwiftUI views: ```swift switch licensing.status { case .valid(let license): // License is active case .gracePeriod(let license): // Expired but within grace window case .invalid: // Invalid or revoked case .unknown: // No license stored } ``` For the full API reference, see the [AmoreLicensing documentation](https://docs.amore.computer). For a working SwiftUI integration that gates the UI on `licensing.status`, see the [Pomodoro example](https://github.com/AmoreComputer/Pomodoro). ## Share Your Checkout Link Each product has a checkout link available in [Product Settings](/help/products/). Share this link on your website, in your app, or anywhere your customers can find it. If you use the checkout link, your customers will automatically get redirected to an Amore-hosted success page showing them their freshly issued license key and information about their purchase. In addition to the success webpage, after each successful purchase, your customers will receive their license key via email. ## Sell Inside Your App The checkout link sends customers to a browser and back again with a key to paste. `AmoreCheckout` skips that round trip: the customer pays in a sheet inside your app and the license activates itself. [Learn more about in-app purchases](/help/in-app-purchases/) # In-App Purchases Source: https://amore.computer/help/in-app-purchases/ The classic way to sell a Mac app outside the App Store asks a lot of your customer. They leave your app for a browser, pay, wait for an email, find the license key, switch back, and paste it in. Every one of those steps is a place to lose the sale, and the ones who make it through still write to you when the email lands in spam. `AmoreCheckout` removes the detour. The customer clicks buy, pays in a sheet inside your app, and the app unlocks itself. It's part of [AmoreKit](https://github.com/AmoreComputer/AmoreKit) and bridges the two libraries you already have: `AmoreStore` fetches your products, `AmoreLicensing` activates the key. When payment completes, the key is fetched from the server and `activate(licenseKey:)` runs for you. For a complete working reference, see the [Pomodoro example project](https://github.com/AmoreComputer/Pomodoro), which integrates Sparkle updates, licensing, and in-app checkout end-to-end. ## Before You Start In-app purchases build on the licensing system, so you'll need a product and a connected Stripe account first. The [licensing guide](/help/licensing-guide/) covers both. ## Install Add the `AmoreKit` package to your project: ```swift .package(url: "https://github.com/AmoreComputer/AmoreKit", from: "0.6") ``` Add `AmoreCheckout` as a dependency to your target: ```swift .product(name: "AmoreCheckout", package: "AmoreKit") ``` Checkout runs in an embedded web view, so sandboxed apps need the outgoing-connections entitlement: ```xml com.apple.security.network.client ``` Payment can always finish in the external browser instead, which Apple Pay requires. The app activates the license either way. ## Create the Checkout Create one `AmoreCheckout` where you create your `AmoreLicensing` instance, and pass it down: ```swift let licensing = try AmoreLicensing(publicKey: "your-public-key") let checkout = AmoreCheckout(licensing: licensing) ``` You own the object. One instance serves every product, and its lifetime is yours. ## Present the Sheet Fetch your products with `AmoreStore`, then bind the one being bought. The `amoreCheckout(item:checkout:)` modifier presents checkout for whatever the binding holds: ```swift import AmoreCheckout import SwiftUI import struct AmoreStore.Product struct PaywallView: View { let checkout: AmoreCheckout let products: [Product] @State private var buying: Product? var body: some View { VStack { ForEach(products) { product in Button("Buy \(product.name)") { buying = product } } } .amoreCheckout(item: $buying, checkout: checkout) } } ``` That's the whole integration. When payment completes, the license is activated on this device and `licensing.status` flips to `.valid`, so any UI you gate on it unlocks reactively. ## Handle the Result Pass `onResult` to receive the outcome of every attempt, including retries after a failure: ```swift .amoreCheckout(item: $buying, checkout: checkout) { result in switch result { case .completed(let license, let licenseKey): print("Unlocked \(license.product.name) with \(licenseKey)") case .cancelled: break case .failed(.activationFailed(let licenseKey, _)): print("Activate manually with \(licenseKey)") case .failed(let error): print(error.localizedDescription) } } ``` The sheet already shows the license key on success, and shows it with a copy button if activation fails after payment, so nobody is ever left having paid without a key. The result carries it for your own UI too, and the key is never persisted beyond the flow. ## Recover Interrupted Purchases If the app quits mid-checkout after the customer paid, resolve the purchase once at launch: ```swift .task { await checkout.recoverPendingPurchase() } ``` Starting checkout guards the same interrupted purchase, so a customer cannot be charged twice by buying again before recovery runs. A session that already completed activates its license, one still processing is polled to its result, and an open session for the same product reopens where it left off. If the session can't be checked at all, the flow fails rather than charging again, and retrying is safe. ## Customize It The sheet is a thin layer over `AmoreCheckout`, which is UI-independent. Everything below drives the same object and activates the license the same way. ### Your Own Success Screen Build one from the same `CheckoutCompletion` and call `onDone` to close the sheet: ```swift .amoreCheckout(item: $buying, checkout: checkout, completedView: { completion in VStack { Text("Welcome to \(completion.product.name)!") Button("Start") { completion.onDone?() } } }) ``` ### Your Own Container Embed `AmoreCheckoutView` anywhere and close it from `onDone`: ```swift AmoreCheckoutView( checkout: checkout, product: product, onDone: { isPresented = false } ) ``` The view's lifetime drives the flow, so removing it from the hierarchy cancels a checkout in progress. ### Your Own Paywall `AmoreCheckout` is `@Observable`, so a paywall built from no supplied views at all can read `state` directly: ```swift switch checkout.state { case .idle, .preparing: ProgressView() case .awaitingPayment(let url): Link("Pay", destination: url) case .activating: Text("Activating…") case .completed(let license, _): Text("Unlocked \(license.product.name)") case .failed(let error): Text(error.localizedDescription) } ``` ### Browser Only To skip the embedded web view and hand the URL straight to the browser, observe `checkoutURL` and open it. The license still activates in the app when payment clears. ## Next Steps - [Custom Checkout UI](https://docs.amore.computer/documentation/amorecheckout/custom-checkout-ui) for the full customization reference - [AmoreCheckout API documentation](https://docs.amore.computer/documentation/amorecheckout) - [Pomodoro](https://github.com/AmoreComputer/Pomodoro), the open-source demo app with the whole flow - [Licensing guide](/help/licensing-guide/) if you haven't set up products and Stripe yet # How to Set Up Sparkle 2 in a SwiftUI App Source: https://amore.computer/help/sparkle/ For your app to be able to fetch and download over-the-air updates you need to add the [*Sparkle Updater*](https://sparkle-project.org/) to your project. Sparkle will need the following 2 entries in your `Info.plist` file to fetch and verify new updates: - Update Feed URL: `SUFeedURL` - Public Key: `SUPublicEDKey` You can find the correct values for these entries in the `Sparkle` settings in Amore. ![Sparkle Settings](/assets/images/help/key-management/key-management.webp) After you added `SUFeedURL` and `SUPublicEDKey` to your `Info.plist` you need to add Sparkle as a package dependency and initialize the Sparkle updater `SPUStandardUpdaterController` class in your source code. ## Add the Sparkle 2 Package Dependency 1. In your Xcode project: File › Add Packages… 2. Enter `https://github.com/sparkle-project/Sparkle` as the package repository URL If you use Swift Package Manager (SPM) you can use: ```swift .package(url: "https://github.com/sparkle-project/Sparkle", from: "2.8.1"), ``` ## Initialize SPUStandardUpdaterController in SwiftUI Initialize the `SPUStandardUpdaterController` in your app's `@main` entry point. Here is an example for a SwiftUI lifecycle project. ```swift import SwiftUI import Sparkle @main struct AmoreApp: App { let updaterController = SPUStandardUpdaterController( startingUpdater: true, updaterDelegate: nil, userDriverDelegate: nil ) var body: some Scene { WindowGroup { ContentView() } .commands { CommandGroup(after: .appInfo) { Button("Check for Updates…") { updaterController.updater.checkForUpdates() } } } } } ``` It is recommended to also add the `Check for Updates...` menu bar button to be able to manually check for new updates, which is a common pattern for macOS apps. You can do this by implementing `checkForUpdates()` like in the above code snippet. If you don't use the SwiftUI app lifecycle you can add `SPUStandardUpdaterController` to your app delegate's (`NSApplicationDelegate`) `didFinishLaunchingWithOptions` method. ## App Sandbox Entitlement Sparkle requires [additional setup](/help/sparkle-sandboxing) when using the `App Sandbox` entitlement. Alternatively, you can remove the sandboxing entitlement for the sake of getting started with Amore. You will still need the `Hardened Runtime` entitlement to satisfy Apple's notarization service. ## Troubleshooting If you get the following Sparkle error after calling `updaterController.updater.checkForUpdates()` you most likely are using the `com.apple.security.app-sandbox` entitlement and haven't followed [Sparkle's sandboxing guide](https://sparkle-project.org/documentation/sandboxing). If you don't need the `App Sandbox` entitlement you can remove it. Make sure that your app still includes the `Hardened Runtime` entitlement to be compatible with Apple's notarization service. ``` Update Error! An error occurred in retrieving update information. Please try again later. ``` ![Update Error! - An error occurred in retrieving update information. Please try again later.](/assets/images/help/sparkle/sparkle-update-error.webp) # Self-Managed S3-Bucket Source: https://amore.computer/help/s3-bucket/ ![Create App](/assets/images/help/s3/s3.webp) Amore intends not to lock you in and to make migration easy.  If you want to stay in control or already use an existing S3 bucket, you can use Amore with any S3-compatible data storage provider of your choice. If you already have an existing S3 bucket with updates and `appcast.xml`, Amore will be able to read your `appcast.xml` and will leave all the other updates alone. When you publish a new release via Amore, the new release will get added to the beginning of the `appcast.xml`. To create a persistent download link for your users, Amore will automatically copy the latest release to `/{Path Prefix}/{Product Name}.zip|dmg`, depending on your preferences. Amore will show the persistent download link to your latest release in `General`. Once everything is setup correctly you can manage releases previously added to `appcast.xml` from within Amore and use features like beta channel, phased rollouts and critical updates. You can use Amore to update the release notes of all of your releases. ## Setup When creating a new app choose `Self-Managed S3`, which will prompt you to configure an S3 bucket. You need to set your access key id and secret access key. In addition, Amore needs the bucket name, region an optionally the API endpoint you want to use in case you don't use AWS. On the top right of the S3 Configuration pane you can see if your credentials and configuration is valid. If everything works you should see a green seal icon. ## Advanced Options | Option | Description | | ------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Path Prefix** | Optional folder path within the bucket. Will also be applied to Appcast Path. | | **Public Base URL** | The public URL where files are accessible (e.g., CloudFront distribution or S3 bucket URL). | | **Appcast Path** | The path to the `appcast.xml` file within the bucket. Useful if you want to use an existing setup. Leave empty otherwise. Will respect Path Prefix if set. | ## Cloudflare R2 If you want to use Amore with Cloudflare R2 you need to set `Region` to `auto`. # Codesigning Source: https://amore.computer/help/codesigning/ Amore's codesigning settings are required for advanced but **optional** features like [automatic DMG creation](/help/dmg-creation/) and the [Xcode post-archive action](/help/xcode-post-archive-action). ## Codesign Identity If you want to use the [Xcode post-archive action](/help/xcode-post-archive-action/) or want to be able to drag and drop unsigned binaries into Amore you need to select a codesign identity in settings. Amore will use the selected identity to sign your app for distribution. You can manage available codesign identities in Xcode. If you haven't previously created a code signing identity, you can create one by following [these steps](https://developer.apple.com/documentation/xcode/sharing-your-teams-signing-certificates#Create-a-new-code-signing-identity): 1. Open Xcode. 2. Choose Xcode > Settings. 3. In the toolbar, click Accounts. 4. Select your Apple Account from the list of accounts. 5. Select the team to create the code signing identity for from the list of your Apple Account teams. 6. Click Manage Certificates. 7. In the lower-left corner of the signing certificates sheet, click the Add button (+) and choose `Developer ID Application` from the pop-up menu. ## Notarization Keychain Profile If you want to use [Xcode post-archive action](/help/xcode-post-archive-action/) or want Amore to automatically wrap your app binary in a [DMG file](/help/dmg-creation/), you need to setup a notarization keychain profile. Amore will then use the selected keychain profile to notarize your app. You only have to set this up once. Run the following command in your shell and follow the instructions. ```sh xcrun notarytool store-credentials "${YOUR_KEYCHAIN_PROFILE}" ``` After you are done, paste what you used as `${YOUR_KEYCHAIN_PROFILE}` into the Amore notarization keychain profile under `Codesigning` → `Notarization Keychain Profile`. [Learn More about Apple Notarization](https://developer.apple.com/documentation/security/notarizing-macos-software-before-distribution). # Automatic DMG Creation Source: https://amore.computer/help/dmg-creation/ Amore can automatically create DMG images during the release flow. When you release a new version of your app, Amore will package it into a DMG with a custom background and drag-to-install experience. The DMG will be code signed and notarized as part of the release process, ensuring your users can install your app without security warnings. If you drag and drop a DMG directly in Amore, it won't generate a DMG for you and will use your DMG instead. During DMG creation, Amore will launch a Finder window to correctly set the background image and resize the window. This is normal. The Finder window will automatically be closed once Amore is done creating the DMG. ![A screenshot of a automatically created DMG from Amore](/assets/images/help/dmg-creation/amore-dmg.webp) ## Video {% youtube "O8Hr8EXjyNw", "Creating a macOS DMG installer with Amore", "Watch Amore build a signed, notarized DMG installer in about two minutes." %} ## Requirements To let Amore automatically create installer DMG images for your app, you need to set up a [Codesign Identity](/help/codesigning/#codesign-identity) and [Notarization Keychain Profile](/help/codesigning/#notarization-keychain-profile) in the `Codesigning` settings. ## Setup Once you setup a [Codesign Identity](/help/codesigning/#codesign-identity) and [Notarization Keychain Profile](/help/codesigning/#notarization-keychain-profile) in the `Codesigning` settings, you will be able to enable `Create DMG Installer Image` in the `DMG Creation` settings. ### Troubleshooting Make sure you disabled the `Open folders in tabs instead of new windows` in your Finder settings for better DMG results. ## Watermark The created DMG installer image will include a `Built with amore.computer` watermark for free users. If you want to remove it, you can disable the `Show Watermark` settings after you subscribe to [Amore+](/pricing/). ## Custom Background With [Amore+](/pricing/) you can replace the generated background with your own artwork. The DMG window is always `600 × 400` points, so your image only needs to match that canvas: ![The DMG background template, with dashed placeholders marking where Finder places the app icon, the Applications folder, and their labels](/assets/images/help/dmg-creation/dmg-background-template.png) 1. [Download the template](/assets/images/help/dmg-creation/dmg-background-template.png) and open it in your design tool. The dashed boxes mark exactly where Finder places your app icon, the `Applications` folder, and their labels. 2. Design over it and export at `1200 × 800` pixels for a sharp result on Retina displays. PNG, JPG, and TIFF all work. Amore takes care of the DPI metadata for you, so a plain `1200 × 800` export at 72 DPI renders correctly. 3. Configure the exported image for your app: ```sh amore config set release dmg-background background.png -b com.example.App ``` Every following release will use your background, in the app and with `amore release`. For a single release, pass `--dmg-background ` to `amore release` or `--background ` to `amore create-dmg` instead. To return to the generated background, clear the setting: ```sh amore config set release dmg-background "" -b com.example.App ``` Images with a different aspect ratio or smaller than `600 × 400` pixels are rejected before the release starts, so you can't accidentally ship a stretched, cropped, or blurry background. ### Video {% youtube "pDLCaBaovMQ", "How to Create a Custom DMG Installer Background for Your Mac App", "Design a custom DMG background from the template and configure it in Amore." %} # Key Management Source: https://amore.computer/help/key-management/ Amore uses the macOS keychain to securely store your EdDSA signing keys to sign your updates for use with Sparkle. By default Amore stores and generates a separate private key for each app. **It is recommended to additionally store your private keys in a secure place, like password manager to not lose them.** You can learn more about how Amore signs each update for Sparkle [here](https://sparkle-project.org/documentation/#3-segue-for-security-concerns). ![Key Management](/assets/images/help/key-management/key-management.webp) ## Use Existing Key Pairs If you already setup Sparkle on your Mac before, Amore can automatically import your existing Sparkle private key and you don't have to do anything. If you already have a key pair you can import the private key by clicking on the `+` button in the top right corner to import your existing key. ## Generate a New Key Pair If you are setting up your first app to use with Sparkle you won't have any key pair in your keychain yet. You can create a new one to use with your apps by clicking the `Generate Keys` button in `Key Management`. # Xcode Post Archive Action Source: https://amore.computer/help/xcode-post-archive-action/ To streamline the release process, *Amore*'s [CLI](/help/command-line/) offers a command to be used with Xcode' archive post-actions, which will automatically handle every part of the release process after you archived your project. This includes: 1. Exporting the archive 2. Codesigning your executable 3. Creating an installer DMG (optional) 4. Notarizing your app 5. Signing your app for the Sparkle updater 6. Creating a new `appcast.xml` 7. Uploading your app binary ## Video {% youtube "liOhLYlneb8", "Setting up the Amore post-archive action in Xcode", "The full setup: hit Archive in Xcode and Amore signs, notarizes, and publishes the update. About four minutes." %} ## Requirements To use the Amore's Xcode post-archive action you first need to setup a [Codesign Identity](/help/codesigning/#codesign-identity) and [Notarization Keychain Profile](/help/codesigning/#notarization-keychain-profile) in the `Codesigning` settings. You also need to have the `amore` [CLI](/help/command-line/) installed. ## Setup All you need to do to set this up is adding the following command line instructions to your archive post-actions run script: ```sh amore post-archive ``` You get there by clicking by `Menu Bar` -> `Product` -> `Scheme` -> `Edit Scheme` -> `Archive` -> `Post-actions`. ![Xcode Post Archive Action](/assets/images/help/xcode-post-archive-action/xcode.png.webp) Now, after you successfully [archive](https://developer.apple.com/documentation/xcode/distributing-your-app-for-beta-testing-and-releases#Create-an-archive-of-your-app) your app for distribution, Amore will take over and open the Amore desktop app, which after your confirmation will take care of all the previously mentioned steps for you. # Licensing Settings Source: https://amore.computer/help/licensing/ The Licensing settings screen configures how Amore connects to [Stripe](https://stripe.com) to process license purchases for your app. ## Stripe Integration ### Secret Key Your Stripe secret key (`sk_live_...`) allows Amore to create checkout sessions and manage subscriptions on your behalf. You can find it in your [Stripe dashboard](https://dashboard.stripe.com/apikeys). If you prefer a [restricted key](https://docs.stripe.com/keys#secret-and-restricted-keys), grant these permissions: - **Checkout Sessions** — Read + Write - **Prices** — Read - **Products** — Read - **Subscriptions** — Read ### Webhook Secret The webhook signing secret (`whsec_...`) is used to verify that incoming webhook events are genuinely from Stripe. You'll get this after creating the webhook endpoint in Stripe. ### Webhook URL Amore generates a webhook URL for your app: ``` https://api.amore.computer/v1/webhooks/stripe/{bundleID} ``` Copy this URL and add it as an endpoint in your Stripe dashboard. ### Stripe Managed Payments When enabled, Stripe acts as the merchant of record for your sales. Learn more about [Stripe managed payments](https://docs.stripe.com/payments/managed-payments). ## Setting Up the Stripe Webhook 1. Go to your [Stripe dashboard](https://dashboard.stripe.com/webhooks) 2. Click **Add endpoint** 3. Paste the webhook URL from Amore 4. Select the following events: - `checkout.session.completed` - `invoice.paid` - `customer.subscription.deleted` - `customer.subscription.paused` - `customer.subscription.resumed` - `customer.subscription.updated` 5. Click **Add endpoint** 6. Copy the **signing secret** and paste it into the Webhook Secret field in Amore For more details, see the [Stripe webhook documentation](https://docs.stripe.com/webhooks). ## Integration Code After your first product is created, the Licensing screen shows a copyable code snippet with your public key and bundle identifier: ```swift let licensing = try AmoreLicensing( publicKey: "your-public-key", bundleIdentifier: "com.example.myapp" ) ``` Use this snippet to initialize the [AmoreLicensing SDK](https://docs.amore.computer) in your app. # Product Settings Source: https://amore.computer/help/products/ Products define what you're selling and how licenses behave. Each product has its own device limit, duration, and Stripe configuration. ## Create a Product Click **New Product** in the Licensing screen to create a product. You'll set three fields: - **Name** — the product name (e.g. "Pro License") - **Device Limit** — how many devices can activate a single license - **Duration** — license duration in days. Leave empty for a perpetual license. For Stripe subscriptions, this is automatically set from the billing cycle. ## Product Settings After creation, you will find your created products in the Amore sidebar in the »Products« section. The product settings screen has additional fields: ### Name The display name for your product. ### Device Limit The maximum number of devices that can be activated with a single license key. ### Duration License duration in days. An empty value means the license never expires. When linked to a Stripe subscription, the duration is automatically managed based on the subscription's billing cycle. In that case it's best to leave it empty. ### Stripe Product ID The Stripe product ID (`prod_...`) from your [Stripe dashboard](https://dashboard.stripe.com/products). This links purchases to the correct product. ### Stripe Price ID The Stripe price ID (`price_...`) used to create checkout sessions. You can find this on the product page in your [Stripe dashboard](https://dashboard.stripe.com/products). ## Checkout Link Each product has a hosted checkout link. From the product settings header, you can: - **Copy Checkout Link** — copy the URL to your clipboard - **Open Checkout In Browser** — preview the checkout page Share this link on your website, in your app, or anywhere your customers can find it. If you use the checkout link, your customers will automatically get redirected to an Amore-hosted success page showing them their freshly issued license key and information about their purchase. To keep customers in your app instead of sending them to a browser, use [in-app purchases](/help/in-app-purchases/). In addition to the success webpage, after each successful purchase, your customers will receive their license key via email. # API Keys Source: https://amore.computer/help/api-keys/ API keys let CI, scripts and the [GitHub Action](/help/github-actions/) authenticate as you without signing in interactively. Instead of your login, an automated release carries a scoped token that you create in the app and can revoke at any time. Publishing a release from CI needs exactly one of these, passed as `AMORE_TOKEN`. ## Create a key 1. Open `Amore` → `Settings…` (`⌘,`) and scroll to `API Keys`. You need to be signed in to Amore to manage keys. 2. Click `New Key`. 3. Give it a `Name` you'll recognize later, e.g. `GitHub Actions`. It's just a label. 4. Pick a `Scope` (see below). `Release` is the default and the right choice for CI. 5. Click `Create`. The secret token appears once. Copy it right then: for your security, Amore never shows it again. If you lose it, delete the key and create a new one. A token looks like `amore_` followed by a long string. Treat it like a password. ## Scopes - **`Release`**: upload releases and read your account. Best for CI. - **`Full access`**: every endpoint, including licenses and products. Give a key the least it needs. `Release` is enough to build and publish, so use it for any release pipeline. Reach for `Full access` only when a script also has to manage licenses or products. ## Use it in GitHub Actions Add the token as a repository secret named `AMORE_TOKEN` under `Settings` → `Secrets and variables` → `Actions` → `New repository secret`, then pass it into the release step: {% raw %} ```yaml amore-token: ${{ secrets.AMORE_TOKEN }} ``` {% endraw %} That's the only Amore-specific secret the action needs. See [GitHub Actions](/help/github-actions/) for the full workflow and the Apple signing secrets. ## Use it with the CLI Set `AMORE_TOKEN` in the environment and the [CLI](/help/command-line/) authenticates with it instead of your local sign-in, so there's no `amore login` step: ```sh export AMORE_TOKEN=amore_your_token_here amore release --scheme MyApp ``` This is what any CI runner or server-side script should do. When `AMORE_TOKEN` is set the CLI runs in token mode and won't read or write your login keychain. ## Manage and rotate keys The `API Keys` list shows each key's `Name`, `Scope` and `Last used`. `Last used` reads `Never` until the key's first request, so you can spot one that isn't being used. To rotate a key, create a new one, update `AMORE_TOKEN` wherever it's stored, then delete the old key. Deleting takes effect immediately: any CI or script still using that token stops working at once. Use a separate key per pipeline or machine so you can revoke one without breaking the others. # Command Line Source: https://amore.computer/help/command-line/ The *Amore* app ships with a powerful command line tool that makes it easy to automate & integrate the most common actions into your process. ## Installation ### Via Homebrew The quickest way to get started is [Homebrew](https://brew.sh). The cask installs Amore.app and links the `amore` command for you: ```sh brew install amore ``` ### Via Terminal If you installed Amore.app another way, you can install the CLI from the terminal without opening the app: ```sh /Applications/Amore.app/Contents/MacOS/AmoreCLI install ``` This creates a symlink at `/usr/local/bin/amore`. If you get a permission error, run with `sudo`: ```sh sudo /Applications/Amore.app/Contents/MacOS/AmoreCLI install ``` ### Via the App Alternatively, navigate to the Amore app `Command Line` settings and click `Install`. You will be prompted to enter your password so Amore can create the symlink at `/usr/local/bin/amore`. --- After installation, you can use the CLI without ever opening the app. A typical CLI-only workflow looks like this: ```sh amore login # Sign in to your account amore setup MyApp.app # Set up a new app amore release --scheme MyApp # Build, sign, notarize, and publish ``` To learn more about the `amore` cli and its capabilities use: ```sh amore --help ``` ## Release {% youtube "pmNKBp3VhFM", "Releasing a macOS app with one amore release command", "From Xcode project to published, notarized app with a single command. Under three minutes." %} If you prefer to use the CLI, instead of Amore's GUI you can use the `amore` cli to release new versions of your app. This command is able to release .app bundles, .dmg files, .zip archives, Xcode archives and archiving directly from Xcode projects/workspaces. In a single command `amore release` takes care of: 1. Archiving your app 2. Exporting the archive 3. Codesigning your executable 4. Creating an [installer DMG](/help/dmg-creation) (optional) 5. Notarizing your app 6. Signing your app for the Sparkle updater 7. Creating a new `appcast.xml` 8. Uploading your app binary for distribution ```sh amore release /path/to/App.xcodeproj --scheme MyApp # You can omit the path when executing `amore` from inside your project folder amore release --scheme MyApp ``` Alternatively you can use the `amore release` command to release your already built app or DMG image. ```sh amore release /path/to/App.app amore release /path/to/App.dmg ``` ## Coding Agents If you let Claude Code or another coding agent drive your releases, install the [Amore agent skill](/help/agent-skill/). It gives the agent the CLI plus Amore's documentation as context, so it follows the documented flows instead of inventing them. # Agent Skill Source: https://amore.computer/help/agent-skill/ Everything you can do in the Amore app you can do from the [command line](/help/command-line/). The Amore agent skill is the AI-friendly companion to the CLI: a Claude Code plugin that lets coding agents interact with Amore using the `amore` command, with Amore's documentation loaded as guidance. To set it up, copy this prompt and paste it into Claude Code, Cursor, or any coding agent working in your project folder: {% include "ai-setup.html", label: "Copy setup prompt" %} ## Install Install the skill from the [amore-skill repository on GitHub](https://github.com/AmoreComputer/amore-skill). Follow the README for the exact `claude` install command. ## Use Once installed, you can ask Claude Code and other agents to release a new version, set up licensing, or wire up Sparkle, and the agent will follow Amore's documented workflows instead of guessing. ## Docs as markdown Every page under `amore.computer/help` is available as clean markdown: add `.md` to the URL, for example [amore.computer/help/get-started.md](/help/get-started.md). Point your agent at these when it needs deeper detail on a specific topic. # Custom Domain Source: https://amore.computer/help/custom-domain/ Amore allows you to use a custom domain for your app's `appcast.xml` and download link. Once set up, your users will fetch updates and downloads from your domain, not Amore's. **It's recommended to set up a custom domain for your app to prevent vendor lock-in.** # Requirements - Amore+ Subscription - App using the Amore storage backend - A domain you can use # Setup To set up a custom domain for your app navigate to the `General` settings in the sidebar, enter a domain in the `Custom Domain` section and click `Save`. For example, you want to use `updates.example.com` as custom domain for your app. Enter `updates.example.com` in the Amore custom domain settings and add the following record in your domain's DNS settings: | DNS Record Type | Name | Target | | --------------- | ------- | ------------------ | | CNAME | updates | api.amore.computer | After you set this up, Amore will periodically check if you set the correct DNS records in the upper right corner of the custom domain settings pane. Once everything is set up, you should see a green checkmark. # GitHub Actions Source: https://amore.computer/help/github-actions/ Amore's [release-action](https://github.com/AmoreComputer/release-action) runs the full release on a GitHub-hosted Mac runner: it archives, code signs, notarizes, signs the update for Sparkle, updates your `appcast.xml` and publishes, no local Mac required. Push a version tag like `v1.2.0` and a signed, notarized release ships automatically. Tag a prerelease like `v1.2.0-beta.1` and it goes out on your beta channel instead. ## Video {% youtube "9TOZkZyRnow", "Automating macOS releases with GitHub Actions and Amore", "The full CI release: a version tag triggers archive, code signing, notarization and publishing on a GitHub-hosted Mac runner, no local Mac. About seven and a half minutes." %} ## The workflow file Create `.github/workflows/release.yml` in your app's repo. Set the `scheme` to yours and pin `xcode-path`/`runs-on` to the toolchain your app builds with; the rest works as-is: {% raw %} ```yaml name: Amore Release run-name: Release ${{ github.ref_name }} on: push: tags: ['v*'] concurrency: group: amore-release cancel-in-progress: true jobs: release: runs-on: macos-26 steps: - uses: actions/checkout@v4 - name: Read version from tag id: version run: | ref="${GITHUB_REF_NAME#v}" echo "number=${ref%%-*}" >> "$GITHUB_OUTPUT" - uses: AmoreComputer/release-action@v1 with: # Pin Xcode to the version your project builds with, so a runner # default drifting can't silently break your build. scheme: Pomodoro codesign-identity: ${{ secrets.CODESIGN_IDENTITY }} dev-id-cert-p12: ${{ secrets.DEV_ID_CERT_P12 }} dev-id-cert-password: ${{ secrets.DEV_ID_CERT_PASSWORD }} sparkle-private-key: ${{ secrets.SPARKLE_PRIVATE_KEY }} asc-api-key-id: ${{ secrets.ASC_API_KEY_ID }} asc-api-issuer: ${{ secrets.ASC_API_ISSUER }} asc-api-key: ${{ secrets.ASC_API_KEY }} amore-token: ${{ secrets.AMORE_TOKEN }} channel: ${{ contains(github.ref_name, '-') && 'beta' || '' }} marketing-version: ${{ steps.version.outputs.number }} ``` {% endraw %} The release-action builds a DMG installer, which carries a `Built with amore.computer` watermark. It is not removed automatically: with [Amore+](/pricing/) you can turn it off (see [DMG watermark](/help/dmg-creation/#watermark)). ## Add your secrets Add each of the values below in your repo under `Settings` → `Secrets and variables` → `Actions` → `New repository secret`. See [using secrets in GitHub Actions](https://docs.github.com/en/actions/how-tos/security-for-github-actions/security-guides/using-secrets-in-github-actions) for the details. ### App Store Connect API key (notarization) Notarization uses an App Store Connect API key. It gives you three secrets in one go. 1. Open [App Store Connect → Users and Access → Integrations](https://appstoreconnect.apple.com/access/integrations/api) and select the `App Store Connect API` tab. 2. Click the `+` to generate a key. Name it (e.g. `Amore CI`) and give it the `Developer` role. 3. Copy the `Issuer ID` shown above the table → `ASC_API_ISSUER`. 4. Copy the `Key ID` from the new row → `ASC_API_KEY_ID`. 5. Click `Download` to get the `AuthKey_XXXXXXXX.p8` file. You can only download it once. Base64-encode it and paste the result into `ASC_API_KEY`: ```sh base64 -i AuthKey_XXXXXXXX.p8 | pbcopy ``` [Apple's guide to creating API keys](https://developer.apple.com/documentation/appstoreconnectapi/creating-api-keys-for-app-store-connect-api). ### Developer ID certificate (code signing) Signing uses your `Developer ID Application` certificate. If you don't have one yet, create it first (see [Codesigning](/help/codesigning/#codesign-identity)). Export it straight from Xcode, no Keychain Access needed: 1. In Xcode, open `Settings` → `Accounts`, select your Apple ID, then pick your team and click `Manage Certificates`. 2. Control-click your `Developer ID Application` certificate → `Export Certificate`. Save it as a `.p12` and set a password. That password is `DEV_ID_CERT_PASSWORD`. 3. Base64-encode the `.p12` and paste it into `DEV_ID_CERT_P12`: ```sh base64 -i Certificate.p12 | pbcopy ``` Your `CODESIGN_IDENTITY` is the full `Developer ID Application: Your Name (TEAMID)` string. List yours in Terminal and copy it from the output: ```sh security find-identity -v -p codesigning | grep "Developer ID Application" ``` ### Sparkle signing key (updates) `SPARKLE_PRIVATE_KEY` is the base64 Ed25519 private key that signs your updates so existing installs trust them. It is the same key Amore stores in your keychain, do not generate a new one or users won't be able to update. Get it either way and paste the result into the secret: - **From the [CLI](/help/command-line/):** ```sh amore export sparkle-key --bundle-id com.example.YourApp ``` - **From the app:** copy the base64 private key from [Key Management](/help/key-management/). ### Amore token (publishing) `AMORE_TOKEN` is a scoped API key that lets CI publish releases to your Amore-hosted app. Create it in the app: open `Amore` → `Settings…` (`⌘,`) and scroll to `API Keys`. Click `New Key`, name it (e.g. `GitHub Actions`), pick the `Release` scope (enough for CI), and click `Create`. Copy the secret token and paste it into `AMORE_TOKEN`. See [API Keys](/help/api-keys/) for scopes and how to revoke a key. ### Provisioning profile If your app uses a restricted entitlement like Associated Domains, iCloud or Push Notifications, the export additionally needs a Developer ID provisioning profile. Create it once, add it base64-encoded as `AMORE_PROVISIONING_PROFILE`, and pass it in the step: {% raw %} ```yaml provisioning-profile: ${{ secrets.AMORE_PROVISIONING_PROFILE }} ``` {% endraw %} See [Provisioning Profiles](/help/provisioning-profiles/) for more information. ## Running a release Tag a commit and push the tag: ```sh git tag v1.2.0 git push origin v1.2.0 ``` - **`v1.2.0`** → stable release, published as version 1.2.0. - **`v1.2.0-beta.1`** → beta release on your beta channel. The version comes from the tag and the build number is assigned automatically, one past your last release, so there is nothing to bump by hand. ## Self-hosted S3 storage By default your releases are hosted by Amore. To publish to your own S3-compatible bucket (AWS S3, Cloudflare R2, MinIO) instead, add these inputs to the `release-action` step: {% raw %} ```yaml s3-bucket: my-app-releases s3-region: us-east-1 s3-public-url: https://cdn.example.com aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} ``` {% endraw %} Add `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY` as repository secrets, and keep `amore-token`; it stays required in S3 mode. For Cloudflare R2 or MinIO, set `s3-region: auto` and add `s3-endpoint: https://.r2.cloudflarestorage.com`. See [Self-Managed S3-Bucket](/help/s3-bucket/) for the full bucket setup. # Why Your Mac App Icon Looks Too Big (and How to Fix It) Source: https://amore.computer/help/why-your-mac-app-icon-looks-too-big/ Most new Mac developers make the mistake of exporting their icon from Icon Composer and then using the resulting PNG as their app icon. ## Problem This results in app icons that look overly large in certain situations and on older macOS versions like Sequoia. For example: ![Icon Composer](/assets/images/help/why-your-mac-app-icon-looks-too-big/problem.webp) ## Solution To fix this, we can just drag and drop our generated `AppIcon.icon` directly into Xcode ![Xcode with AppIcon.icon](/assets/images/help/why-your-mac-app-icon-looks-too-big/xcode-icon.webp) We then just need to make sure that in our target under »General« we set the »App Icon« name to the file name of our generated app icon. ![Xcode with AppIcon.icon](/assets/images/help/why-your-mac-app-icon-looks-too-big/xcode-project-setting.webp) ## Icon Composer Inside Icon Composer, you can right-click on the file name to see where your `.icon` file is stored. ![Icon Composer](/assets/images/help/why-your-mac-app-icon-looks-too-big/icon-composer.webp) Having the `.icon` file in Xcode has the advantage that you can open the Icon Composer right from Xcode and can commit it to your git repository. # How to Test Your App on Different macOS Versions Source: https://amore.computer/help/how-to-test-your-app-on-different-macos-versions/ When you distribute your app, your users may be running different macOS versions. Testing on multiple versions helps you catch compatibility issues before your users do. The easiest way to do this without needing extra hardware is by running a virtual machine with [VirtualBuddy](https://github.com/insidegui/VirtualBuddy). ## What is VirtualBuddy? VirtualBuddy is a free, open-source macOS app that lets you create and manage macOS virtual machines using Apple's `Virtualization` framework. It supports running macOS Monterey (12) and later, so you can test your app across a wide range of versions. ## Requirements - A Mac with Apple Silicon - macOS Ventura (13) or later on the host machine - Enough free disk space for the macOS installer and VM (~30-60 GB per VM) ## Setting Up a Virtual Machine 1. Download [VirtualBuddy](https://github.com/insidegui/VirtualBuddy) from GitHub 2. Open VirtualBuddy and create a new virtual machine 3. Select the macOS version you want to install. VirtualBuddy will download the restore image for you 4. Follow the on-screen setup to complete the macOS installation You can create multiple VMs for different macOS versions to cover your supported range. ## Quick Testing With a Built App If you don't need the full development environment, you can copy a built app into the VM instead. VirtualBuddy supports shared folders between your Mac and the virtual machine, so you can quickly move your `.app` bundle or `.dmg` into the VM for testing. Alternatively, you can drag and drop files directly into the VM window. ## Developing Directly Inside the VM You can install Xcode inside the VM and build, run, and debug your app there, just like on your host Mac. This works on macOS 15 (Sequoia) or later VMs and supports apps with iCloud and other Apple service entitlements. 1. Install Xcode inside the VM from the App Store or [developer.apple.com](https://developer.apple.com/xcode/) 2. Open System Settings and sign in with your Apple Account 3. Open Xcode and add your Apple Account under Settings → Accounts 4. Access your project through a shared folder and build and run as usual This gives you the full development experience — breakpoints, console output, and profiling — on whichever macOS version the VM is running. ## Tips - Test both your oldest supported macOS version and the latest one - Pay attention to deprecated APIs that may behave differently across versions - Use shared folders to access your project source code inside the VM — no need to clone your repository separately # Provisioning Profiles Source: https://amore.computer/help/provisioning-profiles/ Most Developer ID apps ship without a provisioning profile. Some entitlements, Apple calls them restricted, only work when a profile that authorizes them is embedded in the app. Associated Domains (`applinks:`, `webcredentials:`) is the common one; iCloud, Push Notifications and App Groups are others. If your app carries one of these entitlements, a release fails with: ``` The app's entitlements require a provisioning profile. ``` On CI this usually surfaces at the export step: the archive builds fine, and xcodebuild only demands the profile when it re-signs the app for Developer ID distribution. ## Create a Developer ID provisioning profile You only need do this once. 1. Open [Certificates, Identifiers & Profiles → Identifiers](https://developer.apple.com/account/resources/identifiers/list) and make sure your app's identifier has the capability enabled 2. Switch to [Profiles](https://developer.apple.com/account/resources/profiles/list) and click the add button (+). 3. Under `Distribution`, select `Developer ID` and continue. 4. Select your App ID, then select your `Developer ID Application` certificate. It must be the certificate you sign releases with (the one behind `DEV_ID_CERT_P12` in [GitHub Actions](/help/github-actions/), or your [codesign identity](/help/codesigning/#codesign-identity)). 5. Name the profile (e.g. `YourApp Developer ID`) and download the `.provisionprofile` file. ## Use it in GitHub Actions Base64-encode the profile and add it as a repository secret named `AMORE_PROVISIONING_PROFILE`: ```sh base64 -i YourApp.provisionprofile | pbcopy ``` Then pass it to the [release-action](/help/github-actions/) step: {% raw %} ```yaml provisioning-profile: ${{ secrets.AMORE_PROVISIONING_PROFILE }} ``` {% endraw %} ## Use it with the CLI Pass the file directly: ```sh amore release --provisioning-profile YourApp.provisionprofile ``` Or provide it base64-encoded via the `AMORE_PROVISIONING_PROFILE` environment variable, which is what the GitHub Action does under the hood. Either way, Amore derives the signing identity from the profile's own certificates, signs the archive and export manually, and embeds the profile in the app. The whole release runs offline, with no contact to Apple's provisioning service. ## Why Amore cannot fetch the profile automatically On your Mac, where Xcode has an Apple ID session, Amore lets `xcodebuild` fetch missing profiles automatically and no setup is needed. On CI you would expect App Store Connect API credentials to do the same through `xcodebuild`'s cloud signing, and Amore does try exactly that. But Apple's provisioning service currently rejects API-key authentication for Developer ID certificates, regardless of the key's role: even Admin keys fail with `Cloud signing permission error`. Apple has confirmed this limitation ([FB16835802](https://developer.apple.com/forums/thread/776036)). Until it is fixed, a pre-created profile is the only fully headless path, and your ASC key can stay at the `Developer` role it needs for notarization. ## When the profile stops working A profile is invalidated when the certificate it references expires or is revoked, or when you change the entitlements it authorizes. In those cases, regenerate the profile with the same steps and update the secret. Nothing else changes. # Sparkle Sandboxing Guide Source: https://amore.computer/help/sparkle-sandboxing/ This guide shows how to integrate Sparkle into a sandboxed app using the `App Sandbox (com.apple.security.app-sandbox)` entitlement. If this guide does not meet your requirements, you can learn more in [Sparkle's sandboxing guide](https://sparkle-project.org/documentation/sandboxing/). ## XPC Services Sparkle uses 2 XPC services inside the framework to update your application: - Installer.xpc - Downloader.xpc ### Installer The installer service is required to update your application when sandboxed. You enable this service by setting the `SUEnableInstallerLauncherService` to `YES` in your Info.plist file. ```xml SUEnableInstallerLauncherService ``` To allow your app to communicate with Sparkle's installer services, you need to add the following temporary exceptions to your `.entitlements` file: ```xml com.apple.security.temporary-exception.mach-lookup.global-name $(PRODUCT_BUNDLE_IDENTIFIER)-spks $(PRODUCT_BUNDLE_IDENTIFIER)-spki ``` ### Downloader For Sparkle to be able to fetch and download new updates, your application needs the Outgoing Client Connections (`com.apple.security.network.client`) entitlement. You can either enable the checkmark in Xcodes under Signing & Capabilities or add the following to your entitlements file: ```xml com.apple.security.network.client ``` # FAQ Source: https://amore.computer/help/faq/ ## Is Amore free? Amore will always be free for [*FOSS*](/foss/) projects without limitations. If you are working on one and are interested to use Amore for free please [reach out to me](mailto:xoxo@amore.computer?subject=Amore). For everyone else, there will be a free tier which limits some of Amore's functionality: - [DMGs](/help/dmg-creation/) will contain a 'Built with Amore' watermark. - Limits developers to update their apps once a month. - Only the latest release available for download. - Developers won't be able to use Amore with a [custom domain](/help/custom-domain/). For all features and unlimited apps I currently plan an annual **99$** subscription. ## Can I use my own S3 bucket? Amore is primarily designed around DX and convenience, which is why the initial version used Amore's server to host Sparkle's `appcast.xml` and releases. This gives us more freedom to experiment with advanced Sparkle features like download analytics and [anonymous system profiling](https://sparkle-project.org/documentation/system-profiling/) and more. Amore's intent is not to lock you in. It currently provides the option to use a custom domain to serve the `appcast.xml` so you stay in full control. If you want even more control, or need to use an existing S3 bucket you can do that too. [Learn More](/help/s3-bucket) ## Can I install Amore with Homebrew? Yes. Amore is available as an official [Homebrew](https://brew.sh) cask. ```sh brew install amore ``` The cask also links the `amore` [command-line tool](/help/command-line/), so it's ready to use in your terminal right after install. Amore still updates itself via Sparkle, so `brew upgrade` mostly just bumps the cask metadata while Sparkle handles the actual app update on next launch. ## How does licensing work? Amore's licensing system lets you sell license keys for your macOS app through Stripe. You create a product, connect your Stripe account, integrate the AmoreLicensing SDK, and share a checkout link with your customers. When a customer completes a purchase, they receive their license key via email and can activate it in your app. [Learn More](/help/licensing/) ## Can I sell in-app without the App Store? Yes. StoreKit is App Store only, but you don't need it. `AmoreCheckout` presents Stripe checkout in a sheet inside your app, fetches the license key when payment clears, and activates it for you. Your customer clicks buy and the app unlocks, with no browser detour, no key to paste, no App Store cut, and no review. [Learn More](/help/in-app-purchases/) ## Can I use Paddle or another merchant of record? You don't need one. Stripe can be the merchant of record itself through [Stripe Managed Payments](https://docs.stripe.com/payments/managed-payments): it calculates, collects, and remits VAT and sales tax worldwide, and takes on fraud and chargebacks. It's a setting in your own Stripe account, so there is no reseller between you and your customers, and Amore licensing works with it unchanged. Selling directly and handling tax yourself stays an option. [Learn More](/licensing/) # In-App Purchases Without the Mac App Store Source: https://amore.computer/blog/in-app-purchases-without-the-mac-app-store/ If you ship your Mac app outside the App Store, you give up StoreKit. There is no `Product.purchase()` waiting for you, no App Store sheet, no receipt validation. Apple's in-app purchase framework only works for apps distributed through Apple's store, and there is no independent-developer edition of it. That does not mean you have to send people to a browser to buy your app. It just means you have to assemble the flow yourself, and most people assemble a worse one than they need to. ## Why sell outside the store at all The Mac App Store takes 30% of every sale, or 15% if you qualify for the Small Business Program. That's the number everyone quotes, but the developers I talk to rarely leave over the money alone. They leave because App Review gates every bug fix, because sandboxing rules out what their app actually does, or because they want to know who their customers are. If you're weighing that trade-off, I wrote a longer piece on [distributing a Mac app outside the App Store](/blog/distribute-macos-app-outside-app-store/). This post is about the part that comes after you've decided: getting paid. ## What you actually have to build Selling a license yourself means owning four things that StoreKit handled for you: 1. **Payments.** Taking a card, handling subscriptions, refunds, and failed renewals. 2. **Tax.** VAT and sales tax in every jurisdiction you sell into. 3. **License keys.** Issuing them, delivering them, and revoking them. 4. **Activation and validation.** Deciding, on a Mac that might be offline, whether this copy is paid for. Miss any one and you feel it. Skip tax and you eventually get a letter. Skip validation and your app shows up on a warez site with a keygen next to it. ## The options, honestly **A merchant of record** like Paddle or Lemon Squeezy takes payments and tax off your plate entirely, in exchange for a percentage that typically lands in the mid single digits plus a fixed fee per transaction. Cheaper than the App Store, more expensive than Stripe, and you get a reseller sitting between you and your customer. **Gumroad and similar** are the fastest thing to set up and the most expensive to keep. Fine for a first hundred sales, painful at a thousand. **Stripe directly** is the cheapest per transaction by a wide margin, and it leaves you holding items 3 and 4 on that list, plus tax unless you switch on Stripe's managed payments, which makes Stripe itself the merchant of record. **Rolling everything yourself** is a weekend to prototype and a permanent part-time job to run. Key servers get DDoSed, signing keys leak, grace periods turn out to matter the first time your server has an outage while a customer is on a plane. There's no universally right answer here. But notice that all four leave the same hole. ## The hole: the browser handoff Whatever you pick, the default integration looks like this. Your app shows a paywall with a Buy button. The button opens a browser. Your customer pays. A key arrives by email, eventually. They find the email, copy the key, switch back to your app, and paste it into a text field. Count the exits. Any tab they already have open, any notification, any point where the email is slow or lands in spam. Every one of those steps loses a fraction of the people who had already decided to pay you. The ones who make it through are also the ones who write to you when the email doesn't arrive, so the flow costs you support time on top of conversions. The App Store version of this is one sheet and a Touch ID prompt. That gap is the real cost of leaving the store, and it's much bigger than 30%. ## What a good flow looks like instead You can close that gap without StoreKit. The pieces: - **Checkout inside the app.** An embedded web view presenting the payment page, so the purchase happens in a sheet rather than in Safari. Sandboxed apps need the outgoing-connections entitlement for this. - **Automatic activation.** When payment clears, the app fetches the key and activates it itself. The customer never sees a license key unless they go looking for one. - **Reactive unlocking.** Your gate is an observable license status, so the UI unlocks the moment activation succeeds instead of asking anyone to restart. - **Interrupted purchase recovery.** This is the one people forget. If the app quits after the card is charged but before the license is stored, you need to resolve that session at next launch, and you need starting a new purchase to join the existing session rather than charging again. Get this wrong and you will double-charge someone. - **Offline validation.** A signed token checked locally, with a grace period, so an outage on your side doesn't lock out paying customers. - **A browser escape hatch.** Apple Pay requires the external browser, and some customers just prefer it. The app should activate the license either way. None of that is exotic. It's just several days of work that has nothing to do with the app you actually wanted to build, and the failure modes only show up in production with real money attached. ## Doing it with Amore This is the flow [Amore](/) ships. Licensing gives you keys, activation, offline validation, and a customer portal on top of your own Stripe account. [AmoreCheckout](/help/in-app-purchases/) is the part that keeps the purchase inside your app. The integration is one modifier: ```swift import AmoreCheckout let checkout = AmoreCheckout(licensing: licensing) ``` ```swift @State private var buying: Product? Button("Buy Pro") { buying = product } .amoreCheckout(item: $buying, checkout: checkout) ``` When payment completes, the key is fetched and activated on that Mac, and `licensing.status` flips to `.valid`, so anything you gate on it unlocks by itself. Recovery for an interrupted purchase is one call at launch: ```swift await checkout.recoverPendingPurchase() ``` Starting checkout guards the same pending session, so a customer who buys again before recovery runs joins the existing purchase instead of paying twice. The sheet is a thin layer over an observable object, so if you'd rather build your own paywall, your own success screen, or run checkout in the external browser, you drive the same object and get the same activation. The [in-app purchases guide](/help/in-app-purchases/) covers each of those, and [Pomodoro](https://github.com/AmoreComputer/Pomodoro) is an open-source Mac app with the whole thing wired up, updates included. On cost: payments run through your own Stripe account at Stripe's rates, and Amore's licensing adds 1.5% of monthly tracked revenue once you're over $1,000 in a month, nothing below that. If you want to be out of the tax business, Stripe Managed Payments makes Stripe the merchant of record and the integration doesn't change. The catch worth naming: this is Stripe-only, so if you're committed to a different reseller, it isn't for you. ## The short version StoreKit is off the table outside the App Store, but the thing StoreKit is actually good at, buying without leaving the app, is reproducible. Embedded checkout, automatic activation, and honest handling of interrupted purchases get you most of the way to a first-party feel while keeping your margin, your release schedule, and your customer list. [Get started with in-app purchases](/help/in-app-purchases/) or read the [licensing guide](/help/licensing-guide/) first if you haven't set up products yet. # With Amore №6 Source: https://amore.computer/blog/6/ Hi friends, This is the sixth issue of »With Amore«, which I use to keep you in the loop about significant project milestones and updates. In June and July, the focus was on improving Amore for teams and CI pipelines. Additionally, Amore's Swift SDK, AmoreKit, got numerous updates, like in-app purchases and cross-platform support. ### Amore for Teams Amore is used by multiple teams, like [Monologue](https://monologue.to) by Every. In the past, the Monologue team would ship new code, and the product owner had to go through the Amore CLI or Amore Mac app to manually release a new version. That person quickly became the bottleneck of the team. As commonly known in software engineering, short feedback loops are essential for fast shipping teams. To fix this, the Amore CLI got reworked to be fully usable in CI/CD environments. It now has the option for multiple release channels and supports Amore API keys so the whole Amore pipeline can be automated in the cloud. In addition, there's now a [GitHub release action](https://amore.computer/help/github-actions/) to make it easy to automate the release of any macOS project that's hosted on GitHub. It's highly customizable and includes instructions to automatically publish new releases on an alpha or beta channel after pushing to `main` and to the stable channel after adding a release tag. It's already been used by multiple teams and individuals to release continuously. ### AmoreCheckout In May, Amore added a fully functional licensing system (`AmoreLicensing`) that's already used by a dozen apps. One drawback compared to the Mac App Store was that it used the traditional Mac licensing approach. The app would link to a pricing or checkout page, causing the user to leave the app to open a browser. The customer would then input their credit card information and get a licensing key via email, which they manually have to copy and paste back into the app to activate their license, causing support requests and lowering the conversion rate. [AmoreCheckout](https://docs.amore.computer/documentation/amorecheckout) is the latest addition to [AmoreKit](https://github.com/AmoreComputer/AmoreKit) which provides in-app purchases to every Mac app using `AmoreLicensing`. It's an optional addition that enables a smooth checkout experience that happens completely inside your app. It's highly customizable and automatically activates the license after a successful purchase. You can see the whole experience in Amore's open-source demo project, [Pomodoro](https://github.com/AmoreComputer/Pomodoro). ### AmoreKit In addition to `AmoreCheckout`, various parts of the Swift SDK, `AmoreKit` received little updates. It now exposes more information about the user's license, like their email address, and makes all licensing data available synchronously at launch. It also got lighter by dropping the heavy `JWTKit` dependency. `AmoreLicensing` is now platform-independent and can be used on any platform Swift compiles for, not just macOS. ### Onboarding & Docs Like announced in the last post, the Mac app's onboarding experience improved to make it easier for new users to get started. Additionally, the [agent skill](https://github.com/AmoreComputer/amore-skill) got updated, and I added better agent instructions on [amore.computer](https://amore.computer) to make adding an app to Amore even easier. ### Built with Amore Like in previous months, I want to thank early supporters and adopters of this project that helped shape Amore into the tool it is today. ***[Billy](https://usebilly.app)*** Billy is a delightful invoice manager crafted with love for all the freelancers and small businesses that want their bureaucracy to be a little more organized and beautiful. It's one of the best new Mac apps I have seen this year. ***[Notch](https://notch.two.supply)*** Notch is a delightful little app that makes it easy to add inspiring artifacts from your Mac to your [Are.na](https://are.na) spaces. ### What's Next? For the rest of the summer, I plan to improve the help docs and create more videos about various advanced Amore features to make it easier for developers to get started and get the most out of Amore. Additionally, I am still keen to look into an app directory and app landing pages. This will require some thinking and working closely with other developers, which I am looking forward to. I would like to personally onboard more developers to AmoreLicensing. If you consider Amore as your licensing system, reply to this email to get in touch. I would love to talk to you. xoxo\ Lucas # With Amore №5 Source: https://amore.computer/blog/5/ Hi friends, This is the fifth issue of »With Amore«, which I use to keep you in the loop about significant project milestones and updates. In May the focus was on improving the licensing & payments system for the first couple of developers that implemented it into their apps. ### Amore Licensing One of the most significant changes this month is that Amore's licensing system does not require an Amore+ subscription anymore, making it absolutely free to get started. **Only pay in months you earn over $1,000. Thereafter, it's 1.5% of your total monthly tracked revenue**. [Learn More](https://amore.computer/licensing/) ### App & CLI The biggest change in the app and CLI last month was the license manager, making it possible to view and manage issued licenses for your apps. This makes it possible to see who your customers are and to help them with possible support requests. You can see all license data and can revoke licenses and device activations. Additionally, you can now issue licenses right from inside the app. Perfect for testing and giveaways. DMGs are now created faster and more reliably and don't open a new Finder window during the creation process. ### AmoreKit It was a good month for [AmoreKit](https://github.com/AmoreComputer/AmoreKit/releases). It got implemented in a couple of apps that, since then, shipped. Not only that, but it received its first open-source contribution, making it more powerful and flexible. Thanks to a new protocol, it's now possible to bring your own token storage. Licenses now expose the product that they are valid for. Additionally, licenses include the current state of a connected subscription, making it possible to detect if a license is still valid but cancelled, for example. Finally, AmoreKit gained a new [`AmoreStore`](https://docs.amore.computer/documentation/amorestore) library that can be used to fetch products, their prices, and checkout URLs. This makes it possible to build paywalls that use the SDK as a single source of truth. ### Homebrew Amore is now on Homebrew and can be installed via `brew install amore`. ### What's Next? In June I plan to improve the help docs and onboarding experience to make it easier for new developers to get started. Additionally, I am keen to look into an app directory and app landing pages. This will require some thinking and working closely with other developers, which I am looking forward to. I would like to personally onboard more developers to AmoreLicensing. If you consider Amore as your licensing system, reply to this email to get in touch. I would love to talk to you. xoxo\ Lucas # With Amore №4 Source: https://amore.computer/blog/4/ Hi friends, This is the fourth issue of »With Amore«, which I use to keep you in the loop about significant project milestones and product updates. In March and April the focus was on the licensing & payments system, which got polished and is now publicly available. This is the biggest update since Amore was launched and marks the end of phase 2 outlined in the original essay about [My Vision for macOS App Distribution](https://lucas.love/blog/vision-macos-app-distribution). ### Licensing & Payments It was important to make the Amore licensing system approachable for indie hackers and hobbyists, which is why you can start to use the new Amore licensing system for free. **Only pay in months you earn over $1,000. Thereafter, it's 1.5% of your total monthly tracked revenue (MTR)**. [**Learn More**](https://amore.computer/licensing/) Amore's licensing system includes unlimited access to: - Product checkout page - License key generation - Purchase/subscription success page with license key - Email delivery of license key - AmoreLicensing Swift SDK - License activation and validation server To get started, all you need to do is integrate the [AmoreLicensing SDK](https://amore.computer/help/licensing-guide/#integrate-amoramore.computer) into your app and connect your Stripe account to Amore. If you prefer to learn from a working example, I put together [Pomodoro](https://github.com/AmoreComputer/Pomodoro), a small SwiftUI app that shows the full Sparkle + licensing setup end-to-end. ### Agent Skill Everything you can do within the Amore app, you can do via the command line. This includes the new licensing system and product configuration. Because this is the only way some developers interact with Amore, we created a Claude Code plugin and agent skill you can use to interact with Amore with guidance from Amore's documentation. [**Learn More**](https://github.com/AmoreComputer/amore-skill) ### Built with Amore Like last month, I want to thank early supporters and adopters of this project that helped shape Amore into the tool it is today. Here are some of the highlights of the ~50 new apps that started relying on Amore since March. [***SlapMac***](https://slapmac.com) This one has gone quite viral since the end of March. You may have already heard about it. Tonino, the developer, describes his app as »Slap your MacBook. It screams back. That's it. That's the app.« It's a fun little app that already got more than 90k downloads. [***Markdown Preview***](https://markdownpreview.app) One of those apps you should install on every new Mac. It adds native support for Markdown previews to CMD + SPACE and includes a beautiful Markdown document reader. It's free and open-source. Go get it. [***Doorry***](https://altumdream.com/doorry/) Your Mac has more open ports than you think, and most apps never close the ones they used. Doorry lives in the menu bar and shows what's actually listening, with a kill button that works. [***Pluk***](https://pluk.sh) An AI-native macOS database client for Postgres, MySQL, SQLite, MongoDB & Convex. AI does the querying, you explore your data. [***Coca***](https://coca.cammalleri.dev) Keep your Mac from falling asleep with one click! Stay green in all your messengers. [***Peek***](https://mattspear.gumroad.com/l/peekapp) This is a smaller project from my friend Matt. Peek lets you monitor your OpenAI API spending right in the menu bar, with a per-project breakdown in the dropdown. No browser tab, no dashboard – just the number you need. ### What's Next? As the work on the licensing system is complete, I will focus on documentation and help articles to make it easier for new developers to get started. Because Amore now hosts over 100 apps, I was wondering if it could be interesting to have an opt-in app store-like directory of apps. You choose some screenshots and a description and have a landing page you can share. It would include a download and optional payment link. Especially useful for small apps you would rather not build a website for. I would like to personally onboard the first developers to AmoreLicensing. If you consider Amore as your licensing system, reply to this email to get in touch. I would love to talk to you. xoxo\ Lucas # With Amore №3 Source: https://amore.computer/blog/3/ Hi friends, This is the third issue of »With Amore«, which I use to keep you in the loop about significant project milestones and product updates. At the beginning of February, I focused on making the `amore` CLI more powerful and easier to use for humans and their agents. I also made significant progress towards a powerful licensing and payments system. ### CLI In short, the `amore` CLI reached feature parity with the Mac app, which means that everything you can do using the Amore app can now be done in the command line. This is especially useful for automation using scripts or coding agents. One highlight is additions to the `amore release` command, which now allows you to release a new version of your app right from the project folder without the need for manually archiving and notarizing. The currently fastest way to publish new releases with Amore. It's now also possible to let an agent complete the initial Sparkle and Amore setup for your app. The `amore setup` command registers new apps, and with `amore config` you or your agent can change the release settings of your app. Tell your agent about the `amore help` command to get them started. [**Learn More**](https://amore.computer/help/command-line/) ### Licensing & Payments Another big focus in February was the Amore licensing and payments system, which will be publicly available in March. If you are interested, please reply to this email. Early developers get lasting, better conditions before the public release. The licensing system consists of a secure Swift SDK called [AmoreLicensing](https://docs.amore.computer), a licensing server, a self-serve customer portal for your users, and a powerful API for 3rd-party payment providers. Amore currently supports issuing new licenses via CLI, API, and Stripe webhooks. Other payment providers will be added in the future. The user journey for your customers currently looks like this: 1. Optional: The user opens the Amore checkout link for your product, which will redirect to a pre-configured Stripe Checkout session. 2. The user purchases a Stripe product. Both one-time payments and subscriptions are supported. 3. The user gets redirected to an Amore-hosted success page with information about their purchase and freshly issued license key. 4. The user enters their license key in your app. 5. The license gets validated and your app activated. 6. Optional: The user can manage and revoke their license activations in the Amore customer portal by using their email address as an identifier. You can modify the user journey by pre-issuing license keys or using the licensing API to build your own licensing solution. ### Stripe as Merchant of Record I decided to use Stripe as the first 3rd-party payment provider because they now offer to use Link as a Merchant of Record via [Stripe Managed Payments](https://docs.stripe.com/payments/managed-payments). It's easy to set up and fully compatible with Amore. If you prefer to sell licenses directly via Stripe, you can do that too. Amore itself is already using Stripe Managed Payments since November without any issues or complaints. ### Built with Amore Like last month, I want to thank early supporters and adopters of this project that helped shape Amore into the tool it is today. Here are some of the highlights of the 20 new apps that started relying on Amore since last month. - [*SymbolBrowser*](https://stewartlynch.gumroad.com/l/SymbolBrowser) - [*PrettyTimezones*](https://prettytimezones.com/) - [*Juicy*](https://getjuicy.app/) ### What's Next? As the work on the licensing system is almost complete, I will focus on documentation and help articles to make it easier for new developers to get started. I would like to personally onboard the first developers to AmoreLicensing. If you consider Amore as your licensing system, reply to this email to get in touch. I would love to talk to you. xoxo\ Lucas # How to Distribute a macOS App Outside the App Store Source: https://amore.computer/blog/distribute-macos-app-outside-app-store/ If you're building a Mac app, distributing through the App Store isn't your only option. Many of the most popular Mac apps like ChatGPT, Firefox, Sketch, Sublime Text ship directly to users without ever going through App Review. Here's why you might want to do the same, and exactly how to do it. ## Why distribute outside the App Store? The Mac App Store takes a 30% cut of every sale. That's significant, but it's not the only reason developers choose to self-publish: - **No App Review delays.** Ship on your own schedule, not Apple's. - **Direct customer relationship.** You own the relationship and the payment flow. - **Full control.** Use private APIs, kernel extensions, or system-level features that the App Store doesn't allow. - **No sandboxing requirement.** The App Store requires App Sandbox. Outside it, you choose the security model that fits your app. The trade-off is that you need to handle a few things yourself: code signing, notarization, updates, and packaging. Let's walk through each. ## What you need Before distributing outside the App Store, you'll need: 1. **An Apple Developer account** ($99/year) — required for code signing certificates and notarization. 2. **A Developer ID certificate** — this is different from the App Store distribution certificate. 3. **A way to notarize your app** — Apple requires this so macOS doesn't show scary warnings to your users. 4. **An update mechanism** — your users need a way to get new versions. 5. **A distribution format** — typically a DMG installer. ## Code signing and notarization Every Mac app distributed outside the App Store must be signed with a Developer ID certificate and notarized by Apple. Without this, macOS Gatekeeper will block your app or show a warning dialog that scares users away. Notarization is Apple's automated check that your app is free of malware and has been properly signed. The process involves uploading your app to Apple's servers, waiting for approval (usually a few minutes), and then stapling the notarization ticket to your app. You can do this manually with `xcrun notarytool`, or [let Amore handle it automatically](/help/codesigning/). ## Over-the-air updates with Sparkle Without the App Store, you need your own update mechanism so your users don’t have to download your app from your website again once you released a new version. [Sparkle](https://sparkle-project.org/) is the de facto standard for macOS app updates. It's been around for over a decade, is used by thousands of apps, and provides a familiar update experience for Mac users. Sparkle works by checking an RSS-like feed (called an `appcast.xml`) for new versions. When an update is available, it downloads it, verifies the cryptographic signature, and installs it, all with a native macOS UI your users already recognize. Setting up Sparkle involves adding the framework to your project, configuring your `Info.plist` with a feed URL and public key, and hosting the appcast somewhere. You can follow our [step-by-step Sparkle setup guide](/help/sparkle/). ## Creating a DMG installer A DMG (disk image) is the standard way to distribute Mac apps outside the App Store. Users download the DMG, open it, and drag your app to the Applications folder. It's simple and familiar. A good DMG includes a custom background with a visual arrow pointing from your app icon to the Applications folder. The DMG itself should be code-signed and notarized so users don't see any warnings. Creating DMGs manually with `hdiutil` and setting up the background and layout is tedious. [Amore creates DMG installers automatically](/help/dmg-creation/) as part of the release process. ## Putting it all together Each piece — code signing, notarization, Sparkle updates, DMG creation — is well-documented individually. The challenge is wiring them all together into a reliable release workflow. That's exactly what [Amore](/) does. It's a Mac app and CLI that handles the entire release pipeline: 1. Code-sign your app with your Developer ID 2. Notarize with Apple 3. Create a DMG installer 4. Sign the update for Sparkle 5. Generate the `appcast.xml` 6. Upload everything for distribution You can do this through the GUI by dragging your app in, or with a single CLI command: ```sh amore release --scheme Acme ``` [Get started with Amore in under 5 minutes](/help/get-started/). It's free for open-source projects and has a free tier for everyone else. # With Amore №2 Source: https://amore.computer/blog/2/ Hi friends, This is the second issue of »With Amore«, which I plan to use to keep you in the loop about significant project milestones and product updates. Since the first issue 4 weeks ago, I have been working closely with several developers to make Amore easier to use and to support more use cases. Almost every feature now has a dedicated help page on amore.computer which you can find right inside the app. ### WhyFi Last weekend my friend [James Potter](https://jamespotter.dev) shared his weekend project [WhyFi](https://whyfi.network) in a [tweet](https://x.com/jamespotter/status/2014977962890936523), which shortly after went viral. All the attention encouraged him to package it up for distribution and start selling it for $10. On the same day, he reached out to me asking if he could have early access. A few hours later he had hundreds of happy customers and confidently published WhyFi with Amore. Through Amore, he already shipped half a dozen of over-the-air updates to improve WhyFi. His success accomplishes my initial vision for this project, which was to help my friends and fellow developers to focus on what they are doing best: building great products instead of wrangling with tedious distribution flows. ### Public Beta After onboarding new developers to the [self-managed S3 bucket feature](https://amore.computer/help/s3-bucket/) and having the first viral app distributed via Amore, it's time to leave the early access phase and open the project for everyone who's interested to self-publish their Mac apps. You can get started today by downloading Amore from [here](https://amore.computer/download). I recommend you use the [Get Started with Amore](https://amore.computer/help/get-started/) guide, which includes a short [video (3:35)](https://cdn.amore.computer/videos/get-started.mp4) that walks you through the steps of self-publishing your first app with Amore. The option to get a personal onboarding still exists. Please reply to this email if you are interested or need help setting things up. ### Amore+ For the time being Amore will be free to use for everyone who wants to get started publishing their Mac apps. To keep this project sustainable, the latest version of the app includes Amore+, which currently is a monthly/yearly subscription of $9.99/99. The subscription currently unlocks: - Unlimited app and releases - Custom domains (when hosting on Amore) - The option to remove the »Built with amore.computer« watermark in the DMG image ### Built with Amore I want to use this opportunity to thank the early supporters of this project that taught me so much and helped shape Amore into the tool it is today. Their apps are all built with Amore in more ways than one. - *Massimo Biolcati*: [iReal Pro](https://www.irealpro.com/) - *Naveen Naidu*: [Monologue](https://www.monologue.to/) - *James Potter*: [WhyFi](https://whyfi.network/) - *Alberto Gallego*: [Picmal](https://picmal.app/) - *Konstantin*: [Browski](https://iamkonstantin.eu/blog/meet-browski-a-browser-companion-for-the-mac/) ### What's Next? A common theme with developers in onboarding calls has been confusion around some of Amore's features, like [DMG creation](https://amore.computer/help/dmg-creation/), which felt a bit too magical. I am currently working on demystifying and better communicating what Amore is doing and exposing previously implicit behavior as explicit settings in the UI and documenting it. After this work has been done, I want to focus on developer feedback and look into 2 areas more deeply. The first area is payments and licensing for apps, so developers can use Amore to earn money. The second one is to build pretty download pages for apps hosted on Amore and possibly have an index of apps to help developers get more attention for their projects. xoxo\ Lucas # With Amore №1 Source: https://amore.computer/blog/1/ Hi friends, This is the first issue of »With Amore«, which I plan to use to keep you in the loop about significant project milestones and product updates. Since my [blog post](https://lucas.love/blog/vision-macos-app-distribution) back in late November the project evolved into a fully-fledged Mac app that's able to take care of every step of distributing app updates to your users and already has a couple of developers using it. Last week I introduced a new [help page](https://amore.computer/help/) that hosts Amore's documentation and shows how to get started. It's a good way to get an overview of what Amore is currently capable of. I strive to make this one of the best documentations for a developer tool. Let's dive into some of the things Amore can do for you today. ### From Archiving to Releasing To streamline the release process, _Amore_'s [cli](https://amore.computer/help/command-line/) offers a command to be used with [Xcode' archive post-actions](https://amore.computer/help/xcode-post-archive-action/), which will automatically handle every part of the release process after you archived your project. This includes: 1. Exporting the archive 2. Code signing your executable 3. Creating an installer DMG (optional) 4. Notarizing your app 5. Signing your app for the Sparkle updater 6. Creating a new `appcast.xml` 7. Uploading your app binary ### Amore for New Apps The help pages now include a [Get Started](https://amore.computer/help/get-started/) article that describes how to configure a new app for distribution via Amore. The process consists of 3 easy steps: 1. Register app with Amore via drag and drop 2. Configure Sparkle in your project. (Amore can do parts of this automatically) 3. Publish your first release I tested this with multiple developers now and the whole process takes around 10 minutes. ### Amore for Existing Apps Over the last month I did dozens of developer onboarding sessions and learned that developers with existing apps face different problems and would like to keep their existing Sparkle setups. Most of these setups included distribution of updates via the developer's S3 bucket and some custom scripts to create notarized DMGs and upload the result to S3. I am happy to report that Amore now supports the same convenience for apps distributed via S3 buckets. You will be able to use your own S3 bucket from any cloud provider to distribute updates. Only minimal configuration will be required. You won't need to change the source code of your app to get started with Amore. Once setup, Amore can take care of the full release pipeline and you can even edit the `appcast.xml` right from inside Amore. This means you can tweak release notes or change settings like beta channel or phased rollouts without ever leaving Amore. ### Early Access Promo As a thank you for your early support, I offer you the sexy price of $69 per year instead of $99, which won't change, even when I raise subscription prices in the future. You can get it [here](https://amore.computer/early-access-promo). ### What's Next? Currently I am working on the public beta release of Amore and looking for a few developers who are interested in personal onboarding sessions. If that is something that interests you, please reply to this email to get in touch. xoxo\ Lucas