67

My scenario

I wrote an iOS app for a client. The project is almost over and now it's time for them to put it in the App Store. I've been sending them development builds throughout the development process. Those builds had a bundle id based on my company and my client's project like so: com.mycompany.clientname.projectname. I signed those Ad Hoc builds with an Ad Hoc Distribution Provisioning Profile that I created in my own Provisioning Portal account.

Now that it's time to go to the App Store, I need to do a Release Build and send that for them to sign with their own App Store Distribution Provisioning Profile. This also implies setting a new Bundle ID for the project.

My problem

I need to get a compiled app to the client for them to sign with their provisioning profile. However, I need to set the Bundle ID to what they're going to use first. Let's say it's com.bestclientever.appname. Xcode 4 won't let me archive the project now because doing so requires code signing. I can not code sign it because I can not create a provisioning profile with the same Bundle ID as what they have set up in their Provisioning Portal (the Provisioning Portal enforces uniqueness—as it should).

Have I made any incorrect assumptions or misunderstandings here? ie. Do I really have to set the Bundle ID to what they're going to sign with?

The Question

Is there any way to archive, or otherwise build, an iOS app without code signing it? Like a "sign later" setting or something?

Or, is there a way to build the app with one bundle id but then someone else be able to sign it with a provisioning profile for another bundle id (either by changing the bundle id of the compiled app or some other signing method)?

How can I build the final release build but have someone else sign the app for distribution to the App Store?

What I've tried or explored

  • Acting for the client.
    • With other, less savvy clients, I've ended up just getting their Provisioning Portal and iTunesConnect credentials and just doing the final build as them. That won't fly with this client. It's a big company with strict security guidelines and a lot of red tape.
  • Spoofing as the client.
  • Sending the client my project source code and letting them do the release build.
    • A license to the source code was not in our agreement. Additionally, this client does not want to get involved with source code (hence outsourcing it). I would entertain this as a last-resort option, but there's gotta be a better way!
  • Getting set up as an Admin-level developer in their Developer Member Center.
    • Unfortunately, only the Agent-level user can create a Provisioning Profile (as far as I can tell). It seems like there ought to be a way to either let me create a profile that I can use to sign the build or generate a profile for me. I can't find either option.
Community
  • 1
  • 1
RickDT
  • 2,104
  • 1
  • 23
  • 25
  • Hey Rick, we are facing exactly this conundrum. I've sent a request to Apple (including a link to this question, since it so perfectly describes our situation!). What did you end up doing? – Joshua Smith Apr 30 '12 at 17:17
  • Still messing around with send keys around via email (cringe). Further research is on my pre-WWDC todo list! – RickDT May 02 '12 at 16:55
  • 2
    I finally heard back from Apple. This is what they recommend: https://developer.apple.com/library/ios/#qa/qa1763/_index.html – Joshua Smith May 22 '12 at 15:24

10 Answers10

28

Most of these answers seem complicated and out dated. I think the simple answer is to make an archive with a Developer profile.

This is a solution which I am currently investigating for my own purposes (not fully tested):

You just need developer access (not team agent) to their account and create a Development provisioning profile that authorizes you to build the specified App ID (you need to specify the App ID, because it gets compiled in). Then Archive the app with the Development profile, and share the archive with your client. They can then re-sign the archive with their own Distribution profile.

One complication is that when you build an archive with a developer profile, the entitlement attribute get-task-allow gets set to true, but needs to be set to false for distribution, so you have to work around that by setting it manually your Entitlements.plist - see my question here: Can I archive with a Developer certificate, then re-sign it during submission with a Distribution certificate?

Community
  • 1
  • 1
Richard Venable
  • 8,310
  • 3
  • 49
  • 52
  • 2
    This is the general gist of what's easiest that works. I know I tried this before and it didn't work, but I just ran through a full scenario at WWDC and it works like a charm. I posted a full step-by-step answer for more detail: http://stackoverflow.com/a/11038792/5421 – RickDT Jun 14 '12 at 18:04
  • hey, is there a recommended non-hacky way to do this in 2018? – webdevbyjoss Jan 15 '18 at 13:28
27

I just confirmed at WWDC 2012 that the following technique works. It best satisfies my constraints of little client involvement, low client expertise, a simple signing process, and source code ownership.

  1. Client invites developer to their team in the Member Center as an Admin
  2. Developer accepts the invite (should be in your email)
  3. Developer opens Xcode's Organizer -> Devices Tab -> Provisioning Profiles and hits Refresh in the lower-right corner. Make sure you choose the right team and you should get a few new items.
  4. In Xcode, leave Code Signing Identity settings to their default values (or reset them to iPhone Developer for Any iOS SDK)
  5. Archive the app
  6. In Organizer, right-click the archive and select Show in Finder
  7. Send the .xcarchive file to your client
  8. Client must have Xcode installed
  9. Client double-clicks the .xcarchive file which should open it in Organizer
  10. Client clicks Distribute and signs the app with their identity
  11. Profit

This does require the client to use the Member Center on developer.apple.com and to use Xcode a little bit (but just the Organizer!). If your client has technical capability problems at this level then I recommend just taking over and doing it for them (and charging for it!). Ask for their developer login and password and just act on their behalf as if you were an employee.

Ed note: Trading keys around is a terrible compromise because it's more technical and involved for the client and more hacky and risky for the developer. It should be considered a non-option given these two better options.

RickDT
  • 2,104
  • 1
  • 23
  • 25
  • Does the client have to setup the Development certificate, App ID, and Provisioning Profile before hand or will XCode do this automatically when you click "Refresh" after accepting the invite? – dreyln Jan 24 '13 at 22:14
  • 2
    This is not a good solution because the admin can download the private key from the client. I know is a trust thing but is just not a good process. EDIT: Ok, you did state this is a risky option. – mskw Mar 08 '13 at 15:53
  • Has this process been simplified at all since the time of this answer ? Would seem to be a common thing for a developer to have the need to provide a properly signed .ipa for the client without them having to use XCode. My client doesn't have X-Code and I need to create a distribution build for them. Is that possible ? – prototypical Jan 29 '14 at 01:23
  • @prototypical No simplifications were announced at WWDC 2013. There's always hope for 2014 :) – RickDT Feb 26 '14 at 14:14
  • @mskw: no, the developers private keys are never stored on apple servers. and the certificates are basically public – Michael Oct 05 '15 at 10:21
  • Does this require them sending you their private key for their development certificate? – Si-N Oct 07 '15 at 14:34
  • @Si-N no, both sides use their own identities. Please note that these instructions are for an Xcode and dev tools that are now several years old. At our firm, we've moved to using B2B with VPP in the App Store. – RickDT Oct 07 '15 at 17:45
6

I had the same problem. This was how I finally solved it:

  1. Client created a development certificate.
  2. Client created a development provisioning file using the same App ID as the distribution provisioning file.
  3. Client exported development certificate (.p12).
  4. Client sent me the .p12 file and the development mobile provisioning file.
  5. I imported the clients p12 file into my keychain
  6. I imported the client's provisioning file into Xcode.
  7. Set the code signing Identity for my build configuration to use the client's provisioning file.
  8. I Archived the app.
  9. I Sent the Archive to the client.
  10. The client created their distribution build by signing the app with their distribution provisioning file. (They were distributing the app internally for testing.)

The client was not so concerned with sharing a development certificate as they would be sharing their distribution certificate.

I also had to create entitlements.plist with "Can be debugged" (get-task-allow) set to NO, and reference it in the build configuration (under Code Signing, Code Signing Entitlements).

jimmyg
  • 580
  • 4
  • 13
3

I believe I have found a way to do exactly what you want, I haven't done extensive testing or tried to upload to the app store but from the testing I have done it seems to be good. The resign and the addition of my provisioning profile is working as I can install it on my devices defined in the AdHoc profile with no manual profile installation needed. Second test was I got an iPad and an iPhone version of an app with the same bundle ID from xCode, at first I could not have both in iTunes but after the resign and bundle ID change I was able to have both installed. I also tried changing the app name and that worked as well, it showed on the device and in iTunes with the new name. Below is my script, it's designed to resign a specific app for me, so the profile and bundleID are hardcoded. I flip between an iPhone and iPad version of the app so I added that as a parameter to the script. But you should be able to take the principles I have here and refine them for yourself.

The guts of this builds upon articles like Further adventures in resigning for iOS from Dan's Dev Diary and very similar to Erica Sadun's App Signer listed above. The main addition I made was the editing of the Info.plist prior to resigning.

#!/bin/sh

DestFile="Signed_$1"
SigningCertName="YOUR DISTROBUTION CERT NAME HERE FROM KEYCHAIN"
AppInternalName="APP NAME FROM INSIDE PAYLOAD FOLDER.app"

echo
echo "Going to take the app $1 and resign it as $DestFile"
echo

if [ "$2" = "iphone" ] ; then
        echo "Using iPhone Profile"
        echo
        BundleID="com.YOURCOMPANY"
        ProvProfile="/Users/YOURNAME/Library/MobileDevice/Provisioning Profiles/PROVISIONINGPROFILE.mobileprovision"
elif [ "$2" = "ipad" ] ; then
        echo "Using iPad Profile"
        echo
        BundleID="com.YOURCOMPANY.ipad"
        ProvProfile="/Users/YOURNAME/Library/MobileDevice/Provisioning Profiles/PROVISIONINGPROFILE_iPad.mobileprovision"
else
        echo "You must enter either iphone or ipad as the second parameter to choose the profile to sign with."
        echo
        exit 1
fi

rm -f Resigned.ipa
unzip -q $1 -d temparea
cd temparea/Payload
echo "*** Original Signing ***"
echo "************************"
codesign -d -vv $AppInternalName/
cp "$ProvProfile" ./$AppInternalName/embedded.mobileprovision
export EMBEDDED_PROFILE_NAME=embedded.mobileprovision
export CODESIGN_ALLOCATE=/Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/codesign_allocate

#Update the Info.plist with the new Bundle ID
sed 's/>ORIGINAL BUNDLEID HERE</>'$BundleID'</' ./$AppInternalName/Info.plist >./$AppInternalName/Info.plist.new
mv -f ./$AppInternalName/Info.plist.new ./$AppInternalName/Info.plist

# this will do a rename of the app if needed
# sed 's/>ORIGINAL APP NAME</>NEW APP NAME</' ./$AppInternalName/Info.plist >./$AppInternalName/Info.plist.new
# mv -f ./$AppInternalName/Info.plist.new ./$AppInternalName/Info.plist

# echo "Hit enter to proceed with signing."
# read TMP
codesign -f -vv -s "$SigningCertName" -i $BundleID $AppInternalName

echo
echo "*** New Signing ***"
echo "*******************"
codesign -d -vv $AppInternalName/
cd ..
zip -r -q ../Resigned.zip .
cd ..
rm -R temparea
mv Resigned.zip $DestFile
echo
echo "New IPA Created, $DestFile"
Piwaf
  • 808
  • 8
  • 9
2

Best alternative way would be to ask the client to export his distribution certificate private key into .p12 file and send it across to you alongwith the distribution profile with which you can generate a App Store distribution build for your client.

Best of luck!!

Regards, Sam

Saurabh Passolia
  • 8,099
  • 1
  • 26
  • 41
  • 2
    Hi Sam. As I outlined under "spoofing as the client", I'd rather avoid asking my client for their private keys. Even if I asked, they would probably either grumble or just plain turn me down. I've done this with smaller clients, but this is a big, old, stodgy megacorp staffed with IT people that are more motivated to cover their own butts than help move the process along. I'll revisit this if no other option works out... – RickDT Sep 16 '11 at 19:05
  • practically there is no possible way that you can generate a build for your clients and they may sign it on their own before submitting to AppStore. The signing info is embedded at compile time (as last step) when you generate the build. – Saurabh Passolia Sep 16 '11 at 19:17
  • @samfisher Does this mean Erica Sadun's App Signer won't work? http://ericasadun.com/ftp/Macintosh/ – Danyal Aytekin Dec 21 '11 at 09:54
1

Ok, found a way to do it without sharing provisioning profiles or certificates.

The idea is to insert a "run script" build phase to trick XCode into signing an App it didn't compile, so you can send a compiled (unsigned) App to the client, and then their XCode signs that App with their cert and profile.

How to do it:

Step 1: Make XCode generate an unsigned Release .app (I'll call this "App A"). See "To Disable Code Signing" here: https://stackoverflow.com/a/10171462/375486

Step 2: Create a new XCode iOS project and remove from it all build phases you can, so it creates an empty .app file (I'll call this "App B")

Step 3: Add a "run script" build phase to Project B which copies the contents of "App A" into "App B". In my case I used this:

cp -r A.app/* "$CODESIGNING_FOLDER_PATH"

Step 4: Send the "B" XCode project to the client, with all the necessary files.

Step 5: The client builds the B project. Under the hood, XCode will run the "run script" command, then sign the resulting app, and the client gets a perfectly signed App.

And that's it :)

Community
  • 1
  • 1
hasvn
  • 1,054
  • 1
  • 11
  • 15
1

iResign works quite well.

It allows you to change the bundle id and add entitlements when signing. Probably would work for your use case.

That being said, the xcarchive solution is more canonical. Be aware that sharing the xcarchive file gives them the dsym.

If you have any #ifdef DEBUG statements in your code, make sure they are disabled in the build you give them.

funroll
  • 35,925
  • 7
  • 54
  • 59
  • I don't think one has to remove the *DEBUG* statements in their code as long as they're using the **release configuration** irrespective of whether the *development or distribution signer* was used to make *ipa* or *archive* – Durai Amuthan.H Jun 01 '17 at 15:40
1

Huh, all these look way more complicated then they have to. I use this this:

xcodebuild -scheme "$SCHEME" clean archive \ 
           -archivePath "build/$SCHEME" \
           -workspace $PRODUCT_NAME.xcworkspace \
           -allowProvisioningUpdates \ 
           -configuration Release \
           PRODUCT_NAME="$SCHEME" \ 
           PRODUCT_BUNDLE_IDENTIFIER="$BUNDLE_ID" \
           EXECUTABLE_NAME="$SCHEME" \ 
           DISPLAY_NAME="$DISPLAY_NAME" \
           CODE_SIGN_IDENTITY="" \ 
           CODE_SIGNING_REQUIRED=NO \ 
           CODE_SIGN_ENTITLEMENTS="" \
           CODE_SIGNING_ALLOWED=YES
Popmedic
  • 1,791
  • 1
  • 16
  • 21
  • Do you know what process your client uses on their end to sign the IPA? – RickDT Sep 12 '17 at 21:17
  • 1
    Open the archive in xcode organizer, press upload to app store, select company certs, watch as it uploads the app. They will also have to set up their iTunes connect and apple developer account. Other option is for them to give you credentials to itunes connect and apple developer, and then let you do it. – Popmedic Sep 14 '17 at 00:29
  • Xcode 9 requires the -allowProvisioningUpdates flag on the xcodebuild, I edited the answer... – Popmedic Sep 25 '17 at 14:37
0

I just got off the phone with Apple. They say this is the only way to do it: https://developer.apple.com/library/ios/#qa/qa1763/_index.html

The client adds you to their team, and gives you specific privileges.

Joshua Smith
  • 3,689
  • 4
  • 32
  • 45
  • Just got done talking to my client, my above xcodebuild command seems to have worked just fine and they never gave me an account??? – Popmedic Sep 25 '17 at 14:40
  • Things have changed A LOT since this question was originally asked. Now it's easy. You just make an XCode Archive and they load that and apply their own signature. – Joshua Smith Sep 25 '17 at 18:42
0

I've been there. Options 2 or 3 are out of question. Option 4 would be ideal, but as you wrote, Apple will not let the agent delegate her privileges to create distribution profiles.

So basically, your only option is for you to get the distribution profile defined with their account. In order for you to handle it, you would need to login as their agent, which is not an option.

So they will have to do it. There is no way around that.

They will also have to invite you as a member of their product development team on their account. You will need to be an admin. That's mean you will have to send a signing certificate request as outlined by Apple.

Finally, they will have to download and send you the distribution provisioning profiles they created.

With all that, you will be able to sign your application with their resources.

Jean-Denis Muys
  • 6,772
  • 7
  • 45
  • 71
  • Thanks Jean-Denis! This sounds like what I'm looking for. So, if I understand it right, the client adds me as an admin dev member. Then I request a signing certificate (which they then approve?)? Once that's done, then they can create a provisioning profile for me? That would work. It's more manual than I'd like, but it avoids having to share private keys. – RickDT Sep 16 '11 at 19:08
  • There's no point in adding you as a member of their account since the only certificate you can request is development one. – Filip Radelic Sep 16 '11 at 21:54
  • You are right. I should have mentioned that it's easier if you develop on their account too: you don't have to change the app id for each releases, all archives appear in the correct place in Xcode, ad hoc distribution are correctly identified in TestFlight… Voted me down for this is a bit nasty. – Jean-Denis Muys Sep 17 '11 at 19:57