Following these instructions (see also Apple's developer documentation and BoltClock's answer to Test iOS app on device without apple developer program or jailbreak), I was able to compile an iOS app (in this case provenance, a video game console emulator app which doesn't meet Apple's guidelines and will never be allowed in Apple's App Store) in Xcode 7, sign it with my personal iCloud account, sideload it onto my iPhone (by plugging it into my Mac by USB, and selecting my iPhone in xcode menu -> Product -> Destination), and allow my phone to execute it by "trusting" apps with this signature in Settings -> General -> Profile, which installs the certificate associated to my icloud account onto the device.
I would like to replicate these steps with an over the air download. Can I get Xcode to produce an executable that I can share with my brother, who has an iPhone, but does not have access to a Mac with Xcode?
The StackExchange Network accomplished something like this apparently for its iOS app beta program, by using Apple's enterprise distribution via Mobile Device Management, as mentioned in this question. There is also the BuildStore (http://builds.io/), which for $10/year also enables this functionality, apparently by adding users to a "developer team" associated to a paid Apple Developer Program account (see Apple dev docs). With Xcode 7, is it possible to do such a thing without an enterprise or even regular paid developer account?
update: Thanks to Stacksza's help, I have made some progress, which I will summarize here.
- XCode will create an archive (Product -> Archive), but it does not allow you to export an archive to to an .ipa file for ad hoc distribution without subscribing to the paid ADP account tier.
- No problem though, because the command line xcode tool does create an .ipa executable, even with no paid ADP account. Use a command like
xcodebuild -exportArchive -archivePath Provenance-Release\ 11-20-15\,\ 22.24.xcarchive/ -exportOptionsPlist ~/manifest.plist -exportPath ~/Provenance(see Khawar's answer at How to create ipa in xcode 6 without Apple Developer account?)
- But this command requires you to specify a manifest .plist file. The answer by Razvan at Over The Air (OTA) iOS IPA File Distribution For Public? contains a sample manifest.plist, as well as instructions for the hyperlink format necessary for providing a download link, which must be hosted on an SSL webpage. Might be that the SSL URL must math the app's bundle id, I'm not sure.
- But the above only works if the app is provisioned for the device which downloads it, and the device has already installed the developer certificate. So for instance a device which has previously been connected via USB to my Xcode can now download the app over the air, which is great. This is progress. But for clean devices, I get the error
Could not install embedded profile: 0xe8008012 (This provisioning profile cannot be installed on this device.)(as viewed in the device's console, which can be viewed in Xcode -> Window -> Devices, or else in the Apple Configurator app).
- For an app to be provisioned for a device, it needs to contain the device's UDID in the
embedded.mobileprovisionfile, see How Do You Embed a Provisioning Profile in an iOS App, How to automate checking a field in an ipa's embedded.mobileprovision?, How to find out what profile was used for building *.ipa file?, and Is there a way to see what UDID are included in a build?. You cannot just edit this file to add the UDID, however, because then the CODESIGNATURE of the app doesn't match, and the device will report the error
Failed to verify code signature of /private/var/mobile/Library/Caches/com.apple.mobile.installd.staging/temp.7jBjpk/extracted/Payload/Provenance.app : 0xe8008017 (A signed resource has been added, modified, or deleted.)}
- Ok, so we need to resign the app. Xcode provides a commandline tool called
codesignwhich can do this. Instructions are at How to re-sign the ipa file? and Re-sign IPA (iPhone) and Resign an iPhone App, insert new Bundle ID and send to Xcode Organizer for Upload and How to manually re-sign an IPA with a new provisioning profile. I had to specify my developer certificate, the precise name of which can be found in Keychain Access, under the Certificates tab, and looks like "iPhone Developer: firstname.lastname@example.org (ABCDEFGHIJ)". Then the command is like
codesign -f -s "iPhone Developer: email@example.com (ABCDEFGHIJ)" Payload/Provenance.app. The example commands in the instructions above included a flag called
--resource-rules, but I found no such file in my compiled app, so I removed that flag. I wonder what it does, and whether it is necessary. Edit: The excellent blog post Inside Code Signing by Thomas Kollbach explains that the
--resource-rulesflag used to be used to state which parts of an app must be signed, but since iOS8 is deprecated, and the entire app must be signed.
- Now that the app has the UDID added and is signed, downloading it on the fresh device gives the errors
Could not install embedded profile: 0xe8008003 (This provisioning profile is malformedand
A valid provisioning profile for this executable was not found. My guess it the problem now is that the device still has not installed the developer certificate. When sideloading via Xcode, before the app will execute, you have to find the installed certificate in Settings -> General -> Profile, select your certificate and tap "trust". However this option does not appear after the over-the-air download of the ad hoc app, so I am unsure how to proceed. I think I need some way to install the developer certificate on the device. According to Installing provisioning profile on iOS 8.0.2, it used to be possible by simply emailing the certificate to the device, but that no longer works as of iOS 8. I have not tried to confirm. How can I install my developer certificate onto an iOS device remotely?
- I tried exporting my iPhone developer certificate from Keychain Access, and emailing it to the device. The device was able to install the certificate, but it displayed with a red warning that it was not signed, whereas when the cert was installed via Xcode/USB had no such warning. According to Rhythmic Fistman at is possible to re-encrypt an embedded.mobileprovision file?, the profile must be signed by Apple to work. This may be the sticking point. Apple will only sign your cert if you have a paid ADP account.
- This blog post on provisioning by Sean Heber was very illuminating about the general theory of developer certificates and provisioning profiles (along with Kollbach's they should both should be required reading). It contains this paragraph:
The reason all of this works and is secure is that Apple generates the provisioning profiles in the portal and then signs them with their own private keys before delivering them to you. The signing of the provisioning profiles is something only Apple can do. The file you download can therefore not be tampered with without rendering it invalid. An invalid provisioning profile will not be accepted by iOS and thus Apple can control exactly what can and cannot be provisioned by a developer by simply restricting access to the signing of the provisioning profile to things the the developer portal gives you permission to configure in the first place - even though provisioning profiles can support any number of other awesome options you can’t use without jailbreaking. This is why you have to register testing devices in the portal, add your certificates to the portal, etc - only things in the portal (and thus the numbers of which can be controlled and limited arbitrary by Apple) can be included in a generated and properly signed provisioning profile. The portal is where Apple’s provisioning policies and limitations are actually enforced.
This seems to definitively answer my question (can I get the app to run without a paid ADP account) with a "no". Although this article predates Xcode 7. Apparently Xcode 7 will send a device's UDID to the Apple portal, and receive in response a provisioning profile signed by Apple, containing that UDID. Xcode 7 only does this when the device is plugged in via USB and recognized by Xcode, but one wonders whether a manual Xcode request to Apple could be crafted? That gets deeper into reverse engineering Apple's stuff than I'm comfortable with, and probably violates ToS or whatever, so I think I'm satisfied with the "no" answer.
According to the about page for BuildStore, they manage something similiar via email, so it may be possible.
Xcode “Build and Archive” from command line is quite old (circa xcode 3), but suggests using
xcrun instead of
xcodebuild which I've been using.