Using xcodebuild to install application on iPhone - ios

I am working on a shell script that builds and install our xcodeproj directly to the first found and connected iDevice. This is the script
#!/bin/bash
cd ../../cordova/platforms/ios
deviceName=$(ideviceinfo | grep -i DeviceName)
deviceName=${deviceName//DeviceName: /} #This is the device name you set in Settings->General->Info->Name on your iDevice
deviceUdid=$(system_profiler SPUSBDataType | sed -n -e '/iPad/,/Serial/p' -e '/iPhone/,/Serial/p' | grep "Serial Number:" | awk -F ": " '{print $2}')
if [ -n "deviceUdid" ]; then
echo 'Found device "'${deviceName}'" with UUID "'${deviceUdid}'", process...'
xcodeProject=$(ls | grep -i *.xcodeproj)
if [ -n "$xcodeProject" ]; then
echo "Is xCode project dir, start building..."
################### Not working command ###################
eval "xcodebuild -scheme AppScheme -destination 'platform=iOS,id=$deviceUdid' install" #This line is not really working
################### Not working command ################
else
echo "Directory is not an xCode project directory!"
fi
else
echo 'It looks like there is no iDevice connected!'
fi
Everything works, except installing it on my iPhone. I get the correct device name, it looks like as if it finds the device, but I don't see the app on my iPhone. The strange thing is, that everything works well if I install it from xCode.
Does anyone know how to fix this issue?

I use this following commands to build and run my Application in Simulator:
xcodebuild -sdk iphonesimulator8.4 -arch i386 -workspace MyApp.xcworkspace -scheme MyApp install DSTROOT=~/MyApp
xcrun instruments -w "iPhone 5s (8.4 Simulator)"
xcrun simctl install booted ~/MyApp/Applications/MyApp.app
if you want to run in another Simulator try see available simulators with:
xcrun instruments -s

Related

iOS : OCLint is not working with xcode 9.2

We have integrated OCLint in one of our project with below script.
source ~/.bash_profile
export PATH=$PATH:/usr/local/bin/
if [ -z "${SCHEME+x}" ]
then
export SCHEME="${PROJECT_NAME}"
fi
if [ -z "${WORKSPACE+x}" ]
then
export WORKSPACE="${PROJECT_NAME}.xcworkspace"
fi
cd "${SOURCE_ROOT}"
# Check if xctool and oclint are installed
if ! which -s xctool
then
echo 'error: xctool not found, install e.g. with homebrew'
exit 1
fi
if ! which -s oclint-json-compilation-database
then
echo 'error: OCLint not installed, install e.g. with homebrew cask'
exit 2
fi
# Cleanup before building
rm -f compile_commands.json
xctool -workspace "${WORKSPACE}" -scheme "${SCHEME}" clean > /dev/null
# Build and analyze
# OCLint Rule Index: http://docs.oclint.org/en/dev/rules/index.html
xctool -workspace "${WORKSPACE}" -scheme "${SCHEME}" -reporter json-compilation-database:compile_commands.json build
oclint-json-compilation-database -e Pods -- -max-priority-1=100000 -max-priority-2=100000 -max-priority-3=100000 \
# Final cleanup
rm -f compile_commands.json
It gives 'zero' warnings and 'zero' error though code contains the lots of warnings and errors.
It seems that it was working fine with old XCodes but not working with XCode 9.2.
Can anyone tell us what kind of changes required to run the OCLint in xcode 9.2 perfectly ?
We are expecting that xcode will show the warnings when we build the OCLint schema. But we are not getting any result now.
Please guide us if we are doing something wrong.
We faced a similar challenge few days back when we upgraded from xcode 8.2.1 to xcode 9.2 with oclint 0.11
Can you try upgrading to oclint-0.13.1 and do a retry and see if it helps.
There are some other tweaks also present but not sure that will fit or not ?
https://github.com/oclint/oclint/issues/245
(search texts for -fmodules and -gmodules, and delete all matches.)
https://github.com/oclint/oclint/issues/302
(set CLANG_ENABLE_MODULE_DEBUGGING=NO)

xcodebuild command in shell script iOS

I have a complete command to deploy the xCode project on real device.
i.e
xcodebuild -workspace jamesAppV2.xcworkspace -scheme jamesAppV2 -configuration Debug -destination 'platform=iOS,name=Shujaat’s iPad' clean test
its working fine using the command line.
Todo: I wanted to execute this command via a shell script.
here is my complete shell script deploy.sh so for.
#!/bin/bash
#My First Script
#Info to be configured
current_path=$(pwd)
appName="jamesApp"
jamesApp_workspace="jamesAppV2.xcworkspace"
echo "Searching for $jamesApp_workspace workspace..."
if [[ $(ls $jamesApp_workspace) ]]; then
echo "$jamesApp_workspace found in current directory."
echo "Listing all installed and connected devices..."
instruments -s devices
echo "Copy + Paste from above devices"
echo "specify name of your decice to launch $appName"
read d_device_name
echo "building workspace for $d_device_name..."
build_cmd=(xcodebuild -workspace jamesAppV2.xcworkspace -scheme jamesAppV2 -configuration Debug)
destination="'platform=iOS,name=$d_device_name'"
build_cmd+=(-destination "$destination" clean test)
echo "${build_cmd[#]}"
# Here it prints the valid command given above
"${build_cmd[#]}"
else
echo "$jamesApp_workspace workspace not found"
echo "Make sure your current path contains the $jamesApp_workspace workspace"
echo "Place this file i.e deploy.sh within the directory containing $jamesApp_workspace workspace"
fi;
Problem:
I have done like
build_cmd=(xcodebuild -workspace jamesAppV2.xcworkspace -scheme jamesAppV2 -configuration Debug)
destination="'platform=iOS,name=$d_device_name'"
build_cmd+=(-destination "$destination" clean test)
echo "${build_cmd[#]}" #Prints valid command
"${build_cmd[#]}"
but gives error on execution
xcodebuild: error: option 'Destination' requires at least one parameter of the form 'key=value'
if I run the above command via command line its working perfectly but If I run this via shell script its not working.
I have referred I want to concatenate arguments of xcodebuild as string, which have space in it ,then run this command to concatenate the xcodebuild command
The shell removes the single quotes in the original command, therefore you should not have any when creating the array either.
I am also trying to execute the command in a similar way by passing it via a string. The command works without the double quotes anywhere on the command for me.
example:
$ xcodebuild -project ~/ios_projects/example.xcodeproj -scheme Xcode9-XCtest destination id=EBCDFH7S-DCJD-EE8D-DSKDKD78

How to use cocoapods integrated project with OCLint?

I can build the project and generate OCLint report on a project without cocoapods but when integrated with cocoapods the build for project is successful but the build for OCLint results into errors for the file which are present into cocoapods and build fails.
So how to make build successful for cocoapods with OCLint?
Any help would be appreciated.
Below is the script I am using to generate html file for cocoapods integrated project with OCLint.
OCLINT_HOME is the path for oclint downloaded folder. I have renamed the folder to oclintrelease.
OCLINT_HOME=/Users/Dheeraj/Downloads/oclintrelease
export PATH=$OCLINT_HOME/bin:$PATH
hash oclint &> /dev/null
if [ $? -eq 1 ]; then
echo >&2 "oclint not found, analyzing stopped"
exit 1
fi
cd ${TARGET_TEMP_DIR}
if [ ! -f compile_commands.json ]; then
echo "[*] compile_commands.json not found, possibly clean was performed"
echo "Workspace Path : ${MY_WORKSPACE}"
echo "[*] starting xcodebuild to rebuild the project.."
# clean previous output
if [ -f xcodebuild.log ]; then
rm xcodebuild.log
echo "Oclint Clean performed"
fi
cd ${SRCROOT}
xcodebuild clean
#build xcodebuild.log
xcodebuild ONLY_ACTIVE_ARCH=NO -workspace ${PROJECT_NAME}.xcworkspace -scheme ${PROJECT_NAME} -configuration Debug clean build| tee ${TARGET_TEMP_DIR}/xcodebuild.log
#xcodebuild <options>| tee ${TARGET_TEMP_DIR}/xcodebuild.log
echo "[*] transforming xcodebuild.log into compile_commands.json..."
cd ${TARGET_TEMP_DIR}
#transform it into compile_commands.json
oclint-xcodebuild
fi
echo "[*] starting analyzing"
cd ${TARGET_TEMP_DIR}
oclint-json-compilation-database -e /Users/Dheeraj/Desktop/sampleCocoaPods/Pods/ -v oclint_args "-report-type html -o /Users/Dheeraj/NewHTMLREPORT.html" | sed 's/\(.*\.\m\{1,2\}:[0-9]*:[0-9]*:\)/\1 warning:/'
It will exclude all the Pods related files.
If you want to include Pods file as well then replace last line in script by :
oclint-json-compilation-database -v oclint_args "-report-type html -o /Users/Dheeraj/NewHTMLREPORT.html" | sed 's/\(.*\.\m\{1,2\}:[0-9]*:[0-9]*:\)/\1 warning:/'
Notes :
Please try first with a short sample Application including cocoapods and once you have generated report for sample application then integrate script into your real application as building with OCLint takes a lot of time to generate the report.
Always clean application and then build with OCLint.
Link for reference

simctl + xcodebuild changing simulator state

I'm trying to automate the functional testing I have in my project. For this, I use Jenkins and run the test tasks using the post-receive git hook. The job is properly invoked, but before the tests are run, I need to erase the simulators in order to tests first time startup of the app. I do the following:
#!/bin/bash --login
# simulator we want
sim="iPhone 6"
# close the iOS simulator if open
echo "Trying to close iOS Simulator"
osascript -e 'tell app "iOS Simulator" to quit'
# find all booted devices
booted=( $(xcrun simctl list | sed -n 's/.*(\(.*\)) (Booted)/\1/p') )
if [ ${#booted[#]} != 0 ]; then
echo 'Found the following booted devices:'
for device in ${booted[#]}
do
echo $device
done
else
echo 'There are no booted devices, skipping'
fi
# shutdown all of them to be able to erase them
for device in ${booted[#]}
do
echo "Trying to shutdown $device"
xcrun simctl shutdown $device
echo "Done"
done
# sanity check, all devices should be shutdown
booted=( $(xcrun simctl list | sed -n 's/.*(\(.*\)) (Booted)/\1/p') )
if [ ${#booted[#]} != 0 ]; then
echo 'Even though we shut down all the devices, some devices are still booted:'
for device in ${booted[#]}
do
echo $device
done
exit 1
fi
# erase the device so we can test index page and tutorial
allDevices=( $(xcrun simctl list | sed -En 's/.* \((.*)\) \((Shutdown)\)/\1/p') )
for device in ${allDevices[#]}
do
echo "Erasing device $device"
xcrun simctl erase $device
echo
done
# sanity check, all devices should be shutdown
booted=( $(xcrun simctl list | sed -n 's/.*(\(.*\)) (Booted)/\1/p') )
if [ ${#booted[#]} != 0 ]; then
echo 'Even though we shut down all the devices, some devices are still booted:'
for device in ${booted[#]}
do
echo $device
done
exit 1
fi
echo device list:
echo $(xcrun simctl list)
dev=( $(xcrun simctl list | sed -En 's/'"$sim"' \((.*)\) \((Shutdown)\)/\1/p') )
echo Booting the device $dev
xcrun simctl boot $dev
# clean is not good enough, need to remove DerivedData contents manually
rm -rf ~/Library/Developer/Xcode/DerivedData
/usr/local/bin/xctool -workspace MyApp.xcworkspace -scheme MyApp_QA2 clean
xcodebuild -workspace MyApp.xcworkspace -scheme MyApp_QA2 -destination 'platform=iOS Simulator,name=iPhone 6,OS=8.1' test | xcpretty -c -r html
When I run this, I get:
These lines are responsible for booting:
dev=( $(xcrun simctl list | sed -En 's/'"$sim"' \((.*)\) \((Shutdown)\)/\1/p') )
echo Booting the device $dev
xcrun simctl boot $dev
So, I comment them, but then the build fails with:
2015-03-10 09:56:13.036 xcodebuild[84840:4008451] [MT]
iPhoneSimulator: Unable to connect to
"com.apple.instruments.deviceservice.lockdown" (Error
Domain=com.apple.CoreSimulator.SimError Code=146 "Unable to lookup in
current state: Shutdown" UserInfo=0x7fbcb2f00af0
{NSLocalizedDescription=Unable to lookup in current state: Shutdown})
Looks to me like Xcode and simctl can't agree which one should be responsible for booting the correct sim. Any ideas?
You can launch the simulator with xcrun instruments -w "iPhone 5 (8.4 Simulator)"
and to shut down the simulator with killall "iOS Simulator"
In Xcode 6 and Xcode 7, Simulator.app is responsible for booting the device it uses. If you use simctl to boot the device, it will not be usable by Simulator.app in that state because it will be booted to a headless state.

Running iOS UIAutomation as a post-action build script is return as a posix spawn error

I'm entirely new to using bash and Xcode build scripts and so my code is probably a jungle full of errors.
The idea here is to trigger the script below which will scrape the directory that it is saved in for any .js automation scripts. It will then send these scripts to instruments to be run one at a time. I found some nifty code that created time stamped files and so I used that to create a more meaningful storage system.
#!/bin/bash
# This script should run all (currently only one) tests, independently from
# where it is called from (terminal, or Xcode Run Script).
# REQUIREMENTS: This script has to be located in the same folder as all the
# UIAutomation tests. Additionally, a *.tracetemplate file has to be present
# in the same folder. This can be created with Instruments (Save as template...)
# The following variables have to be configured:
#EXECUTABLE="Plans.app"
# Find the test folder (this script has to be located in the same folder).
ROOT="$( cd -P "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
# Prepare all the required args for instruments.
TEMPLATE=`find $ROOT -name '*.tracetemplate'`
#EXECUTABLE=`find ~/Library/Application\ Support/iPhone\ Simulator | grep "${EXECUTABLE}$"`
echo "$BUILT_PRODUCTS_DIR"
echo "$PRODUCT_NAME"
EXECUTABLE="${BUILT_PRODUCTS_DIR}/${PRODUCT_NAME}.app/"
SCRIPTS=`find $ROOT -name '*.js'`
# Prepare traces folder
TRACES="${ROOT}/Traces/`date +%Y-%m-%d_%H-%M-%S`"
mkdir -p "$TRACES"
printf "\n" >> "$ROOT/results.log"
echo `date +%Y-%m-%d_%H-%M-%S` >> "$ROOT/results.log"
# Get the name of the user we should use to run Instruments.
# Currently this is done, by getting the owner of the folder containing this script.
USERNAME=`ls -l "${ROOT}/.." | grep \`basename "$ROOT"\` | awk '{print $3}'`
# Bring simulator window to front. Depending on the localization, the name is different.
osascript -e 'try
tell application "iPhone Simulator" to activate
on error
tell application "iOS Simulator" to activate
end try'
# Prepare an Apple Script that promts for the password.
PASS_SCRIPT="tell application \"System Events\"
activate
display dialog \"Password for user $USER:\" default answer \"\" with hidden answer
text returned of the result
end tell"
# Run all the tests.
for SCRIPT in $SCRIPTS; do
echo -e "\nRunning test script $SCRIPT"
TESTC="sudo -u ${USER} xcrun instruments -l -c -t ${TEMPLATE} ${EXECUTABLE} -e UIARESULTSPATH ${TRACES}/${TRACENAME} -e UIASCRIPT ${SCRIPT} >> ${ROOT}/results.log"
#echo "$COMMAND"
echo "Executing command $TESTC" >> "$ROOT/results.log"
echo "here $TESTC" >> "$ROOT/results.log"
OUTPUT=$(TESTC)
echo $OUTPUT >> "$ROOT/results.log"
echo "Finished logging" >> "$ROOT/results.log"
SCRIPTNAME=`basename "$SCRIPT"`
TRACENAME=`echo "$SCRIPTNAME" | sed 's_\.js$_.trace_g'`
for i in $(ls -A1t $PWD | grep -m 1 '.trace')
do
TRACEFILE="$PWD/$i"
done
if [ -e $TRACEFILE ]; then
mv "$TRACEFILE" "${TRACES}/${TRACENAME}"
fi
if [ `grep " Fail: " results.log | wc -l` -gt 0 ]; then
echo "Test ${SCRIPTNAME} failed. See trace for details."
open "${TRACES}/${TRACENAME}"
exit 1
break
fi
done
rm results.log
A good portion of this was taken from another Stack Overflow answer but because of the repository setup that I'm working with I needed to keep the paths abstract and separate from the root folder of the script. Everything seems to work (although probably not incredibly efficiently) except for the actual xcrun command to launch instruments.
TESTC="sudo -u ${USER} xcrun instruments -l -c -t ${TEMPLATE} ${EXECUTABLE} -e UIARESULTSPATH ${TRACES}/${TRACENAME} -e UIASCRIPT ${SCRIPT} >> ${ROOT}/results.log"
echo "Executing command $TESTC" >> "$ROOT/results.log"
OUTPUT=$(TESTC)
This is turned into the following by whatever black magic Bash runs on:
sudo -u Braains xcrun instruments -l -c -t
/Users/Braains/Documents/Automation/AppName/TestCases/UIAutomationTemplate.tracetemplate
/Users/Braains/Library/Developer/Xcode/DerivedData/AppName-
ekqevowxyipndychtscxwgqkaxdk/Build/Products/Debug-iphoneos/AppName.app/ -e UIARESULTSPATH
/Users/Braains/Documents/Automation/AppName/TestCases/Traces/2014-07-17_16-31-49/ -e
UIASCRIPT /Users/Braains/Documents/Automation/AppName/TestCases/Test-Case_1js
(^ Has inserted line breaks for clarity of the question ^)
The resulting error that I am seeing is:
posix spawn failure; aborting launch (binary ==
/Users/Braains/Library/Developer/Xcode/DerivedData/AppName-
ekqevowxyipndychtscxwgqkaxdk/Build/Products/Debug-iphoneos/AppName.app/AppName).
I have looked all over for a solution to this but I can't find anything because Appium has a similar issue. Unfortunately I don't understand the systems well enough to know how to translate the fixes to Appium to my own code but I imagine it's a similar issue.
I do know that the posix spawn failure is related to threading, but I don't know enough about xcrun to say what's causing the threading issue.
Related info:
- I'm building for the simulator but it'd be great to work on real devices too
- I'm using xCode 5.1.1 and iOS Simulator 7.1
- This script is meant to be run as a build post action script in xCode
- I did get it briefly working once before I broke it and couldn't get it back to the working state. So I think that means all of my permissions are set correctly.
UPDATE: So I've gotten to the root of this problem although I have not found a fix yet. First of all I have no idea what xcrun is for and so I dropped it. Then after playing around I found that my Xcode environment variables are returning the wrong path, probably because of some project setting somewhere. If you copy the Bash command from above but replace Debug-iphoneos with Debug-iphonesimulator the script can be run from the command line and will work as expected.
So for anyone who happens across this the only solution I could find was to hardcode the script for the simulator.
I changed EXECUTABLE="${BUILT_PRODUCTS_DIR}/${PRODUCT_NAME}.app/" to be EXECUTABLE="${SYMROOT}/Debug-iphonesimulator/${EXECUTABLE_PATH}". This is obviously not a great solution but it works for now.

Resources