Build Your Xamarin App For iOS Once, Deploy It Twice – Both To Your Testers And To The AppStore.

The ordinary process of building and shipping an (iOS) app often includes at least two builds: The first for your internal tests, the second for the public (AppStore). That's somewhat less than perfect and we can do better.

Published on Sat, May 14, 2016

How Apple Thinks Deployment Should Be Done

Last year I wrote about how to automate all the things by distributing a Xamarin iOS app to the AppStore and Apple's TestFlight.

That's the way Apple wants us to work. It's better than it has been previously, but at the end of the day Apple is still forcing you through their review process even for your beta builds you want to distribute via TestFlight (at least for what they call external testers).

It may be a good fit for most setups anyway, but if you want to deliver your beta-bits internally without involving Apple, you need an alternative way.

Get Some More Control

If you want to have more control over the internal process, you still have two additional options:

The Problem Of Different Certificates

At the end you still have the problem of having two builds for each target: because you can't distribute an .ipa signed with a certificate for the AppStore to your internal beta-testers. And you can't upload an .ipa signed with an enterprise or development certificate to the AppStore.

I've seen some ways people work with that situation, the most common appears to be to have two different builds at different points in time.

Usually internal test builds are triggered whenever something needs to be tested or a new milestone is hit. Maybe there's even something equivalent to a staging environment where only bugs are being fixed and no new features are added (compare git-flow).

But whenever a new version is ready for the AppStore, a new build is being made – now with the correct provisioning profile and certificate for publishing on iTunes Connect.

The Problem Of Different Builds For Testing and Production

Now you may have a solution that feels good – you have figured out all the crap around provisioning and signing Apple forces you through. Your process may even be automated. But you still have two builds. Why's that bad?

Because you want to to ship the bits to the AppStore you have exhaustively tested internally.

Let that sink for a moment.

So what could possibly go wrong with having two different builds? The main point: Your production build could differ from your test build. That is really bad.

Solution: Build Once, Deploy Twice

0. Preface

Make sure the right AppStore certificate is installed on your build machine and Xcode knows about the right provisioning profile.

1. Build Your AppStore Build

Take a look at step 3 over there to see how you can configure your *.plist automatically.

Let's start. First build the .ipa ...

/Applications/Xamarin Studio.app/Contents/MacOS/mdtool  -v build "--configuration:AppStore|iPhone" "$SOLUTION_PATH"

... then pack it.

xcrun -sdk iphoneos PackageApplication -v "$APP_STORE_DIR" -o "$BUILD_DIR/AppAppStore.ipa"

2. Build Your Internal Build

Now take everything produced in the previous step and adjust it to the needs of your internal build. Start with all the configurations again, for example:

/usr/libexec/PlistBuddy -c "Set :CFBundleIdentifier xyz.yourapp.com" "$APP_STORE_DIR/Info.plist"

Then re-sign your AppStore build:

rm -rf "$APP_STORE_DIR/_CodeSignature/"
cp "$INTERNAL_PROVISIONING_PROFILE_PATH" "$APP_STORE_DIR/embedded.mobileprovision"
codesign -f -s "$INTERNAL_CERT_NAME" "$APP_STORE_DIR" --entitlements "./configs/Entitlements.plist"

And pack it:

xcrun -sdk iphoneos PackageApplication -v "$APP_STORE_DIR" -o "$BUILD_DIR/AppInternal.ipa"

That's it.

Conclusion

Now you know how to build both AppStore.ipa and AppInternal.ipa in one single step. Those packages only differ in the signature and the embedded provisioning profile, but the application itself is absolutely the same in every single bit.

That will give every stakeholder some peace of mind, because it makes sure there is nothing shipped to your users that has not been gone through your test-process.

What do you think?
Drop me a line and let me know!