How to create FAT / Universal framework with XCode 13? - ios

We were using a script to create a FAT framework before where we followed the below steps.
create a framework for iOS devices
create a framework for simulator devices
merge the above two frameworks & it will be your FAT / Universal framework.
The same script is not working fine after XCODE 12.4 so it seems that there is some change that is specific to XCODE 13+.
Can anyone please guide the steps to create FAT / Universal Framework with XCODE 13?

try this one "Build Phase" -> click "+" icon -> "New Run Script Phase" copy below code there and build with simulator and Any iOS Device.Your fat framework will be in your project folder
#1. After then make a fresh directory directory
UNIVERSAL_OUTPUTFOLDER=${BUILD_DIR}/${CONFIGURATION}-universal
# make sure the output directory exists
mkdir -p "${UNIVERSAL_OUTPUTFOLDER}"
# 2. Copy Device(arm64) Framework at fresh universal folder location
cp -a "${BUILD_DIR}/${CONFIGURATION}-iphoneos/${PROJECT_NAME}.framework" "${UNIVERSAL_OUTPUTFOLDER}/"
#3. Copy Sim(x86_64) Frameworks's "MyFramework.swiftmodule" Folder Content & paste it at Fat(x86_64 + arm64) Frameworks's "MyFramework.swiftmodule" folder.
SIMULATOR_SWIFT_MODULES_DIR="${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/${PROJECT_NAME}.framework/Modules/${PROJECT_NAME}.swiftmodule/."
if [ -d "${SIMULATOR_SWIFT_MODULES_DIR}" ]; then
cp -R "${SIMULATOR_SWIFT_MODULES_DIR}" "${UNIVERSAL_OUTPUTFOLDER}/${PROJECT_NAME}.framework/Modules/${PROJECT_NAME}.swiftmodule"
fi
# Step 4. Create universal binary file using lipo and place the combined executable in the copied framework directory
lipo -create -output "${UNIVERSAL_OUTPUTFOLDER}/${PROJECT_NAME}.framework/${PROJECT_NAME}" "${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/${PROJECT_NAME}.framework/${PROJECT_NAME}" "${BUILD_DIR}/${CONFIGURATION}-iphoneos/${PROJECT_NAME}.framework/${PROJECT_NAME}"
# Step 5. Copy output at Project Directory
cp -R "${UNIVERSAL_OUTPUTFOLDER}/${PROJECT_NAME}.framework" "${PROJECT_DIR}"
# Step 6. Open Project Directory
open "${PROJECT_DIR}"#1. After then make a fresh directory directory
UNIVERSAL_OUTPUTFOLDER=${BUILD_DIR}/${CONFIGURATION}-universal
# make sure the output directory exists
mkdir -p "${UNIVERSAL_OUTPUTFOLDER}"
# 2. Copy Device(arm64) Framework at fresh universal folder location
cp -a "${BUILD_DIR}/${CONFIGURATION}-iphoneos/${PROJECT_NAME}.framework" "${UNIVERSAL_OUTPUTFOLDER}/"
#3. Copy Sim(x86_64) Frameworks's "MyFramework.swiftmodule" Folder Content & paste it at Fat(x86_64 + arm64) Frameworks's "MyFramework.swiftmodule" folder.
SIMULATOR_SWIFT_MODULES_DIR="${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/${PROJECT_NAME}.framework/Modules/${PROJECT_NAME}.swiftmodule/."
if [ -d "${SIMULATOR_SWIFT_MODULES_DIR}" ]; then
cp -R "${SIMULATOR_SWIFT_MODULES_DIR}" "${UNIVERSAL_OUTPUTFOLDER}/${PROJECT_NAME}.framework/Modules/${PROJECT_NAME}.swiftmodule"
fi
# Step 4. Create universal binary file using lipo and place the combined executable in the copied framework directory
lipo -create -output "${UNIVERSAL_OUTPUTFOLDER}/${PROJECT_NAME}.framework/${PROJECT_NAME}" "${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/${PROJECT_NAME}.framework/${PROJECT_NAME}" "${BUILD_DIR}/${CONFIGURATION}-iphoneos/${PROJECT_NAME}.framework/${PROJECT_NAME}"
# Step 5. Copy output at Project Directory
cp -R "${UNIVERSAL_OUTPUTFOLDER}/${PROJECT_NAME}.framework" "${PROJECT_DIR}"
# Step 6. Open Project Directory
open "${PROJECT_DIR}"

Related

Import xcode scheme from command line

Is any way to import an xcode scheme into a xcode project or xcode workspace from command line?
I want to automatize the archive process with a shell script and I want to verify if the scheme exist in the xcode project or xcode workspace, if the scheme doesn't exit import it from a .xcscheme file.
That is actually pretty easy to achieve. As you have figured out already, Xcode schemes are just files that reside in the xcodeproj container "file".
If you want to check if a scheme exists you just need to check if the .xcscheme file is present in either of the following locations: <your_project>.xcodeproj/xcuserdata/<your_user>.xcuserdatad/xcschemes/
<your_project>.xcodeproj/xcshareddata/xcschemes/
If not you just need to copy it there (preferably to the xcshareddata/xcschemes/ folder).
The following code should do the trick:
#!/bin/bash
# Set to your project and scheme
export PROJECT_FILE="MyProject.xcodeproj"
export SCHEME="abc.xcscheme"
# Generate path to shared schemes folder
export SCHEMES=$PROJECT_FILE/xcshareddata/xcschemes
if [ ! -f $SCHEMES/$SCHEME ]; then
# Create folder if necessary
mkdir -p $SCHEMES
# Copy scheme
cp $SCHEME $SCHEMES/$SCHEME
fi

Integrate Linphone in own iOS project

I am creating a voip call based project with Linphone and I have also successfully build and run the Linphone project and successfully run audio and video call. Now I am integrating Linphone in my own project and I am facing many problems and issues with this. I have used some following links for help but nowhere are complete instructions. Can anyone provide me the complete running steps for this-
http://shallwelearn.com/blog/build-linphone-for-iphone-and-ipad/
Integrate Linphone app to my iOS app
How to integrate Linphone into an existing project (SIP in IOS)
http://www.linphone.org/technical-corner/linphone/overview
How to integrate Linphone into an existing project (SIP in IOS)
http://lists.gnu.org/archive/html/linphone-developers/2014-09/msg00109.html
http://www.successmonkey.co.nz/blog/building-linphone-for-ios
Download Liblinphone iPhone SDK from the link: http://www.linphone.org/releases/ios choose latest one.
Move two folders (include and lib) to your project folder
Add paths to these folders in your project Build settings - INCLUDE folder goes to headers and LIB folder goes to libraries.
In General tab in Linked frameworks add all files from LIB folder
Download/clone the repo https://github.com/BelledonneCommunications/linphone-iphone
Find 4 files: LinphoneManager.h/.m and Utils.h/.m , include them in your project folder and add them to the left pane to other class files also
Try to compile your project - xCode will spam you with errors - this is ok.
You need to inspect errors and just delete all file imports causing errors (Some Linphone Address book files/ some config store files and some helpers classes that you do not need for basic use in your project (because most likely you already implemented this features in your existing project))
Then compile again and inspect all errors in methods. Comment delete any problematic chunks of code (there will be about 10-15 of them).
LinphoneManager class already include many useful features - like good watch and use of linphone core with good logging and etc and etc, but not all of them (unfortunately).
With Xcode 11 using macos 10.15.6 Catalina
Linphone SDK 4.4.0 Using Cocoapod
https://github.com/BelledonneCommunications/linphone-sdk/blob/master/README.md
Using a local linphone SDK
Clone the linphone-sdk repository from out gitlab:
$ git clone https://gitlab.linphone.org/BC/public/linphone-sdk.git --recursive
$ git submodule update --init --recursive
Or
$ git clone --recurse-submodules https://gitlab.linphone.org/BC/public/linphone-sdk.git
Rebuild the project:
PODFILE_PATH= pod install
where is your build directory of the linphone-sdk project, containing the linphone-sdk.podspec file and a linphone-sdk ouptut directory comprising built frameworks and resources.
Pod file looks like
source "https://gitlab.linphone.org/BC/public/podspec.git"
source "https://github.com/CocoaPods/Specs.git"
def common_pods
use_frameworks!
pod 'linphone-sdk', '4.4.0'
end
Then open linphone.xcworkspace with Xcode to build and run the app.
Linphone SDK 4.4.0 Using Compile
$ git clone https://gitlab.linphone.org/BC/public/linphone-sdk.git -- recursive
$ git submodule update --init --recursive
Or
$ git clone --recurse-submodules https://gitlab.linphone.org/BC/public/linphone-sdk.git
Goto the build directory
$ mkdir build && cd build
———————————
https://gitlab.linphone.org/BC/public/linphone-cmake-builder/blob/ios-3.13.19/README.python.md
first, install brew
$ brew install cmake
$ brew install yasm
$ brew install pkg-config
Install pip ->
$ curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py
$ python get-pip.py
$ python -m pip install pystache //Check by $ python -m pip list
$ brew install doxygen
———————————
$ cmake .. -G Xcode -DLINPHONESDK_PLATFORM=IOS -DENABLE_G729=YES -DENABLE_G729B_CNG=YES -DENABLE_VCARD=OFF -DENABLE_ILBC=OFF -DENABLE_SILK=OFF -DENABLE_ISAC=OFF -DENABLE_MKV=OFF -DENABLE_GSM=OFF -DENABLE_DOC=OFF -DENABLE_UNIT_TESTS=OFF -DENABLE_LIME=OFF -DENABLE_GPL_THIRD_PARTIES=OFF -DENABLE_NON_FREE_CODECS=OFF
Note - in this step we will also enable G729 dedec support in our linphone sdk.
$ cmake --build . --config RelWithDebInfo
The compilation process is done now need to integrate with Xcode
Compiled Linphone SDK integrates into Xcode.
Find compiled sdk in below directory
linphone-sdk -> build -> linphone-sdk -> apple-darwin
Frameworks and share folder add into xcode project, Frameworks have multiple universal architectures.
Frameworks path add into framework search in build settings
Every framework of Frameworks folder, should be type "embed and sign" (means embed framework.) instead of "do not embed" as default while adding into Xcode Framework setting. it's the most very important part.
apple-darwin -> Tools folder have deply.sh script, copy its contents and create a new run script in "build settings" and paste in it"
the tricky part is where to place the 4th point's script for upload app using archive with strip and slice. Edit Scheme -> Archive -> open dropdown -> post actions -> + to add new script -> copy and paste.
6 (Optional). If experience script causes application crash due to fat library used our project, There is a minor change in the script, I found a solution from this URL - Errors building Xcode Project after adding in Run Script fatal error: lipo: input file
APP_PATH="${TARGET_BUILD_DIR}/${WRAPPER_NAME}"
find "$APP_PATH" -name '*.framework' -type d | while read -r FRAMEWORK
do
FRAMEWORK_EXECUTABLE_NAME=$(defaults read "$FRAMEWORK/Info.plist" CFBundleExecutable)
FRAMEWORK_EXECUTABLE_PATH="$FRAMEWORK/$FRAMEWORK_EXECUTABLE_NAME"
echo "Executable is $FRAMEWORK_EXECUTABLE_PATH"
# Start of Script modify - identify if the framework is FAT. If it is, then it skips it.
if [ ! -f "${FRAMEWORK_EXECUTABLE_PATH}" ]; then
continue
fi
if xcrun lipo -info "${FRAMEWORK_EXECUTABLE_PATH}" | grep --silent "Non-fat"; then
echo "Framework non-fat, skipping: $FRAMEWORK_EXECUTABLE_NAME"
continue
fi
echo "Thinning framework $FRAMEWORK_EXECUTABLE_NAME"
# end of Script modify
EXTRACTED_ARCHS=()
for ARCH in $ARCHS
do
echo "Extracting $ARCH from $FRAMEWORK_EXECUTABLE_NAME"
lipo -extract "$ARCH" "$FRAMEWORK_EXECUTABLE_PATH" -o "$FRAMEWORK_EXECUTABLE_PATH-$ARCH"
EXTRACTED_ARCHS+=("$FRAMEWORK_EXECUTABLE_PATH-$ARCH")
done
echo "Merging extracted architectures: ${ARCHS}"
lipo -o "$FRAMEWORK_EXECUTABLE_PATH-merged" -create "${EXTRACTED_ARCHS[#]}"
rm "${EXTRACTED_ARCHS[#]}"
echo "Replacing original executable with thinned version"
rm "$FRAMEWORK_EXECUTABLE_PATH"
mv "$FRAMEWORK_EXECUTABLE_PATH-merged" "$FRAMEWORK_EXECUTABLE_PATH"
done
If you are using pod then de integrate pod using terminal command "pod deintegrate" on your pod directory. also delete .xcworkspace file from the project.
Now install pod using terminal command "pod install"
Note: If your case was Adding script causes app crash as I mentioned in 6th point but every time adding the script, have to pod de integrate help me avoid it.
:) Now enjoy using linphone sdk in your project.
end of linphone sdk
Linphone SDK Configuration in our projects.
Enable Codec - To enable audio codec first enable defaultValue of g729_preference in the Audio.plist file and last step In Project -> Target -> Build Settings find "Preprocessor macros" and include HAVE_G729, it prints in sip log like Adding G729/8000 for compatibility, just in case.
#Update - add 5th point fo compile for upload the app to the app store and G729 codec configuration.

OSX and iOS shared swift module

I have created swift based Cocoa Touch Framework project named TestLib then I have added new target for Cocoa Framework named TestLibOSX. When I use the framework on iOS app it seems to be working without any issue, but when I create OSX console application it XCode is complaining that it couldn't find TestLibOSX module. Am I missing something ?
P.S This is not the same :)
EDIT: Seems this must be possible since I can see Lister is implemented that way.
If you wish to create a single dynamic framework binary, here are the steps you can follow (as outlined in http://colemancda.github.io/programming/2015/02/11/universal-ios-osx-framework/):
1. Change the project's valid architectures and supported platforms.
This should change your framework's and test unit's valid architectures and supported platforms as well. If not, then manually change them to inherit from the project's build settings.
Base SDK: I recommend OS X, but it will work with iOS too. Note that with with iOS as the base SDK, "My Mac" target is separated into 3 different targets.
Supported Platforms: macosx iphoneos iphonesimulator
Valid Architectures: arm64 armv7 armv7s i386 x86_64
2. Change the search paths for the Unit Test bundle
Runpath Search Paths: $(inherited) #executable_path/Frameworks #loader_path/Frameworks #executable_path/../Frameworks #loader_path/../Frameworks
Framework Search Paths: $(SDKROOT) $(inherited)
This will allow you to import it as import MyFramework instead of
#if os(iOS)
import MyFramework
#else
import MyFrameworkOSX
#endif
Alright, universal frameworks are really a pain. Not only for iOS and OSX but also just within iOS since you need 2 frameworks: one for the simulator and one for the devices. The way you handle iOS is with an "Aggregate" target. I believe the same avenue could be exploited to integrate an OS X target.
When you build a framework, you get a .framework (lego block) folder. In there, there are 2 very important things to be had:
The "Executable" file
The "Modules" folder
In both of these places, you have to have implementation to support all the architectures you desire to support. If you where to build your frameworks separately and wanted to fuse them together, you would have to do the following:
Take both executables and merge them with a "lipo" command.
Make sure that all the files in both "Modules" folder are move
together.
In practical terms, it's a mess so here's what I do!
First I build the frameworks. They can be on different targets in the
same project but usually, the same name helps. For iOS only, theres only one framework so one target suffices.
Then I add an "Aggregate" target, it will help create multiple builds for different architectures.
Clicking on the project name and then the Aggregate target, I go to "Build Phases" and click on the little plus to add a "New Run Script Phase".
There I copy paste the code in this GIST.
Finally, changing your scheme to the Aggregate target and building it will do all the merging you need and you end up with a .framework that is universal.
The script is rather straightforward and with a little dabbling, I'm sure it can be tweaked to add OSX support to it. I hope this points you in the right direction :)
Contents of the script:
#!/bin/sh
UNIVERSAL_OUTPUTFOLDER=${BUILD_DIR}/${CONFIGURATION}-universal
# make sure the output directory exists
mkdir -p "${UNIVERSAL_OUTPUTFOLDER}"
# Step 1. Build Device and Simulator versions
xcodebuild -target "${PROJECT_NAME}" ONLY_ACTIVE_ARCH=NO -configuration ${CONFIGURATION} -sdk iphoneos BUILD_DIR="${BUILD_DIR}" BUILD_ROOT="${BUILD_ROOT}" clean build
xcodebuild -target "${PROJECT_NAME}" -configuration ${CONFIGURATION} -sdk iphonesimulator ONLY_ACTIVE_ARCH=NO BUILD_DIR="${BUILD_DIR}" BUILD_ROOT="${BUILD_ROOT}" clean build
# Step 2. Copy the framework structure (from iphoneos build) to the universal folder
cp -R "${BUILD_DIR}/${CONFIGURATION}-iphoneos/${PROJECT_NAME}.framework" "${UNIVERSAL_OUTPUTFOLDER}/"
# Step 3. Copy Swift modules (from iphonesimulator build) to the copied framework directory
cp -R "${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/${PROJECT_NAME}.framework/Modules/${PROJECT_NAME}.swiftmodule/." "${UNIVERSAL_OUTPUTFOLDER}/${PROJECT_NAME}.framework/Modules/${PROJECT_NAME}.swiftmodule"
# Step 4. Create universal binary file using lipo and place the combined executable in the copied framework directory
lipo -create -output "${UNIVERSAL_OUTPUTFOLDER}/${PROJECT_NAME}.framework/${PROJECT_NAME}" "${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/${PROJECT_NAME}.framework/${PROJECT_NAME}" "${BUILD_DIR}/${CONFIGURATION}-iphoneos/${PROJECT_NAME}.framework/${PROJECT_NAME}"
# Step 5. Convenience step to copy the framework to the project's directory
cp -R "${UNIVERSAL_OUTPUTFOLDER}/${PROJECT_NAME}.framework" "${PROJECT_DIR}"
# Step 6. Convenience step to open the project's directory in Finder
open "${PROJECT_DIR}"

Shell Script Invocation Error in Xcode 6

I used to compile universal static library with iOS-Universal-Framework, and works fine until I upgrade Xcdoe to 6.
I got the following error
** BUILD SUCCEEDED **
Create universal static library
/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/libtool -static /Users/taofang/Library/Developer/Xcode/DerivedData/xxxxx/Build/Products/Debug-iphoneos/xxx.framework/xxx /Users/taofang/Library/Developer/Xcode/DerivedData/xxxxx/Build/Products/Debug-iphonesimulator/xxx.framework/xxx -o /Users/taofang/Library/Developer/Xcode/DerivedData/xxxxx/Build/Products/Debug-iphoneos/xxx.framework/xxx.temp
error: /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/libtool: can't open file: /Users/taofang/Library/Developer/Xcode/DerivedData/xxxxx/Build/Products/Debug-iphonesimulator/xxx.framework/xxx (No such file or directory)
If i use Xcode 5 to do the job, it will be fine.
Beside, I selected Device as my compile target, but why the libtool tries to open a file under iphonesimulator folder?
That means there are no header files in any of your build folders. It may be because you haven't configured your library project to export any header files.
Go to your Project Target >> Build Phases >> + sign >> Add a new build phase
You need to add a Copy files Phase that copies the headers you want to the include folder.
Instead of chmod a+x [PATH], I could resolve it with chmod 777 [PATH].
You can use the following command to recursively own all the files and folders in the path like...
chmod -R 777 ./
For more details:
Chmod 777 to a folder and all contents

Azure Mobile Services iOS Library fails to build with Release configuration

When archiving my iOS app the Windows Azure Mobile Services library fails to build.
The App builds fine when using Debug configuration.
While running this script:
/bin/sh -c \"/Users/user/Library/Developer/Xcode/DerivedData/myapp-bxucrfbhixkrpqfwaaovtqqpsvyd/Build/Intermediates/ArchiveIntermediates/MyApp\ (testing)/IntermediateBuildFilesPath/WindowsAzureMobileServices.build/Release-iphoneos/WindowsAzureMobileServices.build/Script-E8E37A27161FAA9600C13F00.sh\"
This turns out to be, this script form the "Build Phases" tab:
# Exit immediately on any errors
set -e
# Set some variables
OUTPUT=${BUILT_PRODUCTS_DIR}
WAMS="WindowsAzureMobileServices"
WAMS_FRAMEWORK="${WAMS}.framework"
WAMS_LIB="lib${WAMS}.a"
HEADERS="Headers"
# Create the needed directories for the framework
mkdir -p "${OUTPUT}/${WAMS_FRAMEWORK}/Versions/A"
mkdir -p "${OUTPUT}/${WAMS_FRAMEWORK}/Versions/A/Headers"
# Add the headers and lib to the framework
cp -a "${OUTPUT}/${HEADERS}/" "${OUTPUT}/${WAMS_FRAMEWORK}/Versions/A/Headers"
lipo -create "${OUTPUT}/${WAMS_LIB}" -output "${OUTPUT}/${WAMS_FRAMEWORK}/Versions/A/${WAMS}"
# Set up the links to complete the framework
ln -sf Versions/Current/Headers "${OUTPUT}/${WAMS_FRAMEWORK}/Headers"
ln -sf "Versions/Current/${WAMS}" "${OUTPUT}/${WAMS_FRAMEWORK}/${WAMS}"
ln -sf A "${OUTPUT}/${WAMS_FRAMEWORK}/Versions/Current"
It fails with this error:
cp:
/Users/user/Library/Developer/Xcode/DerivedData/MyApp-bxucrfbhixkrpqfwaaovtqqpsvyd/Build/Intermediates/ArchiveIntermediates/MyApp
(testing)/BuildProductsPath/Release-iphoneos/Headers/: No such file or
directory
I'm assuming that the error corresponds to this line:
cp -a "${OUTPUT}/${HEADERS}/" "${OUTPUT}/${WAMS_FRAMEWORK}/Versions/A/Headers"
I cannot see any differences in the build settings between Release and Debug.
Update
After some investigation I have determined that when Xcode archives a product it does not create the "headers" folder in ${BUILT_PRODUCTS_DIR}. It instead puts them in `/Build/Intermediates/ArchiveIntermediates/UninstalledProducts'. So the script fails.
Setting the "Skip Install" to NO for the Release build and then checking for the existence of the ${INSTALL_DIR} in the script will successfully build the library.
if [ -d "${INSTALL_DIR}" ]; then
cp -a "${INSTALL_DIR}/" "${OUTPUT}/${WAMS_FRAMEWORK}/Versions/A/Headers"
else
cp -a "${OUTPUT}/${HEADERS}/" "${OUTPUT}/${WAMS_FRAMEWORK}/Versions/A/Headers"
fi
However, Xcode failed to build because it can't find the headers:
fatal error: 'WindowsAzureMobileServices/WindowsAzureMobileServices.h' file not found
#import <WindowsAzureMobileServices/WindowsAzureMobileServices.h>
Update 2
Setting "Skip install" to no causes archiving issues, see this question: Compile, Build or Archive problems with Xcode 4 (and dependencies)
So I have removed the script that fails in the build phases and added "${PROJECT_DIR}/../azure-mobile-services/sdk/iOS/src" to the "User Header Search Paths" list.
This is messy and not my preferred solution.

Resources