xcode command line to configure "embed frameworks" - ios

As showed in the screen above, I couldn't find any xcodebuild command line to add/remove the embed frameworks, is there any way we can do so via command line (to remove or add the line)? As I need to automate the build process.

For conditionally embedding frameworks to your app you should make a script under Build Phases that copies your dynamic library to Frameworks folder of your app and then sign it e.g.:
# Path to your framework to copy. You must have two compiled versions: Debug(arm64, x86_64) and Release(arm64).
FRAMEWORK=".../$CONFIGURATION/MyFramework.framework"
# Frameworks folder of your app
NAME=$(basename $FRAMEWORK)
DESTINATION=${BUILT_PRODUCTS_DIR}/${FRAMEWORKS_FOLDER_PATH}/$NAME
# Copy (if needed) and sign
if [ ! -d $DESTINATION ]; then
cp -r $FRAMEWORK $DESTINATION
codesign --force --sign ${EXPANDED_CODE_SIGN_IDENTITY} ${OTHER_CODE_SIGN_FLAGS:-} --preserve-metadata=identifier,entitlements $DESTINATION
fi
For xcframework you can specify subfolder path in additional for a target arch:
# Release device only
if [ $PLATFORM_PREFERRED_ARCH == "arm64" ]; then
FRAMEWORK=".../MyFramework.xcframework/ios-arm64/MyFramework.framework"
fi

Related

Turn Package.swift file into binary XCFramework

Someone in my company created a Swift package SDK and now I was tasked to publish it for the customer in a binary way so that the end customers that will use the SDK will not be able to see the source code of it. This is how the SDK is built:
the SDK in xcode (p.s. the build folder is empty)
From my reading on the subject I understand that I need to export the files into an XCFramework file. However, the vast majority of guides I've encountered explain how to make this progress from a framework, and not from a package like in my case..
The only guide I found that seems exactly like what I need is this one, however I get an error right on the first relevant terminal command of xcodebuild -scheme [my scheme name] -sdk iphoneos -configuration Release ARCHS="arm64" BUILD_DIR="./Build". This is the main error line I get: xcodebuild: error: Building a Swift package requires that a destination is provided using the "-destination" option. The "-showdestinations" option can be used to list the available destinations.. Why would I need to specify a destination? I want the SDK to work for all the devices (ios 13+). Non of the forums I searched in online helped me solve this.
I also read Apple's instructions here but got very confused about how the terminal command in step 2 is supposed to look like in my case. Are some of the fields mandatory and some are not?
Any help would be much appreciated!!
Assuming you are working with iOS only and you need an xcframework for both device and simulator architectures, in order to generate an XCFramework from a swift package you need to:
Mark your Package as .dynamic (i.e. .library(name: "Foo", type: .dynamic, targets: ["Foo"]))
Archive the project for both simulator and device. This will generate a .framework file for each architecture.
Copy Modules folders (if any) into the .xcarchive files
Copy the bundles (if any) into the .xcarchive files
Create the xcframework with the frameworks created in step 2
Here's a bash script, based on the one from this swift forums post, to create an XCFramework from a swift package (in my case, I have my package inside an xcworkspace. I didn't try it as a standalone package, not sure if that can be done):
Change the input parameters as needed :), but most importantly replace <Your project name> and <your workspace>.
#!/bin/bash
PROJECT_NAME="<Your project name>"
PROJECT_DIR="./Packages/${PROJECT_NAME}" # Relative path to the directory containing the `Package.swift` file
BUILD_FOLDER="./build"
OUTPUT_DIR="${PROJECT_DIR}/Output"
SIMULATOR_ARCHIVE="${OUTPUT_DIR}/${PROJECT_NAME}-iphonesimulator.xcarchive"
DEVICE_ARCHIVE="${OUTPUT_DIR}/${PROJECT_NAME}-iphoneos.xcarchive"
rm -rf "$OUTPUT_DIR"
mkdir -p "$OUTPUT_DIR"
# 2 iterations: 1 for device arch and another for simulator arch
for PLATFORM in "iOS" "iOS Simulator"; do
case $PLATFORM in
"iOS")
ARCHIVE=$DEVICE_ARCHIVE
SDK=iphoneos
RELEASE_FOLDER="Release-iphoneos"
;;
"iOS Simulator")
ARCHIVE=$SIMULATOR_ARCHIVE
SDK=iphonesimulator
RELEASE_FOLDER="Release-iphonesimulator"
;;
esac
# Step 2
xcodebuild archive \
-workspace <your workspace>.xcworkspace \
-scheme $PROJECT_NAME \
-destination="generic/platform=${PLATFORM}" \
-archivePath $ARCHIVE \
-sdk $SDK \
-derivedDataPath $BUILD_FOLDER \
SKIP_INSTALL=NO \
BUILD_LIBRARY_FOR_DISTRIBUTION=YES
FRAMEWORK_PATH="${ARCHIVE}/Products/Library/Frameworks/${PROJECT_NAME}.framework"
MODULES_PATH="$FRAMEWORK_PATH/Modules"
mkdir -p $MODULES_PATH
BUILD_PRODUCTS_PATH="${BUILD_FOLDER}/Build/Intermediates.noindex/ArchiveIntermediates/${PROJECT_NAME}/BuildProductsPath"
RELEASE_PATH="${BUILD_PRODUCTS_PATH}/${RELEASE_FOLDER}"
SWIFT_MODULE_PATH="${RELEASE_PATH}/${PROJECT_NAME}.swiftmodule"
RESOURCES_BUNDLE_PATH="${RELEASE_PATH}/${PROJECT_NAME}_${PROJECT_NAME}.bundle"
# Step 3
if [ -d $SWIFT_MODULE_PATH ]
then
cp -r $SWIFT_MODULE_PATH $MODULES_PATH
fi
# Step 4
if [ -e $RESOURCES_BUNDLE_PATH ]
then
cp -r $RESOURCES_BUNDLE_PATH $FRAMEWORK_PATH
fi
done
# Step 5
xcodebuild -create-xcframework \
-framework "${DEVICE_ARCHIVE}/Products/Library/Frameworks/${PROJECT_NAME}.framework" \
-framework "${SIMULATOR_ARCHIVE}/Products/Library/Frameworks/${PROJECT_NAME}.framework" \
-output "${OUTPUT_DIR}/${PROJECT_NAME}.xcframework"
When the script ends, you will see 3 files in the output folder:
Device xcarchive
Simulator xcarchive
XCFramework
You can remove the xcarchives, as you won't need them anymore (you can also update the script to do that for you).

Xcode 12.4 React native build failed in IOS Showing All Messages Command PhaseScriptExecution failed with a nonzero exit code

i am new in react native i want to run react native app in IOS after react-native init, app not run in IOS show some error
Showing All Messages
bash: Native/social_login/socialLogin/node_modules/react-native/scripts/../Libraries: No such file or directory
Command PhaseScriptExecution failed with a nonzero exit code
and build failed please help me
versions
"react": "17.0.1",
"react-native": "0.64.0"
command line tools : Xcode 12.4 (12D4e)
This happened also to me upgrading from 0.63 to 0.64. After trying all solutions I followed a solution moving the folder to a directory where the path contain no spaces and it works and build the app successfully.
Solution to React Native 0.64 build fail
In order for this to work properly follow these steps:
If you previously installed a global react-native-cli package, please
remove it as it may cause unexpected issues (i.e. npm uninstall -g
react-native-cli)
Move the project folder in a path with no spaces (i.e. ~/sub folder
name/ReactNativeApp won't work till you have spaces in the path, so
move in a path like ~/folder/ReactNativeApp)
Then cd into the project folder and upgrade react native to the
latest version with npx react-native upgrade and resolve conflicts if
any
After upgrading remove the node_modules folder and the yarn.lock from
the root and the podfile.lock and Pods folder from ios subfolder
Then cd back to the root and run yarn install && npx pod-install
Now run again your app in Xcode or your IDE and it works
Crazy and absurd that a space in the path-name could cause this issue
This is nothing just an issue with the scheme name for me, in my case my scheme name contains whitespace e.g. "ABC staging", which is not allowed, it got fixed after deleting and creating a new scheme with the name "ABC-staging".
in the case of react-native 0.67^, you may need to apply these changes as well
change line no 7
set -e. ==> set +e
in
node_modules/react-native/scripts/find-node.sh
then use patch-package using the following command :
npx patch-package react-native
this will create a patch file inside the patch folder in root, then you can add in the post-install script in package.json:
"postinstall": "npx patch-package"
This command will run each time a new package is getting added to the project and auto-fix react-native find-node. sh.
Try to run pod install in ios folder
cd ios && pod install
Then when it's done go back to your main folder and run
yarn run ios
If that doesn't work, check out the solutions here
Xcode 10.2.1 Command PhaseScriptExecution failed with a nonzero exit code
There seems to be an issue with coreutils on macOS.
What fixed it for me is:
brew install coreutils
brew install findutils
brew install gnu-sed
Finally change the node_modules/react-native/scripts/generate-specs.sh to:
#!/bin/bash
# Copyright (c) Facebook, Inc. and its affiliates.
#
# This source code is licensed under the MIT license found in the
# LICENSE file in the root directory of this source tree.
# This script collects the JavaScript spec definitions for core
# native modules and components, then uses react-native-codegen
# to generate native code.
#
# Optionally, set these envvars to override defaults:
# - SRCS_DIR: Path to JavaScript sources
# - CODEGEN_MODULES_LIBRARY_NAME: Defaults to FBReactNativeSpec
# - CODEGEN_MODULES_OUTPUT_DIR: Defaults to React/$CODEGEN_MODULES_LIBRARY_NAME/$CODEGEN_MODULES_LIBRARY_NAME
# - CODEGEN_COMPONENTS_LIBRARY_NAME: Defaults to rncore
# - CODEGEN_COMPONENTS_OUTPUT_DIR: Defaults to ReactCommon/react/renderer/components/$CODEGEN_COMPONENTS_LIBRARY_NAME
#
# Usage:
# ./scripts/generate-specs.sh
# SRCS_DIR=myapp/js CODEGEN_MODULES_LIBRARY_NAME=MySpecs CODEGEN_MODULES_OUTPUT_DIR=myapp/MySpecs ./scripts/generate-specs.sh
#
# shellcheck disable=SC2038
set -e
THIS_DIR=$(cd -P "$(gdirname "$(greadlink "${BASH_SOURCE[0]}" || echo "${BASH_SOURCE[0]}")")" && pwd)
TEMP_DIR=$(gmktemp -d /tmp/react-native-codegen-XXXXXXXX)
RN_DIR=$(cd "$THIS_DIR/.." && pwd)
# find node path
source "$RN_DIR/scripts/find-node.sh"
NODE_BINARY="${NODE_BINARY:-$(command -v node || true)}"
USE_FABRIC="${USE_FABRIC:-0}"
cleanup () {
set +e
grm -rf "$TEMP_DIR"
set -e
}
describe () {
printf "\\n\\n>>>>> %s\\n\\n\\n" "$1"
}
main() {
SRCS_DIR=${SRCS_DIR:-$(cd "$RN_DIR/Libraries" && pwd)}
CODEGEN_MODULES_LIBRARY_NAME=${CODEGEN_MODULES_LIBRARY_NAME:-FBReactNativeSpec}
CODEGEN_COMPONENTS_LIBRARY_NAME=${CODEGEN_COMPONENTS_LIBRARY_NAME:-rncore}
CODEGEN_MODULES_OUTPUT_DIR=${CODEGEN_MODULES_OUTPUT_DIR:-"$RN_DIR/React/$CODEGEN_MODULES_LIBRARY_NAME/$CODEGEN_MODULES_LIBRARY_NAME"}
# TODO: $CODEGEN_COMPONENTS_PATH should be programmatically specified, and may change with use_frameworks! support.
CODEGEN_COMPONENTS_PATH="ReactCommon/react/renderer/components"
CODEGEN_COMPONENTS_OUTPUT_DIR=${CODEGEN_COMPONENTS_OUTPUT_DIR:-"$RN_DIR/$CODEGEN_COMPONENTS_PATH/$CODEGEN_COMPONENTS_LIBRARY_NAME"}
TEMP_OUTPUT_DIR="$TEMP_DIR/out"
SCHEMA_FILE="$TEMP_DIR/schema.json"
if [ -z "$NODE_BINARY" ]; then
echo "Error: Could not find node. Make sure it is in bash PATH or set the NODE_BINARY environment variable." 1>&2
exit 1
fi
CODEGEN_PATH=$("$NODE_BINARY" -e "console.log(require('path').dirname(require.resolve('react-native-codegen/package.json')))")
# Special case for running CodeGen from source: build it
if [ ! -d "$CODEGEN_PATH/lib" ]; then
describe "Building react-native-codegen package"
bash "$CODEGEN_PATH/scripts/oss/build.sh"
fi
describe "Generating schema from flow types"
"$NODE_BINARY" "$CODEGEN_PATH/lib/cli/combine/combine-js-to-schema-cli.js" "$SCHEMA_FILE" "$SRCS_DIR"
describe "Generating native code from schema (iOS)"
pushd "$RN_DIR" >/dev/null || exit 1
"$NODE_BINARY" scripts/generate-specs-cli.js ios "$SCHEMA_FILE" "$TEMP_OUTPUT_DIR" "$CODEGEN_MODULES_LIBRARY_NAME"
popd >/dev/null || exit 1
describe "Copying output to final directory"
gmkdir -p "$CODEGEN_COMPONENTS_OUTPUT_DIR" "$CODEGEN_MODULES_OUTPUT_DIR"
gcp -R "$TEMP_OUTPUT_DIR/$CODEGEN_MODULES_LIBRARY_NAME.h" "$TEMP_OUTPUT_DIR/$CODEGEN_MODULES_LIBRARY_NAME-generated.mm" "$CODEGEN_MODULES_OUTPUT_DIR" || exit 1
gfind "$TEMP_OUTPUT_DIR" -type f | gxargs gsed -i.bak "s/$CODEGEN_MODULES_LIBRARY_NAME/$CODEGEN_COMPONENTS_LIBRARY_NAME/g" || exit 1
gfind "$TEMP_OUTPUT_DIR" -type f -not -iname "$CODEGEN_MODULES_LIBRARY_NAME*" -exec cp '{}' "$CODEGEN_COMPONENTS_OUTPUT_DIR/" ';' || exit 1
echo >&2 'Done.'
}
trap cleanup EXIT
main "$#"
notice that some commands are starting with g like greadlink etc.
if your get invalid identifier error in react-native-xcode.sh then under Build Phases -> Bundle React Native code and images it should be: (notice the double quotes):
set -e
export NODE_BINARY="node ../node_modules/react-native/scripts/react-native-xcode.sh"
use patch-package react-native to patch it (if project is being developed on different machines then they must install the brew packages above)
For me it was just having a space in folder name which was in the path of project folder from root.
I had to delete the contents of my ~/.bash_profile file.
I don't even use bash, but some other script populated the file and that broke my build. Deleting the contents fixed the build, immediately. Might not work for you, but thought I'd share.
I'm running Xcode 13.4.1
Installed cocoapods using brew install cocoapods (https://brew.sh/index_es)
M2 apple chip
React Native 0.70
Actually after spending a whole lot of time trying different solutions none of them worked except for Giuseppe's answer. I had white spaces in my path
"/React Native/exampleProject"
1. Renamed folders/files to remove any white space in the path (creating a fresh project within the fixed path worked with no problems at all)
I didn't even had to execute pod install anymore in the ios folder
In my case, i had to export the right path to node
in your terminal type which node, copy the path and export it in ios/xcode.env
export NODE_BINARY="copied node path"
Ok, worth trying this.
(This usually happens if you had multiple imports or any imports missing)
As soon as we get this error message:
Always scroll up & read the issue if written in that log file. Any issues like syntax error or issue related to your js code.
If yes, you can fix that first & re build it.
In my case I had multiple imports of one of the RN components.
Adding $(ARCHS_STANDARD) to Valid Architectures in Build Settings solved it for me

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.

Xcode - symbol(s) not found for architecture x86_64 (iOS Lib)

I am building a static library. The build setting has the Architectures set to: $(ARCHS_STANDARD) which is shown as Standard Architectures (armv7, armv7s, arm64) I build the lib choosing iOS Device AND then using the simulator (for example iPhone Retina).
Now that I have two builds (one inside Debug-iphoneos and the other inside Debug-iphonesimulator, I use lipo -create to create the aggregated lib:
lipo -create path/to/first/lib /path/to/second/lib -o MyLib.a
If I used this library in another project to simulate on any iOS device with 64-bit architecture, it gives symbol(s) not found for architecture x86_64. What really makes me so angry that the lib project itself is inside a workspace with another project that use the lib. I can simulate on 64-bit iOS simulator! (on all simulators and devices for that matter). What am I doing wrong?
Notes:
This is not duplicate Q. Before accusing me of that (since this is my second day trying to fix this stupid issue), I did search on Stack and Google. All answers don't help.
I am using Xcode 5.1.1.
I had the same trouble with building static library.
Finally I have found the basic solution. (You need to build universal library for x86_64/armv7/armv7s/arm64)
1) Click on the project file
2) Click on the target
3) Open "Build Phases"
4) Open "Run Script"
5) Add "/bin/sh" and the script below
##########################################
#
# c.f. http://stackoverflow.com/questions/3520977/build-fat-static-library-device-simulator-using-xcode-and-sdk-4
#
# Version 2.7
#
# Latest Change:
# - Supports iPhone 5 / iPod Touch 5 (uses Apple's workaround to lipo bug)
#
# Purpose:
# Automatically create a Universal static library for iPhone + iPad + iPhone Simulator from within XCode
#
# Author: Adam Martin - http://twitter.com/redglassesapps
# Based on: original script from Eonil (main changes: Eonil's script WILL NOT WORK in Xcode GUI - it WILL CRASH YOUR COMPUTER)
#
set -e
set -o pipefail
#################[ Tests: helps workaround any future bugs in Xcode ]########
#
DEBUG_THIS_SCRIPT="false"
if [ $DEBUG_THIS_SCRIPT = "true" ]
then
echo "########### TESTS #############"
echo "Use the following variables when debugging this script; note that they may change on recursions"
echo "BUILD_DIR = $BUILD_DIR"
echo "BUILD_ROOT = $BUILD_ROOT"
echo "CONFIGURATION_BUILD_DIR = $CONFIGURATION_BUILD_DIR"
echo "BUILT_PRODUCTS_DIR = $BUILT_PRODUCTS_DIR"
echo "CONFIGURATION_TEMP_DIR = $CONFIGURATION_TEMP_DIR"
echo "TARGET_BUILD_DIR = $TARGET_BUILD_DIR"
fi
#####################[ part 1 ]##################
# First, work out the BASESDK version number (NB: Apple ought to report this, but they hide it)
# (incidental: searching for substrings in sh is a nightmare! Sob)
SDK_VERSION=$(echo ${SDK_NAME} | grep -o '.\{3\}$')
# Next, work out if we're in SIM or DEVICE
if [ ${PLATFORM_NAME} = "iphonesimulator" ]
then
OTHER_SDK_TO_BUILD=iphoneos${SDK_VERSION}
else
OTHER_SDK_TO_BUILD=iphonesimulator${SDK_VERSION}
fi
echo "XCode has selected SDK: ${PLATFORM_NAME} with version: ${SDK_VERSION} (although back-targetting: ${IPHONEOS_DEPLOYMENT_TARGET})"
echo "...therefore, OTHER_SDK_TO_BUILD = ${OTHER_SDK_TO_BUILD}"
#
#####################[ end of part 1 ]##################
#####################[ part 2 ]##################
#
# IF this is the original invocation, invoke WHATEVER other builds are required
#
# Xcode is already building ONE target...
#
# ...but this is a LIBRARY, so Apple is wrong to set it to build just one.
# ...we need to build ALL targets
# ...we MUST NOT re-build the target that is ALREADY being built: Xcode WILL CRASH YOUR COMPUTER if you try this (infinite recursion!)
#
#
# So: build ONLY the missing platforms/configurations.
if [ "true" == ${ALREADYINVOKED:-false} ]
then
echo "RECURSION: I am NOT the root invocation, so I'm NOT going to recurse"
else
# CRITICAL:
# Prevent infinite recursion (Xcode sucks)
export ALREADYINVOKED="true"
echo "RECURSION: I am the root ... recursing all missing build targets NOW..."
echo "RECURSION: ...about to invoke: xcodebuild -configuration \"${CONFIGURATION}\" -project \"${PROJECT_NAME}.xcodeproj\" -target \"${TARGET_NAME}\" -sdk \"${OTHER_SDK_TO_BUILD}\" ${ACTION} RUN_CLANG_STATIC_ANALYZER=NO" BUILD_DIR=\"${BUILD_DIR}\" BUILD_ROOT=\"${BUILD_ROOT}\" SYMROOT=\"${SYMROOT}\"
xcodebuild -configuration "${CONFIGURATION}" -project "${PROJECT_NAME}.xcodeproj" -target "${TARGET_NAME}" -sdk "${OTHER_SDK_TO_BUILD}" ${ACTION} RUN_CLANG_STATIC_ANALYZER=NO BUILD_DIR="${BUILD_DIR}" BUILD_ROOT="${BUILD_ROOT}" SYMROOT="${SYMROOT}"
ACTION="build"
#Merge all platform binaries as a fat binary for each configurations.
# Calculate where the (multiple) built files are coming from:
CURRENTCONFIG_DEVICE_DIR=${SYMROOT}/${CONFIGURATION}-iphoneos
CURRENTCONFIG_SIMULATOR_DIR=${SYMROOT}/${CONFIGURATION}-iphonesimulator
echo "Taking device build from: ${CURRENTCONFIG_DEVICE_DIR}"
echo "Taking simulator build from: ${CURRENTCONFIG_SIMULATOR_DIR}"
CREATING_UNIVERSAL_DIR=${SYMROOT}/${CONFIGURATION}-universal
echo "...I will output a universal build to: ${CREATING_UNIVERSAL_DIR}"
# ... remove the products of previous runs of this script
# NB: this directory is ONLY created by this script - it should be safe to delete!
rm -rf "${CREATING_UNIVERSAL_DIR}"
mkdir "${CREATING_UNIVERSAL_DIR}"
#
echo "lipo: for current configuration (${CONFIGURATION}) creating output file: ${CREATING_UNIVERSAL_DIR}/${EXECUTABLE_NAME}"
xcrun -sdk iphoneos lipo -create -output "${CREATING_UNIVERSAL_DIR}/${EXECUTABLE_NAME}" "${CURRENTCONFIG_DEVICE_DIR}/${EXECUTABLE_NAME}" "${CURRENTCONFIG_SIMULATOR_DIR}/${EXECUTABLE_NAME}"
#########
#
# Added: StackOverflow suggestion to also copy "include" files
# (untested, but should work OK)
#
echo "Fetching headers from ${PUBLIC_HEADERS_FOLDER_PATH}"
echo " (if you embed your library project in another project, you will need to add"
echo " a "User Search Headers" build setting of: (NB INCLUDE THE DOUBLE QUOTES BELOW!)"
echo ' "$(TARGET_BUILD_DIR)/usr/local/include/"'
if [ -d "${CURRENTCONFIG_DEVICE_DIR}${PUBLIC_HEADERS_FOLDER_PATH}" ]
then
mkdir -p "${CREATING_UNIVERSAL_DIR}${PUBLIC_HEADERS_FOLDER_PATH}"
# * needs to be outside the double quotes?
cp -r "${CURRENTCONFIG_DEVICE_DIR}${PUBLIC_HEADERS_FOLDER_PATH}"* "${CREATING_UNIVERSAL_DIR}${PUBLIC_HEADERS_FOLDER_PATH}"
fi
fi
6) Hit "cmd + B" (Build Project)
7) Open Product in Finder
8) Navigate 1 directory up ("cmd + ↑"), and you will see "Release-universal" directory.
There will be your "fat/universal" library, You are ready to go!
I encountered this with a framework lib I'm using in one of my apps, when I tried to test it in iPhone Retina 64bit simulator.
I simply added x86_64 as an architecture to build for and set it to always build for all architectures. Worked a charm.
The lipo tool can not only create fat mach-o binaries, but it can inspect them:
xcrun lipo -info /path/to/libThing.a
This will output what architectures are in the file. Before you join binaries using lipo, run this to make sure the architectures you expect are present. It's also a good idea to run this on the product of a fat binary join.
In your case you need:
iPhoneSDK Configuration:
armv7, armv7s, arm64
iPhoneSimulator Configuration:
i386, x86_64
It seems that the iPhoneSimulator build product is not producing an x86_64 binary based on your question. Check your build configuration - in particular, "Build Active Architectures Only" (ONLY_ACTIVE_ARCH ) should be set to NO. The default is for this to be NO for Release, but YES for debug. If it is YES, only one architecture will be in the build product.
Go to your application project Target and look in Library Search Path.
Now check that your library file path should be written in double quotes:
"$(SRCROOT)/MyAppTest/TestFlight"
If there is no double quote then just add them and compile the project.
Hope it will work for you.

Resources