xcode - Distributing iOS App on App Store and Enterprise


Keywords:ios 


Question: 

TLDR :

A. Issue in exporting app with Enterprise Cert

Error : wildcard app id cannot be used to create in house provisioning profiles

B. Right approach to distribute app on Enterprise and AppStore

We have been distributing apps on Apple's AppStore for years, Enterprise is new addition. – App has Watch App and supports iOS 8+.

What is done so far:
– Two different dev accounts and certificates.
– Separate provisioning profiles on each accounts
– Build Config and Scheme for Enterprise a AppStore
– using Scheme/Config to switch between settings like bundleId, etc.
– Successfully Archive Enterprise Application

I have NOT created separate info.plist or entitlements (Do I need to?)

Issue: When I try to export Enterprise Archive, I am getting error

wildcard app id cannot be used to create in house provisioning profiles<

I do have proper provisioning profiles created. None of them are wildcard, except created by Xcode.

I have read this post, which says needs to create different targets. That is overhead of keeping both the targets in sync.

Question:

bool itIsPossible = Can this be achieved with Configuration/Schemes?

if (itIsPossible){
– What else I need to create separate entitlements etc?
}else{
– Do I have to create new target to support Enterprise App?
– Separate Target for Watch and Extension? 
– What else I need to create separately Info.plist, entitlements etc?
}

4 Answers: 

Using Targets

New targets do create some overhead (new files must be added to all relevant targets). New targets allow to easily compartmentalize which file goes where, provide a platform for separate plist & config, Unit Tests, etc.

Remember that App Store executable and Enterprise executable are two different applications, with different certificates and signatures. (1)


Separate target recommendations (from an actual product)

  • Shared Entitlements
  • PROJECT > TARGETS > General > Team > pick separate teams there
  • < yourTarget >.xconfig (optional & handy)
  • .plist (most likely, but not required)(2)

(1) Same can be said about Apple Watch executables
(2) Separate plist allows for runtime magic: single code controlled by resources.

 

It is quite easy to do if you can create separate build script for each application. No need to have separate target.

Here is my build script: # Created by Nguyen Tuan on 10/8/14. #!/bin/sh

AP_NAME="$1"
echo "App name $AP_NAME"
FILE_NAME="$2"
echo "FILE_NAME $FILE_NAME"
SCHEME="$3"
echo "SCHEME $SCHEME"
PROVISIONING_NAME="$4"
echo "provisioning $PROVISIONING_NAME"
BUNDLE_ID="$5"
echo "BUNDLE_ID $BUNDLE_ID"
AP_ICON="$6"
echo "AP_ICON $AP_ICON"
PARENT_FOLDER="$7"
echo "PARENT_FOLDER $PARENT_FOLDER"
CONFIG="$8"
echo "CONFIG $CONFIG"

PROJECT_HOME_DIR="$9"

#Goto working folder
MY_PATH="`dirname \"$0\"`"
cd $MY_PATH
echo "build sh: This is the current working directory: $MY_PATH"
SCRIPT_FOLDER=$(basename "$MY_PATH")

MY_NAME=$(whoami)
echo "Script Folder $SCRIPT_FOLDER"
sudo sh sudo.sh
echo "Global PATH: \n$PATH"

#Go up to Project folder
cd ../../
rm -r -f build/$PARENT_FOLDER

PLIST=$PROJECT_HOME_DIR/Info.plist
echo "Please enter build number"
#BUILD_NUMBER=$(/usr/libexec/PlistBuddy -c "Print CFBundleVersion" "$PLIST")
#BUILD_NUMBER=$(expr $BUILD_NUMBER + 1)
BUILD_NUMBER=`git rev-list HEAD --count`
echo "Get provisioning file: UUID + name for $PROVISIONING_NAME"

if test -d ~/Library/MobileDevice/Provisioning\ Profiles/; then
    ProfilesDir=~/Library/MobileDevice/Provisioning\ Profiles/
else
    ProfilesDir=/Library/Developer/XcodeServer/ProvisioningProfiles/
fi

array=$(ls "$ProfilesDir")
provi=""
for i in $array; \
do output=$(/usr/libexec/PlistBuddy -c 'Print :Name' /dev/stdin <<< $(security cms -D -i "$ProfilesDir/${i%%/}") 2>&1); \
echo $output; \
if [ "$output" == "$PROVISIONING_NAME" ]; then provi=$(/usr/libexec/PlistBuddy -c 'Print :UUID' /dev/stdin <<< $(security cms -D -i "$ProfilesDir/${i%%/}") 2>&1); break; fi;\
done

#echo PROVISIONING_UUID=$provi >> provisioning.properties
echo "selected profile $provi"

/usr/libexec/Plistbuddy -c "Set CFBundleVersion $BUILD_NUMBER" "$PLIST"
/usr/libexec/Plistbuddy -c "Set CFBundleIdentifier $BUNDLE_ID" "$PLIST"
xcodebuild -alltargets -configuration "$CONFIG" clean
xcodebuild -scheme $SCHEME PRODUCT_BUNDLE_IDENTIFIER=$BUNDLE_ID ONLY_ACTIVE_ARCH=NO ARCHS="armv7 arm64" PROVISIONING_PROFILE=$provi PRODUCT_NAME="$AP_NAME" ASSETCATALOG_COMPILER_APPICON_NAME=$AP_ICON archive -archivePath "build/$PARENT_FOLDER/$FILE_NAME.xcarchive" 
#xcodebuild -exportArchive  -archivePath "build/$PARENT_FOLDER/$FILE_NAME.xcarchive" -exportPath "build/$PARENT_FOLDER"
#-exportOptionsPlist $PLIST
echo "export ipa file"
rm -r -f build/$PARENT_FOLDER/$FILE_NAME.ipa
sh $MY_PATH/create_ipa.sh build/$PARENT_FOLDER/$FILE_NAME.xcarchive build/$PARENT_FOLDER/$FILE_NAME.ipa
mv build/$PARENT_FOLDER/**You need to change this to your app name**/.ipa build/$PARENT_FOLDER/$FILE_NAME.ipa
rm -r -f $HOME/Dropbox/$FILE_NAME.ipa
cp build/$PARENT_FOLDER/$FILE_NAME.ipa $HOME/Dropbox/$FILE_NAME.ipa

rm -r -f "build/$CONFIG-iphoneos"

echo "copy xcarchive file into organizer"
sh $MY_PATH/copy_resource.sh build/$PARENT_FOLDER/$FILE_NAME.xcarchive $MY_NAME

And then create two build command, one for enterprise build and one for app store build, something like this:

AP_NAME="ABCD"
FILE_NAME="An App Name"
SCHEME="Scheme for enterprise build"
PROVISIONING_NAME="Expected provisioning profile, what is shown in XCode"
BUNDLE_ID="app bundle Id"
AP_ICON="custom icon if need?"
PARENT_FOLDER="the folder that will contains the build"
CONFIG="Release"

#Goto working folder
MY_PATH="`dirname \"$0\"`"
sh $MY_PATH/build.sh "$AP_NAME" "$FILE_NAME" "$SCHEME" "$PROVISIONING_NAME" "$BUNDLE_ID" "$AP_ICON" "$PARENT_FOLDER" "$CONFIG"

In case you need the copy_resource script:

path=$1
user=$2
echo $path
filename=$(basename "$path")
extension="${filename##*.}"
filename="${filename%.*}"
now=`date +%Y-%m-%d`
et=`date +%H:%M:%S`
PATH="/Users/$user/Library/Developer/Xcode/Archives/$now"
echo $PATH
/bin/mkdir -p $PATH
PATH=$PATH/$filename$et.$extension
/bin/mv $path $PATH

From now on, just run the command and you will see a build either in working folder or in Xcode Organizer

 

It seems like the provisioning profile is not set correctly.

The easiest way of doing this is to create an additional configuration.

Select the project in the navigator. Then duplicate the Release configuration and rename it to Enterprise Distribution or Enterprise Release.

enter image description here

Then select your target and go to Build Settings. There you can unfold the settings for Code Signing Identity, Provisioning Profile. You also need to use a different bundle identifier.

Check what configuration you use in the archive scheme too.

 

We had the error

Wildcard app id cannot be used to create in house provisioning profiles

We solved it by manually adding a Distribution (In House) Provisioning Profile in the Apple Developer Portal...

enter image description here