What's the replacement for Xcode's PackageApplication? - xcode

With Xcode 8.3 PackageApplication is gone. I did use it to convert an *.app package/directory to a *.ipa file (after re-signing):
xcrun -sdk iphoneos PackageApplication -v "MyApp.app" -o "MyApp.ipa"
Is there any replacement for this, so I can continue to convert .app to .ipa?

Apparently there is no need to use any other tool, and it's also not necessary to change the process that leads to the *.app package (in other words: no need to use xcodebuild -exportArchive).
All we have to do, is to zip that *.app package:
pushd "/build"
mkdir ./Payload
cp -R "$PATH_TO_SIGNED_APP_PACKAGE.app" ./Payload
zip -qyr MyApp.ipa ./Payload
rm -r ./Payload
popd
Note:
Jump into the target directory, here /build. This ensures we don't have the full path in the zip archive later.
Create a folder named Payload (important, this cannot vary)
Copy the *.app bundle to the Payload folder
Zip the folder and instead of *.zip use *.ipa as extension
Jump back to where you came from

Another workaround would be to put a copy of the PackageApplication tool from a previous Xcode into the Xcode 8.3 directory
Get the PackageApplication script from Xcode 8.2.1 here: https://gist.github.com/anonymous/48f3e4c5ae25313dc0fe10d9ec50c3fc
Remember to make it executable
chmod +x PackageApplication
Then drop it into your 8.3 Xcode.app as
/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/PackageApplication

This is the error:
xcrun: error: unable to find utility "PackageApplication", not a developer tool or in PATH
It looks like PackageApplication is removed from Xcode 8.3.
In Xcode 8.2 there was a warning: PackageApplication is deprecated, use xcodebuild -exportArchive instead.

Related

Cant get gtest working with Xcode 6.2

I'm trying to follow the instructions from Here.
The instructions seem very straight forward, but I can't get it to compile. If I download the gtest file from the website, it appears there are header files missing from the include directory which means they don't get into the gtest-framework.
the files are the gtest-port-arch.h and everything in the internal/custom folder. I get complier errors that these files are not found.
If I get the source from the svn, all of the files are present in the include dir of the sdk, however, the source folder in the xcode project omits the same files from being added to the project. I have to add them myself then build the frame work. The missing files are then present, but when I build the gtest-framework and add it to the test project, then the Test target's main class does not recognize the TEST calls and I get errors like C++ requires all types to be defined. I am following the steps. I really need to get this framework functioning.
Any help appreciated.
I had the same issue and couldn't find out the problem.
Ended up installing the libraries and simply linking them to Xcode, as described in the answer here
I copy the instructions here too. The only difference is that I used /usr/local/include and /usr/local/lib
Moreover, do not forget to set these for your "Tests" target:
Library search paths: /usr/local/lib
User header search paths: /usr/local/include
other linker flags: -lgtest
Copied:
1. Get the googletest framework
$ wget http://googletest.googlecode.com/files/gtest-1.7.0.zip
2. Unzip and build google test
$ unzip gtest-1.7.0.zip
$ cd gtest-1.7.0
$ ./configure
$ make
3. "Install" the headers and libs on your system.
$ sudo cp -a include/gtest /usr/include
$ sudo cp -a lib/.libs/* /usr/lib/

Downloading the Android support library from command line

How do you download the Android support library via the command line?
For example:
echo y | android update sdk --no-ui --filter "android-19"
echo y | android update sdk --no-ui --all --filter "extra-android-m2repository"
android command is deprecated now
You can use sdkmanager instead like so:
sdkmanager --install "extras;android;m2repository"
sdkmanager "extras;android;m2repository"
worked for me.
I ran in to the error: Warning: File /var/root/.android/repositories.cfg could not be loaded.
so I had to create that file before running the above command.
touch ~/.android/repositories.cfg
The sdkmanager should be your go to. Otherwise, there is another way which is what sdkmanager will do automatically. So, there are dangers to this, one typo and the whole thing will not work. Go to Google Sources repository and choose either support or m2repository and download by clicking the tgz/archive link under the breadcrumbs.
Or use;
wget https://chromium.googlesource.com/android_tools/+archive/master/sdk/extras/android.tar.gz
The second option downloads a bigger file size (and two versions of the support library but neither is the newer androidX referenced on the official Android development page). But, both will give you a zipped archive with the Android support library. Go to your directory and create the extras directory. Use "extras/android" as a file path and unzip (use tar xvfj) your archive into it;
unzip <archive file>
mv -R <unzipped directory> <Android SDK home>/extras/android/
mv -R <unzipped and moved directory> <support>
Or
tar xvjf <archive file>
mv -R <unzipped directory> <Android SDK home>/extras/android/
mv -R <unzipped and moved directory> <support>
You should now have the Android support library installed in your SDK package.
Further support in use.

Xcode5 post-archive script for Sparkle package no longer works

Xcode 5 seems to have changed the way it stores the build application package (xxx.app) such that ditto no longer works. In the ../BuildProductsPath/Release/ directory, the app is actually a symlink to .../InstallationBuildProductsLocation/Applications/...
MyApp.app -> ~/Library/Developer/Xcode/DerivedData/MyApp-emwilkqhlayanxahjpexlpbbkato/Build/Intermediates/ArchiveIntermediates/MyApp/InstallationBuildProductsLocation/Applications/MyApp
This breaks the ditto command I was using to create a zip file of the application to put on my Sparkle update server.
Anyone have an updated script for building the Sparkle XML and ZIP files? Or know what environment variable I need to use to locate my actual binary after the Archive phase?
Here's the relevant lines from the post-archive script:
ARCHIVE_FILENAME="$HOME/Desktop/$PROJECT_NAME-$VERSION_STRING.zip"
cd "$BUILT_PRODUCTS_DIR"
ditto -ck --keepParent "$PROJECT_NAME.app" "$ARCHIVE_FILENAME"
That's from the sample script on the Sparkle website.
Turns out that in Xcode5 you need to pull the app package from the archive directory, not the Built Products directory. This works:
ARCHIVE_FILENAME="$HOME/Desktop/$PROJECT_NAME-$VERSION_STRING.zip"
ditto -ck --keepParent "${ARCHIVE_PRODUCTS_PATH}/Applications/${PROJECT_NAME}.app" "$ARCHIVE_FILENAME"

how to make Xcode project with homebrew libraries portable?

I have installed FreeType on my mac using Brew. The code on my mac works fine, but when I try to run the project on other mac I get the below mentioned linking error.
dyld: Library not loaded: /usr/local/opt/freetype/lib/libfreetype.6.dylib
Referenced from: /Users/ashutosh/Library/Developer/Xcode/DerivedData/InstrumentChamp-
etytleaabhxmokadgrjzbgtmwxfl/Build/Products/Debug/instrumentchamp.app/Contents/MacOS/instrumentchamp
Reason: image not found (lldb)
All the library directories and include directories of Freetype are included in project's '$SRCROOT/' directory when I try to run the code on other mac.
The path you see in the linking error for library is where brew had installed freetype in the mac where I created this project.
/usr/local/opt/freetype/lib/libfreetype.6.dylib
I have copied all the lib/ include/ directories that were needed to my project's home folder.
And I have set the library and include paths in Xcode.
What is it that I am missing here? What else do I have to do to make my code portable on any other Mac.
I got the project to run on other mac by installing Brew, but I want to do it without the need to install brew.
PS: I had to install freetype using brew, as I couldn't compile the .dylib for freetype for 32bit processor, a 64bit copy of .dylib was giving me error such as 'wrong architecture!'
The basic idea I was getting at in my comments is that OS X is pretty stupid about where it searches for libraries, it will use the same absolute path used during compilation to resolve them at run-time.
Usually when you want to deploy/distribute your application to a different machine from the one that built it, you will include your libraries with the install package/bundle. But you probably want them to use a path relative to your application at run-time, thus install_name_tool -change allows you to replace the nasty absolute path with something relative.
Hope this makes sense, Apple makes it really easy to use system-wide frameworks on OS X, custom libraries not so much. If you compile using a system-wide framework, /System/Library/Frameworks/... is universally available on all OS X installs (given the same target release version).
To solve your problem, I would do the following:
install_name_tool -change /usr/local/opt/freetype/lib/libfreetype.6.dylib #executable_path/lib/libfreetype.6.dylib <executable_name_here>
Then it will stop looking for libfreetype.6.dylib in the location it was when you compiled the software, and instead search for it relative to your executable's location at run-time (in this case, in the sub-directory lib/).
In the end, this did not end up as easy as I originally thought. It works but there are caveats.
Building on the answers from Andon M. Coleman & Alexander Klimetschek, here is a script function which takes dylib names from Homebrew, copies them into the app bundle's Contents/Frameworks directory, and sets the executable's corresponding search path using install_name_tool. I noticed that sometimes the actual .dylib location is different from what the Xcode linker finds when putting together the executable and this handles that as well by querying the exe with otool -L.
The script below copies the .dylib for the liblo library into the app bundle. Adding new libs should be as simple as adding a new copy lib ###.dlyib line to the bottom of the script.
# exit on error
set -e
# paths
LOCALLIBS_PATH="$SRCROOT/libs"
HOMEBREW_PATH="/usr/local"
FRAMEWORKS_PATH="$BUILT_PRODUCTS_DIR/$FRAMEWORKS_FOLDER_PATH"
EXE_PATH="$BUILT_PRODUCTS_DIR/$EXECUTABLE_FOLDER_PATH/$EXECUTABLE_NAME"
# code signing identity
IDENTITY="$EXPANDED_CODE_SIGN_IDENTITY_NAME"
if [ "$IDENTITY" == "" ] ; then
IDENTITY="$CODE_SIGN_IDENTITY"
fi
# copy lib into Contents/Frameworks and set lib search path
# $1: library .dylib
# $2: optional path to libs folder, otherwise use Homebrew
copylib() {
LIB=$1
if [ "$2" == "" ] ; then
# use homebrew
LIB_PATH=$(find "$HOMEBREW_PATH" -type f -name $LIB)
else
# use given path
LIB_PATH="$2/$LIB"
fi
echo "$LIB:"
echo " $LIB_PATH -> $FRAMEWORKS_FOLDER_PATH/$LIB"
# copy lib, set permissions, and sign
mkdir -p "$FRAMEWORKS_PATH"
cp "$LIB_PATH" "$FRAMEWORKS_PATH/"
chmod 755 "$FRAMEWORKS_PATH/$LIB"
codesign --verify --force --sign "$IDENTITY" "$FRAMEWORKS_PATH/$LIB"
# set new path within executable
# note: grep --max 1 as multi-arch builds will print path once *per arch*
OLD=$(otool -L "$EXE_PATH" | grep --max 1 $LIB | awk '{print $1}')
NEW="#executable_path/../Frameworks/$LIB"
install_name_tool -change "$OLD" "$NEW" "$EXE_PATH"
# print to confirm new path
otool -L "$EXE_PATH" | grep $LIB
}
##### GO
# use lib from homebrew
copy lib liblo.7.dylib
# or use local lib
#copylib liblo.7.dylib "$LOCALLIBS_PATH/liblo/lib"
Add this as a Run Script build phase in the Xcode project. You can also save it as an external file and call it using sh within the Run Script phase with:
sh $PROJECT_DIR/path-to/copy-libs.sh
Example build report output:
liblo.7.dylib:
/usr/local/Cellar/liblo/0.29/lib/liblo.7.dylib ->> YOURAPP.app/Contents/Frameworks/liblo.7.dylib
#executable_path/../Frameworks/liblo.7.dylib (compatibility version 11.0.0, current version 11.0.0)
The $(find $HOMEBREW_PATH -type f -name $LIB) could probably be improved by following the .dylib symlink in /usr/local/lib instead.
UPDATE: You will probably also need to make sure the new dylibs are signed otherwise the code signing step will fail when building, at least it eventually did for me. Following this SO post, adding --deep to the Other Code Signing Flags option in the project Build Settings works.
There might be a better way to sign only the files that the script adds, but I didn't feel like digging into running codesign manually. From what I've read, however, --deep is not suggested by Apple for anything but temporary fixes, so it's probably not a best practice.
UPDATE 2: Running --deep didn't actually solve the problem and the app still would not run on other machines. In the end, I needed to code sign the copied .dylib manually which turned out to be relatively easy.
One note: I ran into an ambiguous "Mac Developer" identities error when running codesign which seemed to be confused by two certificates with the same name in the Keychain: ie. the current developer certificate and the previous expired developer certificate. Opening Keychain Access and deleting the expired certificate solved the problem.
UPDATE 3: Quoted path variable usage to fix paths with spaces.
UPDATE 4: This solution works fine for building apps for recent systems, but I ran into a code signing problem when running the app on macOS 10.10. Judging from this SO post, older macOS versions use a different codesign hash algorithm and the app would run fine on a 10.12 system but fail with a code signing error on 10.10. On both systems, codesign verified that everything was signed correctly.
You basically need to build the libraries with the -mmacosx-version-min set so codesign will be able to tell which algorithms to use to support the min and the recent macOS versions. I tried to pass custom CFLAGS/LDFLAGS to Homebrew while building liblo from source, but it's not possible without editing the brew formula. In the end, I decided to write a build script to build liblo from source myself and I modified the copy script so it can also take a local location. Now everything is finally working.
TLDR: Homebrew libs work great for initial development & testing, but building the libs manually works better for deployment.
Here is an automated script based on Andon's answer that will replace all #executable_path/../Frameworks/ with #executable_path/, so that all frameworks can be in the same folder as the executable. This also adapts the frameworks themselves, if they have dependencies on each other.
Beware, this only makes sense for command-line applications. If it's a regular OSX bundles app, one probably shouldn't change the "../Frameworks" convention.
Instructions
Add this as "Run Script" using Shell = /bin/sh at the end of your Xcode project Build Phases.
Also make sure to have the "Copy Files" step with a "Destination = Products Directory" for all the frameworks.
Script
# change the hardcoded ../Frameworks relative path that Xcode does by rewriting the binaries after the build
# check with:
# otool -L <binary>
# this is the new location
# make sure this is the same Destination the Frameworks are copied to in the "Copy Files" step
# the default "#executable_path/" would be Destination = Products Directory
NEW_FRAMEWORKS_PATH="#executable_path/"
# the one we want to replace
DEFAULT_FRAMEWORKS_PATH="#executable_path/../Frameworks/"
function change_binary {
local libpaths=`otool -L "$1" | grep "$DEFAULT_FRAMEWORKS_PATH" | tr '\t' ' ' | cut -d " " -f2`
local lib
for lib in $libpaths; do
if [ "$2" == "recursive" ]; then
local libbinary=`echo $lib | sed "s,$DEFAULT_FRAMEWORKS_PATH,,"`
change_binary "$libbinary"
fi
local newlib=`echo $lib | sed "s,$DEFAULT_FRAMEWORKS_PATH,$NEW_FRAMEWORKS_PATH,"`;
echo "changing library path in '$1': '$lib' => '$newlib'"
install_name_tool -change "$lib" "$newlib" "$1"
done
}
cd $BUILT_PRODUCTS_DIR
change_binary "$EXECUTABLE_NAME" recursive
Note that changing NEW_FRAMEWORKS_PATH to e.g. a relative subpath does not work, the script would need to become a bit more complex to handle this.
Result Structure
$BUILT_PRODUCTS_DIR/
executable
Some.framework/
Another.framework/
...
And otool -L executable would look like this:
executable:
#executable_path/Some.framework/Versions/A/Some (...)
#executable_path/Another.framework/Versions/A/Another (...)
...

xcodebuild - how to specify the directory where the project is, without doing a cd in it

I am using xcodebuild from command line in a script, but I realized that I cannot specify the path of the project that i wanna build;I am forced to cd in the folder where the project is.
Is there a way to accomplish the build process without having to cd in the directory, or this is how it must be?
Is not a big deal to cd into the directory and execute xcodebuild, but I wonder what if someday you need to build a project and you cannot cd into the directory....It doesn't really make sense to me to not being able to specify the path.
You can use xcodebuild -project pathtoprojectfile
eg
xcodebuild -project /IOSprojects/YourProject/YourProject.xcodeproj
You must be in the directory containing the project(s) when you run xcodebuild. If you don’t want to mess with your current directory, there a couple of options:
/bin/sh -c "cd $PRJDIR; xcodebuild"
or
(cd $PRJDIR; xcodebuild)

Resources