Hashdrop

Guide

How to install an .ipa over the air

The mechanism Apple has always supported for installing an app outside the store, what it requires, and the four reasons it usually fails.

You have an .ipa and someone with an iPhone. No TestFlight, no cable, no Xcode. This is the mechanism Apple has supported for that since iOS 4, and it still works — but it has requirements that are easy to miss, and it fails silently when they are not met.

How it works

iOS installs an app from a link with a custom scheme: itms-services. The link points at a manifest — a plist file describing the app — and the manifest points at the .ipa itself.

<a href="itms-services://?action=download-manifest&url=https://example.com/app.plist">
  Install
</a>

The manifest is XML and needs the bundle identifier, version and title to match the build, plus the URL of the .ipa:

<?xml version="1.0" encoding="UTF-8"?>
<plist version="1.0">
<dict><key>items</key><array><dict>
  <key>assets</key><array><dict>
    <key>kind</key><string>software-package</string>
    <key>url</key><string>https://example.com/app.ipa</string>
  </dict></array>
  <key>metadata</key><dict>
    <key>bundle-identifier</key><string>com.example.app</string>
    <key>bundle-version</key><string>1.2.8</string>
    <key>kind</key><string>software</string>
    <key>title</key><string>Example App</string>
  </dict>
</dict></array></dict>
</plist>

The requirements people miss

  1. Both the manifest URL and the .ipa URL must be HTTPS, with a certificate iOS can build a complete chain for. A self-signed certificate, or a chain missing its intermediate, fails with no useful message.
  2. The link must be opened in Safari. Tapping it inside another app's in-app browser usually does nothing at all, which is the single most common report.
  3. The build must be signed with a distribution profile that covers the device.
  4. The bundle identifier in the manifest must match the one in the .ipa.

Ad Hoc versus Enterprise — this is the part that decides everything

With a standard Apple Developer Program account, your build is signed Ad Hoc. An Ad Hoc provisioning profile contains a fixed list of device UDIDs, chosen when the build was signed. A device whose UDID is not in that list cannot install the build, however you send it.

With an Apple Enterprise account, builds install on any device — but that programme is for distributing to your own employees, and Apple enforces that.

This is why "it works on my phone but not my client's" is so common. The answer is almost never the link. It is that their UDID was not in the profile when you signed.

Collecting a UDID

You cannot read a UDID from a phone number or an email address. The device has to tell you, and there are two ways:

Once you have the UDIDs, add them to the Ad Hoc profile in the Apple Developer portal, re-sign the app, and distribute the new build. Devices added after signing are not covered until you re-sign.

The failure that catches everyone

An expired provisioning profile does not stop the app installing. It stops it LAUNCHING. Your tester had it working yesterday; today the icon closes instantly, the crash log says nothing useful, and nothing you change on the server will fix it. Re-sign and ship a new build.

Ad Hoc profiles last a year from the day they are created, not from the day you use them. Note the date somewhere you will see it.

Troubleshooting

What they seeUsually means
"Unable to install"The device's UDID is not in the build's profile
Nothing happens on tapOpened in an in-app browser instead of Safari
"Cannot connect to example.com"The manifest or .ipa is not HTTPS, or the chain is incomplete
Installs, then closes on openThe profile has expired, or the developer is untrusted
"Untrusted Developer"Settings → General → VPN & Device Management, then trust

Doing it without building the plumbing

Everything above is a few hours of work the first time and a recurring chore afterwards: hosting the manifest, keeping the certificate chain intact, collecting UDIDs, and noticing an expiry before it bites.

Hashdrop does that part. Upload an .ipa, send a link, and the manifest, the HTTPS hosting, the device enrolment page and the expiry warnings come with it — including which of your registered devices each build actually covers. There is a free tier.