Distribute iOS apps “over the air”

Most app developers have heard the following request at least once in their professional life

I have this cool app idea that would help me in this very special use case. I don’t want to distribute it over the AppStore, it’s enough to have it on my phone only.

If you are writing Android apps, that might not give you any headaches. But that’s different on iOS. “It’s enough to have it on my phone”… As if it were that simple. 🙈

While Swift and SwiftUI make it easy and fun to write apps, distribution is still a pain if you don’t want to use the AppStore. TestFlight makes it possible to distribute apps before the actual release, but it requires you to add the app formally to your account.

Fortunately, there is another way to make apps available on multiple phones without going the TestFlight route.

“Over the air” installation to the rescue

I found a blog post from 2011 by Aaron Parecki that shows how to do that: https://aaronparecki.com/2011/01/21/4/how-to-distribute-your-ios-apps-over-the-air

Big shout-out to Aaron for sharing this great advice. I decided to take this process and make a “2025 version” with up-to-date screenshots.

Step 1: Register target devices

The first thing to do is to register the devices you want to use in your developer.apple.com account. Important: The devices need to have “Developer Mode” enabled to run your apps

Step 2: Create and assign Provisioning Profile

You have to have a provisioning profile that includes your target devices. This is also done on developer.apple.com

This new provisioning profile needs to be imported in Xcode and assigned to your app’s project settings under “Signing & Capabilities”.

Step 3: Build your app archive

When everything is set up, you can build your app archive by clicking the menu item “Product -> Archive“.

This will bring up the “Organizer” showing your new archive.

Step 4: Distribute options and export

Now click “Distribute App” to define the specific options.

In the next step, select the “Custom” option

Now select “Release Testing” to distribute to registered devices

In the next step, check the “Include manifest for over-the-air installation” checkbox. Then click “Next”.

Now, you need three URLs. The first one is the URL that points to your .ipa file. For this example, we will use “https://blog.lars-richter.dev/over-the-air-installation.ipa”. The second URL points to a display image and the third one to a full-size image (ideally 512px x 512px). These three URLs will be placed in the .plist file that will be used to distribute your app later.

Almost there. Now, select your Distribution certificate and the provisioning profile you created in step 2.

After that, Xcode shows a summary of your settings. If everything is fine, click “Export” and select a directory you want to export the .ipa and .plist files to.

Step 5: Upload .ipa and .plist

It’s time to upload the .ipa file to the location you specified earlier. But the .ipa file alone won’t do the trick. You need to make the .plist file available as well.

Step 6: Create a download page

To make Safari download and install an app, we need to use a special download link that uses the “itms-services” protocol. This link needs to point to the .plist file you uploaded in the previous step:

<a href="itms-services://?action=download-manifest&url=https://blog.lars-richter.dev/over-the-air-installation/manifest.plist">Download!</a>

Here is a little HTML page that uses Bulma for some basic styling. Feel free to reuse if you want:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Your over the air installation</title>
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bulma@1.0.2/css/bulma.min.css">
  </head>
  <body>
    <section class="hero is-fullheight">
        <div class="hero-body">
            <div class="container has-text-centered">
                <div class="column is-8 is-offset-2 is-6-widescreen is-offset-3-widescreen">
                    <p class="title is-1">Get this awesome app TODAY!</p>
                    <div class="container">
                        <p class="subtitle is-4">
                            Sollicitudin et nunc dolor, rutrum sapien tempus habitant faucibus. Gravida tristique vivamus, purus amet habitasse integer.
                        </p>
                    </div>
                    <div class="section">
                        <a class="button is-info is-large" href="itms-services://?action=download-manifest&url=https://blog.lars-richter.dev/overtheair/manifest.plist">
                            Download!
                        </a>
                    </div>
                </div>
            </div>
        </div>
    </section>
  </body>
</html>

Step 7: Upload and share the HTML file

That’s the final step. Upload the HTML file to make it available to everyone with a registered device. They can open the link in Safari and install your app without TestFlight or the AppStore.


Posted

in

by

Tags: