When PhoneGap Build .ipa files need to be re-signed

Update 6/13/2014: Fixed instructions to support XCode 5.1.1

Update 11/4/2015: Fixed filename of the entitlements file (use hyphens, not underscores)

We use PhoneGap Build to compile a number of iOS apps.  It saves us the complexity of setting up and maintaining XCODE/PhoneGap build environments.  We simply upload our web code and corresponding configuration files and get back an .ipa file ready for distribution.

One of our clients uses the app we build for in-house enterprise deployment.  They need a copy of the .ipa file signed with their Enterprise certificate and their provisioning profile.    They said “please just provide us an .xcarchive file so we can open it in the XCODE Organizer and distribute it.”  But all we get from PhoneGap Build is an .ipa file.  So what do we do?

Option 1: Have the client use PhoneGap Build

We discussed with the client the option of them opening a PhoneGap Build account and uploading their certificate to it.  We would then just provide them a zip file ready to build and they’d get back the .ipa ready for distribution.  This would be the easiest approach.  Unfortunately, this client has strict policies in place about not letting their certificates out of their control, even to PhoneGap Build with all of its security protocols.  So that option was off the table.

Option 2: Have them re-sign the .ipa

Can an .ipa be re-signed?  Yes – sort of.  There are a couple of open-source scripts that do this re-signing.  They do work, and our client tried it successfully a couple of times.  However, the client was not comfortable using this because it doesn’t follow the normal Apple-sanctioned approach of using XCODE’s Organizer.  They felt we were requiring them to go through extra steps just because we wanted to use PhoneGap Build.

Option 3: Repackage .ipa as .xcarchive

Can an .ipa be turned into an .xcarchive?  There’s not a lot of information about this, but it turns out it can be done quite easily!

First, let’s look at the file structure of an .ipa file generated by PhoneGap (it’s actually a zip file – just change the extension and unzip it)

ipa_structure

Now let’s compare what we get if we use XCODE to archive that same project as an .xcarchive directory:

xcarchive_structure

Here are the differences in the .xcarchive:

  1. An Info.plist file in the root
  2. A dSYMs folder with debug information in subfolders
  3. The HelloWorld.app folder is under Products/Applications instead of Payload

So we’re not far off.  With just a little editing, we can take the contents of that unzipped .ipa file and make an .xcarchive to give to the client!

Here are the steps:

  1. Get the .ipa file from PhoneGap Build and unzip it
  2. Create a folder named YourApp.xcarchive
  3. Create a subdirectory named Products with a subdirectory named Applications
  4. Copy the .ipa file’s Payload/YourApp.app directory to the .xcarchive directory’s Products/Applications directory
  5. Delete Products/Applications/YourApp.app/embedded.mobileprovision – this may include some of your certificate information that will cause strange errors.  It is safe to delete because it will get regenerated when the new .ipa is built anyway
  6. Create Products/Applications/YourApp.app/archived-expanded-entitlements.xcent (or edit it if it exists). Builds prior to Xcode 5.1.1 seemed to work without this, but it is now needed to avoid errors when you install about missing entitlements:  Note that for the ID of the app here you’ll need to included the prefix from the App ID in the Developer Portal
    <?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>{App_Prefix}.{Your Bundle Identifier}</string>
        <key>keychain-access-groups</key>
        <array>
            <string>{App_Prefix}.{Your Bundle Identifier}</string>
        </array>
    </dict>
    </plist>
  7. Open Products/Applications/YourApp.app/Info.plist* and change the CFBundleIdentifier to Bundle Identifier the client will be using (In our case, we are using a different Bundle Identifier for our own builds than the client uses).
  8. Create an Info.plist in the root.  This is different than the Info.plist that was in your .ipa – this one describes the .xcarchive.  Below is an example that should work:
<?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>ApplicationProperties</key>
    <dict>
        <key>ApplicationPath</key>
        <string>Applications/{YourApp}.app</string>
        <key>CFBundleIdentifier</key>
        <string>{Your Bundle Identifier}</string>
        <key>CFBundleShortVersionString</key>
        <string>{Your version number, like 1.0.0}</string>
        <key>CFBundleVersion</key>
        <string>{Your version number, like 1.0.0}</</string>
        <key>SigningIdentity</key>
        <string>{Your original signing identity, such as “iPhone Developer: Your company”}</string>
    </dict>
    <key>ArchiveVersion</key>
    <integer>2</integer>
    <key>CreationDate</key>
    <date>{Date you want to show up in organizer, use format 2014-02-07T23:05:44Z}</date>
    <key>Name</key>
    <string>{YourApp}</string>
    <key>SchemeName</key>
    <string>{YourApp}</string>
</dict>
</plist>

* A .plist file is just XML, but is encoded for Mac.  If you are on a Mac with XCODE, editing it is easy.  On a PC you’ll need a separate program.  I use plistEditor for Windows from www.iCopyBot.com

Important note:  A normal .xcarchive file does have debug information which this conversion process does not provide.  This probably limits some other uses of the resulting .xcarchive file.  But for just packaging the file back into an .ipa file, this does not seem to be an issue.  So we just don’t worry about creating the dSYMs directory and it works fine.

You now have an .xcarchive folder ready to give to the client.  They should be able to open it in Organizer, choose the profile they want to sign it with, and package it for deployment without any extra steps.

The hardest step was the last one where you had to make an Info.plist.  The good news is that this really doesn’t change from build to build unless you want to change the version number and/or date.  So I suggest creating a shell .xcarchive folder with the Info.plist file ready to go and reuse it for each build.

Conclusion

By going through these steps to convert the .ipa to .xcarchive, we were able to meet our client’s requirements without changing our desired build process.  We just added a few simple steps to our workflow, which now looks like this:

pgbuild_workflow

Good luck!

Advertisements

4 thoughts on “When PhoneGap Build .ipa files need to be re-signed

  1. Very interesting! And very well explained. Thanks for that!

    I have a similar situation, and looking for information about distributing iOS in-house apps with the Apple’s Enterprise program, I came across your post. Now, I have a question: is it enough with generating the .ipa in Phonegap build in order to distribute the app – with the Enterprise program- ? Or as Apple says, you need to package your app with Xcode and follow a sort of steps?

    If the second answer is “yes” I guess I could do that with your option 3 …
    ?
    Any light on that?

    Many thanks, and again, congratulations!

    • Assuming you correctly uploaded your Enterprise certificate to PhoneGap Build and had it use that certificate for your app, the IPA file from PhoneGap Build has everything you need for your in-house distribution. We’ve been doing that a lot for our internal builds without any issues, and we have some clients that allow us to use their certificate to build the app so we get an IPA file they can use for their own distribution. My steps in this post are just what would be needed if the client won’t let you have their certificate. It lets you turn that IPA file back into an XCARCHIVE that they can then sign in Xcode using the normal process.

      • Hi again Kevin,

        so i have another doubt. How could we distribute the app? I read we need a plist archive. Should we create it as you explain in step 8 within option 3?

        Many thanks.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s