Building an IPA for the App Store without transferring it directly to App Store Connect

I haven't tried building an IPA for the App Store yet. Is there a way to not transfer this IPA directly to App Store Connect, but instead download it to the computer/Mac first? Because I still have to edit this IPA, which means adding missing assets and then re-signing it.

Reason: My app (IPA) exceeds the allowed limit of 32 MB, so I have to go this way.


Or is there another way?

You should be able to download the Ad Hoc IPA, add your assets, and then resign the bundle using codesign.

1 Like

Thanks for the quick feedback.

  1. I change the file extension of the IPA file from .ipa to .zip and unzip it. (Maybe it is not necessary to rename .ipa to .zip.) In the extracted folder, I find in the Payload folder \myApp.ipa\Payload\myApp.app\appdata.aia\assets\.

  2. I copy the additional files into the assets folder.

  3. Signing with codesign (on my Mac): I open a terminal and navigate to the Payload folder and use the following command to sign the app:
    codesign -f -s "Distribution certificate" "myApp.app"

  4. I create a new ZIP file of the Payload folder and then change the file extension from .zip to .ipa.

This IPA can then be uploaded to the App Store via iTunes Connect [or Xcode])?


Are these steps correct?

If it helps, here's what the server does to sign:

/usr/bin/codesign --force --sign $CERTIFICATE_SHA1 --timestamp=none --entitlements  $ENTITLEMENTS_FILE Payload/PlayerApp.app

where $CERTIFICATE_SHA1 is the SHA1 of the distribution certificate (you should be able to get this from Keychain Access or Xcode) and $ENTITLEMENTS_FILE is a plist file with a name ending .xcent and the contents:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>application-identifier</key>
    <string>your app id</string>
    <key>com.apple.developer.team-identifier</key>
    <string>your team id</string>
    <key>get-task-allow</key>
    <false/>
    <key>keychain-access-groups</key>
    <array>
        <string>your app id</string>
    </array>
</dict>
</plist>

After signing, you then repack the ZIP and name it back to IPA.

For delivery, we use Apple Transporter, which is a Java program you can run on Mac, Windows, or Linux to deliver IPAs to App Store Connect. Details here: Transporter User Guide 3.3

1 Like

Yes, I think you can also name the certificate based on its common name but for us it's easier to use the SHA1. As long as the string you provide uniquely identifies your distribution certificate in Keychain Access it should work.

1 Like

I have to admit that your approach is giving me a bit of a headache. I have to work through it first. At first glance it seems quite complicated to me. :thinking:

It's possible you don't need the entitlements file but I haven't tried it. It's a static file so you could create one and just keep it around somewhere on your system to reference when you need it. Xcode automatically generates one when you build an app so we do that as well, but it is ephemeral and is deleted once the project finishes being compiled on the servers.

1 Like

To be fair, has anything about Apple's process screamed "easy"?

2 Likes

Truly not! However, with Swift / Xcode it is comparatively simple.

1 Like

Which entitlements file?

When we sign the app, we specify an entitlements file (see the codesign command from my post above), which is something that Xcode generates and uses automatically for signing. I do not know whether this is actually necessary or whether you can skip including it in the codesign invocation.

1 Like

Some research revealed the following:
The "entitlements file" is an XML file that defines special permissions and settings for your iOS app. It contains information such as the team ID, application ID, and other permissions your app requires. In many cases, this file is automatically generated by Xcode and used during the app signing process.

Whether you need to explicitly specify the "entitlements file" depends on your app's requirements and the specific instructions you've received. In some cases, especially if you need special permissions or settings, including the "entitlements file" is necessary.

If you don't explicitly specify the "entitlements file," the signing process defaults to using the settings generated by Xcode. In most cases, these default settings are sufficient.


However, how would Xcode know e.g. the application ID, because Xcode knows nothing about the new app. All certificates, identifiers & profiles were only created in the Apple Developer Account. So I guess I won't be able to avoid creating this entitlements file myself. :cry:


So for example:

<plist version="1.0">
<dict>
    <key>application-identifier</key>
    <string>appinventor.ai-bodymindpower.AT-Pro</string>
    <key>com.apple.developer.team-identifier</key>
    <string>RY5XXXXQ2H</string>
    <key>get-task-allow</key>
    <false/>
    <key>keychain-access-groups</key>
    <array>
        <string>appinventor.ai-bodymindpower.AT-Pro</string>
    </array>
</dict>
</plist>

Correct?


Command should then be:

codesign -f -s "Distribution Certificate" -entitlements $ENTITLEMENTS_FILE Payload/PlayerApp.app

`codesign -f -s "AT_AppStore" --entitlements AT_pro_entitlements.plist Payload/PlayerApp.app`

In my case "AT_AppStore.mobileprovision"(so without extension) and AT_pro_entitlements.xml (renamed to AT_pro_entitlements.plist).


I wanted to be a little prepared before using my Mac for the first time again after more than a year and then experiencing too many frustrations. :wink:

If you have only 1 distribution certificate it may be enough to just specify "Distribution Certificate" without having to jump through hoops. The entitlements file is embedded in the app image when it is signed by the buildserver, so it may be that codesign will reuse the content already in the app rather than having to construct one manually. I would suggest trying something like:

codesign -f -s "iPhone Distribution" Payload/PlayerApp.app

and see if it works out of the box like that. It would definitely be the easiest solution if it does.

1 Like

Ok. So I just tried this on the App Inventor companion app and the entitlements section of the app disappeared. However, since we don't specify anything sensitive in the entitlements file it may still pass muster when running the app and submitting it to App Store Connect.

1 Like

Thank you very much for the detailed information! Now I am even better prepared and have several options.