Distributing iOS App on App Store and Enterprise - ios

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?
}

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.
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...

Related

Unable to remote build xcode project

I have a jenkins server connecting to a remote mac mini through ssh to execute a shell script that has to build an IPA from a unity project.
When the shell script is executed locally on the mac mini everything goes fine. But when the shell script is ran from jenkins (with the exact same parameter and the same user) it fails codesigning the archive.
I will share with you the obfuscated shell script as well as the build log.
Thank you for your help in advance.
The shell script :
#!/bin/bash
# Consider directory paths initialized in parameter here
#
#
# Consider git cleaning / fetching commit here
#
#
# Consider environment / version and build name controls here
#
#
# Start Unity Build :
/Applications/Unity2017.4.10f1/Unity.app/Contents/MacOS/Unity -batchmode -quit -projectPath "$SOURCE_PATH" -executeMethod "BuildManager.BuildPlayer" -logFile "$BUILD_LOG_FILE" -buildEnvironment "$ENVIRONMENT" -buildPlatform "IOS" -buildPath "$TARGET_BUILD_DIR" -overrideVersion "$OVERRIDE_VERSION"
if [ ! -d "${TARGET_BUILD_DIR}/Unity-iPhone.xcodeproj" ]
then
echo "[ERR]Exporting unity project to Xcode failed."
exit 1
else
echo "Build successfull"
fi
#
#
# Consider initializing a param for the provisioning profile file path
#
#
# Consider initializing a param for the plist file path
cd $TARGET_BUILD_DIR
# archive generated xcode project
xcodebuild -scheme "Unity-iPhone" -archivePath "${DEPLOY_DIR_ROOT}/${BUILD_NAME}_${FILE_FORMAT_VERSION}/archive.xcarchive" -sdk iphoneos -configuration Release PROVISIONING_PROFILE="${PROVISIONING_PROFILE_PATH}" archive
if [ $? != 0 ]; then
echo "FAILED ARCHIVING XCODE PROJECT"
exit 1
fi
# export ipa from archive
xcodebuild -exportArchive -archivePath "${DEPLOY_DIR_ROOT}/${BUILD_NAME}_${FILE_FORMAT_VERSION}/archive.xcarchive" -exportOptionsPlist "${PLIST_PATH}" -exportPath "${DEPLOY_DIR_ROOT}/${BUILD_NAME}_${FILE_FORMAT_VERSION}"
if [ $? != 0 ]; then
echo "FAILED EXPORTING IPA FROM ARCHIVE"
exit 1
fi
#
# Section reserved for uploading the ipa to relevant remote storage
#
exit 0
So everything works like a charm (even the build can be installed on a device) when the shell script is ran locally from the terminal on the mac mini.
When it comes to run the shell script remotely through ssh it fails to codesign the archive. The user used over ssh is the same than the one used locally to run the script.
Here is the error :
CodeSign
/#######/Library/Developer/Xcode/DerivedData/Unity-iPhone-#########/Build/Intermediates.noindex/ArchiveIntermediates/Unity-iPhone/InstallationBuildProductsLocation/Applications/#########.app
(in target: Unity-iPhone) cd /#########/xcodeProjPath export
CODESIGN_ALLOCATE=/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/codesign_allocate
Signing Identity: "#########" Provisioning Profile: "iOS Team
Provisioning Profile: #########"
(#########)
/usr/bin/codesign --force --sign ######### --entitlements
/#########/Library/Developer/Xcode/DerivedData/Unity-iPhone-#########/Build/Intermediates.noindex/ArchiveIntermediates/Unity-iPhone/IntermediateBuildFilesPath/Unity-iPhone.build/Release-iphoneos/Unity-iPhone.build/#########.app.xcent
--timestamp=none /#########/Library/Developer/Xcode/DerivedData/Unity-iPhone-#########/Build/Intermediates.noindex/ArchiveIntermediates/Unity-iPhone/InstallationBuildProductsLocation/Applications/#########.app
/#########/Library/Developer/Xcode/DerivedData/Unity-iPhone-#########/Build/Intermediates.noindex/ArchiveIntermediates/Unity-iPhone/InstallationBuildProductsLocation/Applications/#########.app:
errSecInternalComponent
Command CodeSign failed with a nonzero exit code
** ARCHIVE FAILED **
I m kind of stuck right now since all my attempts didn't work at all ...
Thank you in advance for your help.
EDIT:
mac mini on macOS High Sierra Version 10.13.6 (17G65)
xcode Version 10.0 (10A255)
Ok so for all of you guys struggling around this tricky subject ( totally invisible if we don't know enough about macOS ) there is kind of security system that still makes the difference between a local user and a remote access to a user.
So the keychain handling your keys and certificates ( used by codesign to sign your build ) is not usable out of the box for the remote user. Its needs to be unlocked first !!!
To know about the available keychains on your system just type in on your terminal :
security list-keychains
You should see something like :
"/Users/'YOURUSER'/Library/Keychains/login.keychain-db"
"/Library/Keychains/System.keychain"
And you guessed it right there, you have to unlock the keychain of your user ! Juste run this :
security unlock-keychain -p 'USER_PASSWORD' 'PATH_TO_USER_KEYCHAIN'
And that's it.
N.B:
Please let me know if I understood something wrong about all this.

MultiBranding the same source code without using xcode

I have an app and I’d like to brand it as 3 different apps with different UI.
I don’t want to do using Xcode directly.
So far I found so many solutions that says create different targets and drag and drop the image like that
But I intend to do this branding work outside of Xcode


Help me out !
Now we can build the code without opening the Xcode
Branding
(UI,Build settings and functional)
UI
App icon & other icons
iTunes Artwork
Build settings
App Name
Bundle Identifier
Provisioning profile
Code signing identity
Functional
Brand specific URLs(login,logout,resource-fetch etc...)
Using Terminal
Branding.sh
#Author: Durai Amuthan(h.duraiamuthan#gmail.com)
#This is to achieve multiple branding of an iOS app by configuring the variables below
#************ Configuring the brand starts ************
#Directory path where .xcworkspace or .xcodeproj exists
PathOfProjectDirectory=/Users/Shared/Jenkins/Documents/JenkinsTestNuu/New/
#Path where info.plist exists
PathOfInfoPlist=$PathOfProjectDirectory/XxYyZz
#Path to icons where new iTunesArtwork and application icon exixts
#Note: Make sure proper naming conventions of file has been followed
PathOfNewIcons=/Users/Shared/Jenkins/Documents/icons-two
#Path to asset resource where you have kept your application icon.
PathOfAppIconSet=$PathOfProjectDirectory/XxYyZz/Icon.xcassets/AppIcon.appiconset
#Path where do you want the .app file has to be kept
PathToApp=/Users/Shared/Jenkins/Documents/JenkinsTestNuu/app
#Path where do you want the .ipa file has to kept
PathToIpa=/Users/Shared/Jenkins/Documents/JenkinsTestNuu/ipa
#Cocoapods project or project that involves more than one modules are scheme based
isWorkspaceBased=true
#Path of the Project (.xcodeproj) - applicable for workspace(.xcworkspace) based project
PathofProjectFile=$PathOfProjectDirectory/XxYyZz.xcodeproj
#Path of the Workspace (.xcworkspace)
PathofWorkspaceFile=$PathOfProjectDirectory/XxYyZz.xcworkspace
#Name of the target - applicable only for non-workspace(.xcodeproj) based projects
Target=XxYyZz
#Scheme of the iOS app
Scheme=XxYyZz
#To ascertain Cocoapods has been used or not
isCocoaPodsBased=true
#Configuration of the app (Debug -(Development) or Release(Adhoc or Distribution))
Config=Release
#For giving access to signing idetity found in KeyChain
LoginKeychainPath=/Users/Shared/Jenkins/Library/Keychains/login.keychain
LoginKeyChainPassword=xxyyzz
#Name of the code signing identity.You can find the name in Keychain or xcode build setting
CodeSigningIdentity='iPhone Distribution: Xx Yy Zz Limited (3Z5MHUYJ2L)'
#Path of the provisioning profile
PathToMobileProvision=/Users/Shared/Jenkins/Desktop/BrandingTest.mobileprovision
#UUID value found inside Provisioning profile has to be given
#Do not forget to install provisiong profile in the system
ProvisioningProfileIdentity=6e6506e9-8233-4886-9084-zf21e8f8bbae
#Bundle identifier of the app
BundleIdentifier=com.xxyy.zz
#AppVersion of the app
AppVersion=2.2.2
#App Name
Appname=Two
#************ Configuring the brand ends ************
#** Creatting the build based on configuration starts **
cd $PathOfInfoPlist
echo "****************** Setting App Name ******************"
/usr/libexec/PlistBuddy -c "Set :CFBundleName $Appname" info.plist
/usr/libexec/PlistBuddy -c "Set :CFBundleDisplayName $Appname" info.plist
echo "app name has been set as $Appname"
cd $PathOfProjectDirectory
echo "****************** Setting AppVersion ******************"
/usr/bin/agvtool new-marketing-AppVersion $AppVersion
/usr/bin/agvtool new-AppVersion -all $AppVersion
echo "****************** Changing app icons & iTunes Artwork ******************"
cp -R $PathOfNewIcons/*.png $PathOfAppIconSet
echo "App icons has been changed at $PathOfNewIcons"
cp -R $PathOfNewIcons/iTunesArtwork#2x $PathOfProjectDirectory/XxYyZz
cp -R $PathOfNewIcons/iTunesArtwork $PathOfProjectDirectory/XxYyZz
echo "iTunesArtwork has been changed at $PathOfProjectDirectory"
#Unlock login keychain
security unlock-keychain -p $LoginKeyChainPassword $LoginKeychainPath
if $isCocoaPodsBased == 'true'
then
echo "****************** Installing Cocoapods **********************"
/usr/local/bin/pod install
echo "Cocoapods has been installed"
fi
echo "****************** Creating .app ******************"
if $isWorkspaceBased == 'true'
then
/usr/bin/xcodebuild -scheme $Scheme -workspace $PathofWorkspaceFile -configuration $Config clean build CONFIGURATION_BUILD_DIR=$PathToApp "CODE_SIGN_IDENTITY=$CodeSigningIdentity" "PRODUCT_BUNDLE_IDENTIFIER=$BundleIdentifier" "PROVISIONING_PROFILE=$ProvisioningProfileIdentity"
else
/usr/bin/xcodebuild -target $Target -project $PathofProjectFile -configuration $Config clean build CONFIGURATION_BUILD_DIR=$PathToApp "CODE_SIGN_IDENTITY=$CodeSigningIdentity" "PRODUCT_BUNDLE_IDENTIFIER=$BundleIdentifier" "PROVISIONING_PROFILE=$ProvisioningProfileIdentity"
fi
echo ".app has been generated at $PathToApp"
echo "****************** Creating .ipa *******************"
/usr/bin/xcrun -sdk iphoneos PackageApplication -v $PathToApp/XxYyZz.app -o $PathToIpa/$Appname.ipa --embed $PathToMobileProvision --sign "$CodeSigningIdentity"
echo "$Appname.ipa has been generated at $PathToIpa"
#** Creatting the build based on configuration ends **
The file is self-descriptive you can understand easily.
Just configure the values of variable in the file and call it like below
sh Branding.sh
FYI:
If you want some other icons also to be changed besides App Icon and iTunesArtwork
use cp command e.g
cp path/to/source path/to/destination
To know more info do cp man
With the above file you can do Branding for UI and Build Settings.
For functional branding , you have to keep
Brand specific URLs
Other inputs respective to a brand
in a separate plist file so that this things also can be changed according to respective brand while building the app
In coding side you can customise your application to read the values from plist like this
Function defintion:
func getPlistFile()->Dictionary<String,AnyObject>? {
var dictPlistFile:Dictionary<String,AnyObject>?
if let path = NSBundle.mainBundle().pathForResource("plistfile", ofType: "plist") {
if let dictValue = NSDictionary(contentsOfFile: path) as? Dictionary<String, AnyObject> {
dictPlistFile=dictValue
}
}
return dictPlistFile
}
Function calling:
var Value=getPlistFile()?["Key"]
You can change the values of the key according to brand using the PlistBuddy while building the app
Here is the syntax
/usr/libexec/PlistBuddy -c "Set :Key Value" plistfile.plist
Using Jenkins
We can effectively re-use the shell script here in jenkins
1.You have to parameterise all the variables in shell script in jenkins using Add Parameter... like in the below screenshot I have done for one variable like that you have to do it for all others
2.Choose Execute shell in the Build Step
3.Copy the script that is there in between Creating the build based on configuration starts and Creating the build based on configuration ends and paste it in Execute Shell
Note:
Resource Rules
There is a known bug Regarding ResourceRules of Xcode in some versions while building and packaging the app through non-xcode interface.
So it has to be run once to deactivate a validation for resource rules path in xcode.The resource rules path is deprecated feature and apple doesn't accept apps that comes with resource rules but if we build an app without using Xcode the validation error saying resource rules has not been found will arise to counter that we have to run the script only once.
xcode_fix_PackageApplicationResourceRules.sh
#!/bin/sh
# A script to patch xcrun PackageInstallation so that it doesn't use the deprecated --resource-rules
# See "Do not use the --resource-rules flag or ResourceRules.plist. They have been obsoleted and will be rejected."
# under https://developer.apple.com/library/mac/technotes/tn2206/_index.html#//apple_ref/doc/uid/DTS40007919-CH1-TNTAG205
# Reported as Apple bug #19384243
#
# should be run as a user who can modify the PackageApplication file
xcodedir=$1
function usage {
# FIXME we cannot parse args properly because 2 are optional...
echo "USAGE: $0 xcodedir"
echo " xcodedir: an install dir like /Application/Xcode6.1.1.app"
}
if [[ $# -ne 1 ]]; then
echo "ERROR: invalid number of arguments"
usage
exit -1
fi
pi="$xcodedir/Contents/Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/PackageApplication"
piorig="$piOrig"
if [[ ! -f "$pi" ]]; then
echo "$pi file not found. Invalid argument ?"
usage
exit -1
fi
grep resource-rules "$pi"
if [[ $? -ne 0 ]]; then
echo "PackageApplication doesn't use resource-rules. Skipping"
exit 0
fi
if [[ -f "$piorig" ]]; then
echo "Backup file $piorig already exist. Aborting"
exit -1
fi
perl -p -i'Orig' -e 'BEGIN{undef $/;} s/,resource-rules(.*sign}).*ResourceRules.plist"/$1/smg' "$pi"
echo $?
Unlock keychain
Whenever you run Branding.sh in terminal it will prompt username and password as its accessing system keychain
Whenever you run the Job in jenkins you will get "User Interaction Is Not Allowed" error
so to tackle this you have to follow the below steps
Open the Keychain Access
Right click on the private key
Select "Get Info"
Select "Access Control" tab
Click "Allow all applications to access this item"
Click "Save Changes"
Enter your password
Provisioning profile
if you ever get "No Matching Provisioning Profile Found" make sure you have double clicked and installed it via Xcode.
The moment you install you'll see UUID.mobileprovision in ~/Library/MobileDevice/Provisioning Profiles/
This UUID is the value inside mobile provision that means the provisioning profile is installed.
I hope this helps you

xcodebuild is not compiling the project unless it is opened using Xcode atleast only once for cocoapods integrated project

I have a project with cocoa pods.
Here is the command that I use to build the project.
/usr/bin/xcodebuild -scheme Jenkins -workspace
/Users/Shared/Jenkins/Documents/Jenkins/Jenkins2/Jenkins.xcworkspace
-configuration Release clean build CONFIGURATION_BUILD_DIR=/Users/Shared/Jenkins/Documents/JenkinsTestNuu/app
'CODE_SIGN_IDENTITY=iPhone Distribution: XXXX yay (3G5FKTZJ2K)'
PRODUCT_BUNDLE_IDENTIFIER=com.XXXX.two
PROVISIONING_PROFILE=6e6506e9-8233-4886-9084-ce21e8f8bbae
The above script works good only if the project has been opened using Xcode atleast once after that Xcode can be closed no issues.
If the project has not been opened then If I run the script
the wheel is spinning below without any progress forever for example in the below image
if its opened once instead of the spinning wheel below texts would be shown below
=== CLEAN TARGET XWebView OF PROJECT Pods WITH CONFIGURATION Release ===
Check dependencies
Clean.Remove clean
/Users/Shared/Jenkins/Documents/JenkinsTestNuu/app/XWebView.framework.dSYM
builtin-rm -rf /Users/Shared/Jenkins/Documents/JenkinsTestNuu/app/XWebView.framework.dSYM
Clean.Remove clean
/Users/Shared/Jenkins/Library/Developer/Xcode/DerivedData/appanme-bqjwbjcqisegldeaonpytprisnig/Build/Intermediates/Pods.build/Release-iphoneos/XWebView.build
builtin-rm -rf /Users/Shared/Jenkins/Library/Developer/Xcode/DerivedData/appanme-bqjwbjcqisegldeaonpytprisnig/Build/Intermediates/Pods.build/Release-iphoneos/XWebView.build
Clean.Remove clean
/Users/Shared/Jenkins/Documents/JenkinsTestNuu/app/XWebView.framework
builtin-rm -rf /Users/Shared/Jenkins/Documents/JenkinsTestNuu/app/XWebView.framework
=== CLEAN TARGET Pods OF PROJECT Pods WITH CONFIGURATION Release ===
Check dependencies
etc...
The problem is not observed in any non-cocoapods project.
So what would be the cause and how to solve it ?
Why it happens ?
A quick diffMerge tool analysis between a project opened by Xcode Vs a same project not opened by Xcode so far
From this we can see lots of scheme related files being created once opened by Xcode inside .xcodeproj
so xcodebuild creates .app by using the scheme related meta data but as there is no scheme to build against its failing
How to solve this ?
As there is lack of meta data it couldn't build and so it requires Xcode to be opened so that the files get automactically created by Xcode and so there will be some schemes to build against.
But when you open the Xcode this Scheme related files gets created under xcuserdata which is for particular user. i.e each user gets their own file that saves state folders opened,last file opened etc...
Its not wise idea to keep this file with us.
The problem can be solved by checking the Shared Check box under Manage Schemes
This moves schemes out from under your individual xcuserdata into a shared folder that can be committed via source control and you can safely ignore xcuserdata and keep the shared folder in source control
Now we can build the code without opening the Xcode even for only one time.
Branding
(UI,Build settings and functional)
UI
App icon & other icons
iTunes Artwork
Build settings
App Name
Bundle Identifier
Provisioning profile
Code signing identity
Functional
Brand specific URLs(login,logout,resource-fetch etc...)
Using Terminal
Branding.sh
#Author: Durai Amuthan(h.duraiamuthan#gmail.com)
#This is to achieve multiple branding of an iOS app by configuring the variables below
#************ Configuring the brand starts ************
#Directory path where .xcworkspace or .xcodeproj exists
PathOfProjectDirectory=/Users/Shared/Jenkins/Documents/JenkinsTestNuu/New/
#Path where info.plist exists
PathOfInfoPlist=$PathOfProjectDirectory/XxYyZz
#Path to icons where new iTunesArtwork and application icon exixts
#Note: Make sure proper naming conventions of file has been followed
PathOfNewIcons=/Users/Shared/Jenkins/Documents/icons-two
#Path to asset resource where you have kept your application icon.
PathOfAppIconSet=$PathOfProjectDirectory/XxYyZz/Icon.xcassets/AppIcon.appiconset
#Path where do you want the .app file has to be kept
PathToApp=/Users/Shared/Jenkins/Documents/JenkinsTestNuu/app
#Path where do you want the .ipa file has to kept
PathToIpa=/Users/Shared/Jenkins/Documents/JenkinsTestNuu/ipa
#Cocoapods project or project that involves more than one modules are scheme based
isWorkspaceBased=true
#Path of the Project (.xcodeproj) - applicable for workspace(.xcworkspace) based project
PathofProjectFile=$PathOfProjectDirectory/XxYyZz.xcodeproj
#Path of the Workspace (.xcworkspace)
PathofWorkspaceFile=$PathOfProjectDirectory/XxYyZz.xcworkspace
#Name of the target - applicable only for non-workspace(.xcodeproj) based projects
Target=XxYyZz
#Scheme of the iOS app
Scheme=XxYyZz
#To ascertain Cocoapods has been used or not
isCocoaPodsBased=true
#Configuration of the app (Debug -(Development) or Release(Adhoc or Distribution))
Config=Release
#For giving access to signing idetity found in KeyChain
LoginKeychainPath=/Users/Shared/Jenkins/Library/Keychains/login.keychain
LoginKeyChainPassword=xxyyzz
#Name of the code signing identity.You can find the name in Keychain or xcode build setting
CodeSigningIdentity='iPhone Distribution: Xx Yy Zz Limited (3Z5MHUYJ2L)'
#Path of the provisioning profile
PathToMobileProvision=/Users/Shared/Jenkins/Desktop/BrandingTest.mobileprovision
#UUID value found inside Provisioning profile has to be given
#Do not forget to install provisiong profile in the system
ProvisioningProfileIdentity=6e6506e9-8233-4886-9084-zf21e8f8bbae
#Bundle identifier of the app
BundleIdentifier=com.xxyy.zz
#AppVersion of the app
AppVersion=2.2.2
#App Name
Appname=Two
#************ Configuring the brand ends ************
#** Creatting the build based on configuration starts **
cd $PathOfInfoPlist
echo "****************** Setting App Name ******************"
/usr/libexec/PlistBuddy -c "Set :CFBundleName $Appname" info.plist
/usr/libexec/PlistBuddy -c "Set :CFBundleDisplayName $Appname" info.plist
echo "app name has been set as $Appname"
cd $PathOfProjectDirectory
echo "****************** Setting AppVersion ******************"
/usr/bin/agvtool new-marketing-AppVersion $AppVersion
/usr/bin/agvtool new-AppVersion -all $AppVersion
echo "****************** Changing app icons & iTunes Artwork ******************"
cp -R $PathOfNewIcons/*.png $PathOfAppIconSet
echo "App icons has been changed at $PathOfNewIcons"
cp -R $PathOfNewIcons/iTunesArtwork#2x $PathOfProjectDirectory/XxYyZz
cp -R $PathOfNewIcons/iTunesArtwork $PathOfProjectDirectory/XxYyZz
echo "iTunesArtwork has been changed at $PathOfProjectDirectory"
#Unlock login keychain
security unlock-keychain -p $LoginKeyChainPassword $LoginKeychainPath
if $isCocoaPodsBased == 'true'
then
echo "****************** Installing Cocoapods **********************"
/usr/local/bin/pod install
echo "Cocoapods has been installed"
fi
echo "****************** Creating .app ******************"
if $isWorkspaceBased == 'true'
then
/usr/bin/xcodebuild -scheme $Scheme -workspace $PathofWorkspaceFile -configuration $Config clean build CONFIGURATION_BUILD_DIR=$PathToApp "CODE_SIGN_IDENTITY=$CodeSigningIdentity" "PRODUCT_BUNDLE_IDENTIFIER=$BundleIdentifier" "PROVISIONING_PROFILE=$ProvisioningProfileIdentity"
else
/usr/bin/xcodebuild -target $Target -project $PathofProjectFile -configuration $Config clean build CONFIGURATION_BUILD_DIR=$PathToApp "CODE_SIGN_IDENTITY=$CodeSigningIdentity" "PRODUCT_BUNDLE_IDENTIFIER=$BundleIdentifier" "PROVISIONING_PROFILE=$ProvisioningProfileIdentity"
fi
echo ".app has been generated at $PathToApp"
echo "****************** Creating .ipa *******************"
/usr/bin/xcrun -sdk iphoneos PackageApplication -v $PathToApp/XxYyZz.app -o $PathToIpa/$Appname.ipa --embed $PathToMobileProvision --sign "$CodeSigningIdentity"
echo "$Appname.ipa has been generated at $PathToIpa"
#** Creatting the build based on configuration ends **
The file is self-descriptive you can understand easily.
Just configure the values of variable in the file and call it like below
sh Branding.sh
FYI:
If you want some other icons also to be changed besides App Icon and iTunesArtwork
use cp command e.g
cp path/to/source path/to/destination
To know more info do cp man
With the above file you can do Branding for UI and Build Settings.
For functional branding , you have to keep
Brand specific URLs
Other inputs respective to a brand
in a separate plist file so that this things also can be changed according to respective brand while building the app
In coding side you can customise your application to read the values from plist like this
Function defintion:
func getPlistFile()->Dictionary<String,AnyObject>? {
var dictPlistFile:Dictionary<String,AnyObject>?
if let path = NSBundle.mainBundle().pathForResource("plistfile", ofType: "plist") {
if let dictValue = NSDictionary(contentsOfFile: path) as? Dictionary<String, AnyObject> {
dictPlistFile=dictValue
}
}
return dictPlistFile
}
Function calling:
var Value=getPlistFile()?["Key"]
You can change the values of the key according to brand using the PlistBuddy while building the app
Here is the syntax
/usr/libexec/PlistBuddy -c "Set :Key Value" plistfile.plist
Using Jenkins
We can effectively re-use the shell script here in jenkins
1.You have to parameterise all the variables in shell script in jenkins using Add Parameter... like in the below screenshot I have done for one variable like that you have to do it for all others
2.Choose Execute shell in the Build Step
3.Copy the script that is there in between Creating the build based on configuration starts and Creating the build based on configuration ends and paste it in Execute Shell
Note:
Resource Rules
There is a known bug Regarding ResourceRules of Xcode in some versions while building and packaging the app through non-xcode interface.
So it has to be run once to deactivate a validation for resource rules path in xcode.The resource rules path is deprecated feature and apple doesn't accept apps that comes with resource rules but if we build an app without using Xcode the validation error saying resource rules has not been found will arise to counter that we have to run the script only once.
xcode_fix_PackageApplicationResourceRules.sh
#!/bin/sh
# A script to patch xcrun PackageInstallation so that it doesn't use the deprecated --resource-rules
# See "Do not use the --resource-rules flag or ResourceRules.plist. They have been obsoleted and will be rejected."
# under https://developer.apple.com/library/mac/technotes/tn2206/_index.html#//apple_ref/doc/uid/DTS40007919-CH1-TNTAG205
# Reported as Apple bug #19384243
#
# should be run as a user who can modify the PackageApplication file
xcodedir=$1
function usage {
# FIXME we cannot parse args properly because 2 are optional...
echo "USAGE: $0 xcodedir"
echo " xcodedir: an install dir like /Application/Xcode6.1.1.app"
}
if [[ $# -ne 1 ]]; then
echo "ERROR: invalid number of arguments"
usage
exit -1
fi
pi="$xcodedir/Contents/Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/PackageApplication"
piorig="$piOrig"
if [[ ! -f "$pi" ]]; then
echo "$pi file not found. Invalid argument ?"
usage
exit -1
fi
grep resource-rules "$pi"
if [[ $? -ne 0 ]]; then
echo "PackageApplication doesn't use resource-rules. Skipping"
exit 0
fi
if [[ -f "$piorig" ]]; then
echo "Backup file $piorig already exist. Aborting"
exit -1
fi
perl -p -i'Orig' -e 'BEGIN{undef $/;} s/,resource-rules(.*sign}).*ResourceRules.plist"/$1/smg' "$pi"
echo $?
Unlock keychain
Whenever you run Branding.sh in terminal it will prompt username and password as its accessing system keychain
Whenever you run the Job in jenkins you will get "User Interaction Is Not Allowed" error
so to tackle this you have to follow the below steps
Open the Keychain Access
Right click on the private key
Select "Get Info"
Select "Access Control" tab
Click "Allow all applications to access this item"
Click "Save Changes"
Enter your password
Provisioning profile
if you ever get "No Matching Provisioning Profile Found" make sure you have double clicked and installed it via Xcode.
The moment you install you'll see UUID.mobileprovision in ~/Library/MobileDevice/Provisioning Profiles/
This UUID is the value inside mobile provision that means the provisioning profile is installed.
I hope this helps you
You need to run pod install before building the project so that CocoaPods fetches the Pods specified in your Podfile within the Jenkins workspace.

Jenkins + iOS + TestFlight API

I installed a Jenkins and startet a Project with the Git Plugin, Xcode Plugin and the Testflight Plugin.
I can create automatic builds with the setup, but it is failing at the point on creating the .ipa files for Testflight.
The problem are at Debug and Release settings in different ways though…
If i try to create a .ipa via the Debug settings it will fail at the point that there is no build/Debug-iphoneos folder (i tried to turn of the clean option but it didn't helped). But the Xcode Build is not failing on the command line
When i try to switch to Release the linker is failing (ld).
Whithout the .ipa files i can't submit to Testflight and get a automated Test distributing.
Here is the script I'm using. (Obviously I removed the personal information, but you should be fine to understand it).
TARGET_NAME="-" # Target name
TARGET_SDK="iphoneos" # Target SDK: iphoneos
CONFIGURATION="Release" # Build Configuration
BUILD_DIR="build" # Directory where the build is generated
ARCHS="armv7" # Valid Architectures
APP_NAME="-" # Application name
## Provisioning configurations
BUILD_ARCHIVED_DIR="BuildArchived" # Directory with the history of builds
DEVELOPER_NAME="-" # Developer name
PROVISIONING_PROFILE=Prototype.mobileprovision # Provisioning profile file
PROVISIONING_DIR=~/Library/MobileDevice/Provisioning\ Profiles/ # Provisioning dir
## TestFlight App
TESTFLIGHT_API_TOKEN="-"
TESTFLIGHT_TEAM_TOKEN="-"
#Release Notes
BUILDSCRIPTS_DIR="build"
TESTFLIGHT_RELEASE_NOTES_FILE="ios_testflight-releasenotes"
#Distribution Lists
TESTFLIGHT_DISTRIBUTION_LISTS="Jenkins"
# Returns to the root directory of the build
cd ../ios
PROJECT_BUILDDIR="${BUILD_DIR}/${CONFIGURATION}-${TARGET_SDK}"
CURRENT_DIR=`pwd`
# fix for the newest sdk
# Only export the environment variable if the location exists,
# otherwise it breaks the signing process!
if [ -f "/Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/codesign_allocate" ]
then
echo Export environment variable for codesign_allocate location
export CODESIGN_ALLOCATE=/Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/codesign_allocate
fi
#changing the build version
INFO_PLIST_PATH="${CURRENT_DIR}/${TARGET_NAME}/${TARGET_NAME}-Info.plist"
/usr/libexec/PlistBuddy -c "Set :CFBundleVersion ${SVN_REVISION}" $INFO_PLIST_PATH
# compile project
echo Building Project
xcodebuild -target "${TARGET_NAME}" -sdk "${TARGET_SDK}" ARCHS=${ARCHS} -configuration "${CONFIGURATION}" clean build
#Check if build succeeded
#if [ $? != 0 ]
#then
# exit 1
#fi
# Create output dir ($x) if doesn't exist
mkdir -p $BUILD_ARCHIVED_DIR
# .ipa file generation
echo Generating .ipa file
/usr/bin/xcrun -sdk "${TARGET_SDK}" PackageApplication -v "${PROJECT_BUILDDIR}/${APP_NAME}.app" -o "${CURRENT_DIR}/${BUILD_ARCHIVED_DIR}/${APP_NAME}.ipa" --sign "${DEVELOPER_NAME}"
#zipping the .dSYM to send to Testflight
echo Generating zip file
/usr/bin/zip -r "${CURRENT_DIR}/${BUILD_ARCHIVED_DIR}/${APP_NAME}.app.dSYM.zip" "${CURRENT_DIR}/${PROJECT_BUILDDIR}/${APP_NAME}.app.dSYM"
echo Sending to TestFlight
curl http://testflightapp.com/api/builds.json -F file="#${CURRENT_DIR}/${BUILD_ARCHIVED_DIR}/${APP_NAME}.ipa" -F dsym="#${CURRENT_DIR}/${BUILD_ARCHIVED_DIR}/${APP_NAME}.app.dSYM.zip" -F api_token="${TESTFLIGHT_API_TOKEN}" -F team_token="${TESTFLIGHT_TEAM_TOKEN}" -F notes="This build was uploaded via the upload API" -F notify=False -F distribution_lists="${TESTFLIGHT_DISTRIBUTION_LISTS}"
echo Submission ended
I imagine the Scheme your build is targeting is incorrect.
Additionally, TestFlight has a plugin for Jenkins so you can script your build process and execute the upload to TestFlight using the their Jenkins Plugin. I have provided a build script example that works for me via manual command line and under Jenkins CI.
If you would like to see the full setup, you can find a iOS/Git/TestFlight tutorial here: Jenkins iOS – Git, xcodebuild, TestFlight
xcodebuild -alltargets clean
rm -rf "./JenkinsBuild/*"
xcodebuild -target HelloJenkins PROVISIONING_PROFILE="00000000-0000-0000-0000-000000000000" CONFIGURATION_BUILD_DIR=JenkinsBuild
rm -rf "./JenkinsArchive/*"
xcodebuild -scheme HelloJenkins archive PROVISIONING_PROFILE="00000000-0000-0000-0000-000000000000" CODE_SIGN_IDENTITY="iPhone Developer: Jonny Appleseed (XXXXXXXXXX)" -archivePath ./JenkinsArchive/HelloJenkins.xcarchive
rm -rf "./JenkinsIPAExport/*"
xcodebuild -exportArchive -exportFormat IPA -exportProvisioningProfile iOS\ Team\ Provisioning\ Profile:\ com.yourAPP.HelloJenkins -archivePath ./JenkinsArchive/HelloJenkins.xcarchive -exportPath ./JenkinsIPAExport/HelloJenkins.ipa

Is there any automatic Testflight upload script on application archiving?

I found that Testflight is supporting application uploading through API call http://testflightapp.com/api/builds.format. It accepts application package, dsyms, application info and other.
So my question is next: Is there any automatic script for xcode which will upload build into Testflight after "archive" operation? Share the links, please.
SOLUTION IS HERE (Mac OS X 10.8):
1) Follow this manual and setup post-execution script
2) Remove Replace "echo" strings with next rule:
#!/bin/bash
#
# (Above line comes out when placing in Xcode scheme)
#
API_TOKEN="<YOUR-TESTFLIGHT-API-TOKEN>"
TEAM_TOKEN="<YOUR-TESTFLIGHT-TEAM-TOKEN>"
SIGNING_IDENTITY="iPhone Developer"
PROVISIONING_PROFILE="${HOME}/Library/MobileDevice/Provisioning Profiles/<YOUR-PROFILE-NAME>.mobileprovision"
LOG="/tmp/testflight.log"
GROWL="/usr/bin/terminal-notifier -title Xcode -message"
DATE=$( /bin/date +"%Y-%m-%d" )
ARCHIVE=$( /bin/ls -t "${HOME}/Library/Developer/Xcode/Archives/${DATE}" | /usr/bin/grep xcarchive | /usr/bin/sed -n 1p )
DSYM="${HOME}/Library/Developer/Xcode/Archives/${DATE}/${ARCHIVE}/dSYMs/${PRODUCT_NAME}.app.dSYM"
APP="${HOME}/Library/Developer/Xcode/Archives/${DATE}/${ARCHIVE}/Products/Applications/${PRODUCT_NAME}.app"
#/usr/bin/open -a /Applications/Utilities/Console.app $LOG
#echo -n "Creating .ipa for ${PRODUCT_NAME}... " > $LOG
${GROWL} "Creating .ipa for ${PRODUCT_NAME}"
/bin/rm "/tmp/${PRODUCT_NAME}.ipa"
/usr/bin/xcrun -sdk iphoneos PackageApplication -v "${APP}" -o "/tmp/${PRODUCT_NAME}.ipa" --sign "${SIGNING_IDENTITY}" --embed "${PROVISIONING_PROFILE}"
#echo "done." >> $LOG
${GROWL} "Created .ipa for ${PRODUCT_NAME}"
#echo -n "Zipping .dSYM for ${PRODUCT_NAME}..." >> $LOG
${GROWL} "Zipping .dSYM for ${PRODUCT_NAME}"
/bin/rm "/tmp/${PRODUCT_NAME}.dSYM.zip"
/usr/bin/zip -r "/tmp/${PRODUCT_NAME}.dSYM.zip" "${DSYM}"
#echo "done." >> $LOG
${GROWL} "Created .dSYM for ${PRODUCT_NAME}"
#echo -n "Uploading to TestFlight... " >> $LOG
${GROWL} "Uploading to TestFlight"
/usr/bin/curl "http://testflightapp.com/api/builds.json" \
-F file=#"/tmp/${PRODUCT_NAME}.ipa" \
-F dsym=#"/tmp/${PRODUCT_NAME}.dSYM.zip" \
-F api_token="${API_TOKEN}" \
-F team_token="${TEAM_TOKEN}" \
-F notes="Build uploaded automatically from Xcode."
#echo "done." >> $LOG
${GROWL} "Uploaded to TestFlight"
/usr/bin/open "https://testflightapp.com/dashboard/builds/"
3) Reveal provision profile in finder: go to Organazier/Devices/Provision profiles, then right mouse on your profile, and click "Reveal in finder". Copy profile name and paste to PROVISIONING_PROFILE variable instead of <YOUR-PROFILE-NAME>
4) Open terminal and install terminal-notifier:
sudo gem install terminal-notifier
5) You're ready :)
I've also created a ruby gem for this if you want to integrate this into rake tasks:
gem install testflight_upload
source on my github here
Here's a nice collection of utilities http://nomad-cli.com/
I ended up using Shenzen to automate builds and testflight deployments.
Here is one nice tutorial..may be useful for you:
http://developmentseed.org/blog/2011/sep/02/automating-development-uploads-testflight-xcode/
Shenzhen is discontinued, you can use pilot instead. It's a Ruby based tool to upload new builds and manage your beta testers. Under the hood it uses the iTunes Transporter and spaceship.

Resources