I have question about framework.
When I import my customized swift framework in Objc project, I cant init class object and find customized delegate.
And I also have script to combined different framework like this:
Is my script problem?
Or project setting problem?
Xcode 11.3.1
swift 5
#!/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 "XXXSDK" ONLY_ACTIVE_ARCH=NO -configuration ${CONFIGURATION} -sdk iphoneos BUILD_DIR="${BUILD_DIR}" BUILD_ROOT="${BUILD_ROOT}" clean build
xcodebuild -target "XXXSDK" -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/XXXSDK.framework" "${UNIVERSAL_OUTPUTFOLDER}/"
# Step 3. Copy Swift modules from iphonesimulator build (if it exists) to the copied framework directory
SIMULATOR_SWIFT_MODULES_DIR="${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/XXXSDK.framework/Modules/XXXSDK.swiftmodule/."
if [ -d "${SIMULATOR_SWIFT_MODULES_DIR}" ]; then
cp -R "${SIMULATOR_SWIFT_MODULES_DIR}" "${UNIVERSAL_OUTPUTFOLDER}/XXXSDK.framework/Modules/XXXSDK.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}/XXXSDK.framework/XXXSDK" "${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/XXXSDK.framework/XXXSDK" "${BUILD_DIR}/${CONFIGURATION}-iphoneos/XXXSDK.framework/XXXSDK"
# Step 5. Convenience step to copy the framework to the project's directory
cp -R "${UNIVERSAL_OUTPUTFOLDER}/XXXSDK.framework" "${PROJECT_DIR}"
cp -R "${UNIVERSAL_OUTPUTFOLDER}/XXXSDK.framework" "${PROJECT_DIR}/../../XXXSDKDemo"
cp -R "${UNIVERSAL_OUTPUTFOLDER}/XXXSDK.framework" "${PROJECT_DIR}/../../XXXSDKObjcDemo"
# Step 6. Convenience step to open the project's directory in Finder
open "${PROJECT_DIR}"
If you build your framework with xcframeworks, all this configuration mess will be a lot easier. If you can, give it a try. Look at https://github.com/bielikb/xcframeworks
There should not be any problem to consume swift framework in objective c, check if the framework has the correct .h file in it.
If you want to combine multiple framework in one the you can use lipo command from terminal. Please do check the combined framework after lipo and see if there is the header file.
Also try to use the frameworks individually before lipo.
Related
I have a workspace which has 2 projects: One is a Cocoa touch framework and the other is the app which uses the framework.I have added the framework in the embedded binaries section. When I run the app, it compiles the framework and the app and things are fine. However, I need the framework to compile for all architectures and not just the one it is currently being built for. I have searched for this and the most common solution is to add a run script to enable this functionality. However, every run script I have come across is different from one another, so I am confused what is the script that is ideal for this situation? Also, is it a good idea to create a fat binary for this purpose?
I am using the following script at the moment, that I have added to the build phase of the framework (taken from http://www.insert.io/frameworkios8xcode6/):
set -e
set +u
# Avoid recursively calling this script.
if [[ $SF_MASTER_SCRIPT_RUNNING ]]
then
exit 0
fi
set -u
export SF_MASTER_SCRIPT_RUNNING=1
# Constants
SF_TARGET_NAME=${PROJECT_NAME}
UNIVERSAL_OUTPUTFOLDER=${BUILD_DIR}/${CONFIGURATION}-universal
# Take build target
if [[ "$SDK_NAME" =~ ([A-Za-z]+) ]]
then
SF_SDK_PLATFORM=${BASH_REMATCH[1]}
else
echo "Could not find platform name from SDK_NAME: $SDK_NAME"
exit 1
fi
if [[ "$SF_SDK_PLATFORM" = "iphoneos" ]]
then
echo "Please choose iPhone simulator as the build target."
exit 1
fi
IPHONE_DEVICE_BUILD_DIR=${BUILD_DIR}/${CONFIGURATION}-iphoneos
# Build the other (non-simulator) platform
xcodebuild -project "${PROJECT_FILE_PATH}" -target "${TARGET_NAME}" -configuration "${CONFIGURATION}" -sdk iphoneos BUILD_DIR="${BUILD_DIR}" OBJROOT="${OBJROOT}" BUILD_ROOT="${BUILD_ROOT}" CONFIGURATION_BUILD_DIR="${IPHONE_DEVICE_BUILD_DIR}/arm64" SYMROOT="${SYMROOT}" ARCHS='arm64' VALID_ARCHS='arm64' $ACTION
xcodebuild -project "${PROJECT_FILE_PATH}" -target "${TARGET_NAME}" -configuration "${CONFIGURATION}" -sdk iphoneos BUILD_DIR="${BUILD_DIR}" OBJROOT="${OBJROOT}" BUILD_ROOT="${BUILD_ROOT}" CONFIGURATION_BUILD_DIR="${IPHONE_DEVICE_BUILD_DIR}/armv7" SYMROOT="${SYMROOT}" ARCHS='armv7 armv7s' VALID_ARCHS='armv7 armv7s' $ACTION
# Copy the framework structure to the universal folder (clean it first)
rm -rf "${UNIVERSAL_OUTPUTFOLDER}"
mkdir -p "${UNIVERSAL_OUTPUTFOLDER}"
cp -R "${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/${PROJECT_NAME}.framework" "${UNIVERSAL_OUTPUTFOLDER}/${PROJECT_NAME}.framework"
# Smash them together to combine all architectures
lipo -create "${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/${PROJECT_NAME}.framework/${PROJECT_NAME}" "${BUILD_DIR}/${CONFIGURATION}-iphoneos/arm64/${PROJECT_NAME}.framework/${PROJECT_NAME}" "${BUILD_DIR}/${CONFIGURATION}-iphoneos/armv7/${PROJECT_NAME}.framework/${PROJECT_NAME}" -output "${UNIVERSAL_OUTPUTFOLDER}/${PROJECT_NAME}.framework/${PROJECT_NAME}"
This script requires that the framework be built for iOS Simulator. After building the the .framework in the Products folder in my workspace shows that the framework is in iphoneos folder instead of the Universal folder. Should I drag the .framework from the Universal folder into the Products section in the worksapce?
I don't know about having the framework project and the app project in the same workspace, however you can see my answer here on how I did this. I didn't have to put the framework in embedded binaries. I only had to put in Linked Frameworks and Libraries. I just set up a build script that when I build for a Generic iOS Device, it builds a Fat Framework to my desktop. I can then run the -lipo info command to confirm this is actually a fat framework. From there I put the framework in my Linked Frameworks and Libraries in my app.
What it worked for me was the following complete tutorial:
https://github.com/jverkoey/iOS-Framework
There you can see the benefits of using a Cocoa Touch static Library based Framework over a Static iOS Framework. It really is an open discuss, but I am only telling you my positive experience with it in a production environment.
The important command you have to care about is the lipo one. It's the one who will smash the binaries into a fat one. With that command you can easily check if the result contains the architectures you wanted or not. If not, check first this and then ensure you follow the instructions of the guide above.
Once you create the static library you can run the following command to check the architectures:
lipo -info YourLibrary.framework/YourLibrary
This solutions also allows you to include the framework as a dependent target to your project making your Framework development much easier. For that purpose check this chapter of the guide.
Attached code : http://speedy.sh/xTEp8/XYZFrameworkDemo.zip
I have create a framework name ABCFramework.framework having my Constant.h file where i put my MACRO used in my code.
For Ex:
#define WEBURL #"www.google.com/api"
Not i have following question.
1)
Please explain how do i distribute my ABCFramework.framework so it can be used in both simmulater and Iphone device,as till now i have to use both seperately with example code in which i want to use it.
2)
Please if a developer import my ABCFramework.framework in his code and he want to change the Constant.h WEBURL with his own WEBURL how to do it?
#define WEBURL #"www.google.com/api" //SDK URL
#define WEBURL #"www.yahoo.com/api" //USER URL TO BE ADD?
On adding aggregate target and run script
xcodebuild -target ABCFramework -sdk Debug-iphonesimulator
xcodebuild -target ABCFramework -sdk Debug-iphoneos
rm -rf "$SRCROOT/products" mkdir -p "$SRCROOT/products/ABCFramework"
lipo -create "$SOURCE_ROOT/build/Release-iphonesimulator/ABCFramework" "$SOURCE_ROOT/build/Release-iphoneos/ABCFramework" -o "$SOURCE_ROOT/products/ABCFramework/ABCFramework"
cp -r "$SOURCE_ROOT/build/Release-iphoneos/include/ABCFramework" "$SOURCE_ROOT/products/ABCFramework/include"
I am getting this error /
xcodebuild: error: SDK "Debug-iphonesimulator" cannot be located.
xcodebuild: error: SDK "Debug-iphoneos" cannot be located.
fatal error: lipo: can't open input file: /Users/xxxxxxxx/build/Release-iphonesimulator/ABCFramework (No such file or directory)
cp: /Users/xxxxxxxx/build//build/Release-iphoneos/include/ABCFramework: No such file or directory
NOTE: My project in which i create ABCFramework is XYZFrameworkDemo
1) To create a Universal framework that works on Simulator and device you have to build them separately and then use the lipo command to merge them. You do this by creating a Aggregate target and building the code once in simulator and once for device. You add a Run script phase to the aggregate target to build both simulator and device version which will go into their respective folders and then merge them using lipo command.
xcodebuild -target ABCFramework -sdk iphonesimulator
xcodebuild -target ABCFramework -sdk iphoneos
rm -rf "$SRCROOT/products"
mkdir -p "$SRCROOT/products/ABCFramework"
lipo -create "$SOURCE_ROOT/build/Release-iphonesimulator/ABCFramework" "$SOURCE_ROOT/build/Release-iphoneos/ABCFramework" -o "$SOURCE_ROOT/products/ABCFramework/ABCFramework"
cp -r "$SOURCE_ROOT/build/Release-iphoneos/include/ABCFramework" "$SOURCE_ROOT/products/ABCFramework/include"
2) You cannot change the macros in the framework after its built. You have to provide a api or a exported variable to set this property from the app that's integrating your framework.
I need to build dynamic library as framework. I have building settings as follows:
ARCHS: armv7 armv7s arm64 i386 x86_64
ONLY_ACTIVE_ARCH: NO
VALID_ARCHS: arm64 armv7 armv7s x86_64 i386
I built target for ios device, and used lipo -info to check the architectures, the result is :
Architectures in the fat file: dyl are: armv7s armv7 arm64
So, does xcode can not build for both i386 and arm?
You need to select iOS simulator and build a framework for i386 arch. Then you can use lipo -create command to merge the two framework into one.
There is a way of doing it without exiting the Xcode. First you need to identify the latest iOS versions (64 bits) do not support i386 architecture. So if you still need i386 compatible framework, you have to build your project by selecting an old iOS version. I tried with iOS 10.
Next thing that you have to do is, add all the architectures that you need under Valid Architectures filed in the Build Settings.
Then, add a Run Script with your lipo commands to create the FAT file. (Following script I've taken from the Internet sometime back & credit goes to those who wrote that)
#!/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 (if it exists) to the copied framework directory
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. 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}"
Finally what you have to do is, build the framework by selecting Generic iOS Device option.
Then to verify, run the lipo -info command
I am creating a little SDK, I want to release a Foo.framework.
What I have done is the following:
1- Create a project framework.
2- Add my code.
3- Add an agregator.
In the Agregator Build Phases I added the this run 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. 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 4. Convenience step to copy the framework to the project's directory
cp -R "${UNIVERSAL_OUTPUTFOLDER}/${PROJECT_NAME}.framework" "${PROJECT_DIR}"
//Step 5. Convenience step to open the project's directory in Finder
open "${PROJECT_DIR}"
Then I build the Agregator and get the Foo.framwork
My problem is, to be able to use the framework in another application I should:
step 1 - drag and drop the framework to my project.
step 2- And add it to the embedded binaries.
If I don't do the step 2 I get this error
dyld: Library not loaded: #rpath/Foo.framework/Foo
Referenced from: /private/var/mobile/Containers/Bundle/Application/00A2E4FD-23F4-43E8-AA85-505785A4FF16/foo.app/foo
Reason: image not found
How should I do if I want to use the framework only by dragging it to my project
(In other words add it only to Link Binary with Library) to make it simple to integrate.
Thanks in advance.
For All People facing this kind of issue the solution is here.
Just follow those instruction to build a Framework
https://github.com/jverkoey/iOS-Framework#walkthrough
This is the first time I have ever tried to create a custom iOS Framework. I'm trying to create custom iOS Framework using xCode by following this tutorial. I have gotten all the way to the very last step (Step 12).
Step 12: Build Project with Aggregate scheme
Select Aggregate("UniversaliOS") Scheme
Select iOS device
Build Project (⌘-B)
But the build fails with a Shell Script Invocation Error: Command /bin/sh failed with exit code 1. The error details are:
ditto: can't get real path for source
lipo: can't create temporary output file: /Users/pdl/Library/Developer/Xcode/DerivedData/InnerID-iOS-SDK-dgyjuudeootshidhpzlejhbyqvco/Build/Products/InnerID-iOS-SDK-Bundle.framework/InnerID-iOS-SDK-Bundle.lipo (No such file or directory)
Command /bin/sh failed with exit code 1
I have absolutely no clue as to what to do now. Any suggestions? I can provide the PhaseScriptExecution dump if necessary.
Thank you in advance for your help.
This is the correct shell script to be used (for swift).
CONFIG=Release
# Step 1. Make sure the output directory exists
UNIVERSAL_OUTPUTFOLDER=${BUILD_DIR}/${CONFIG}-universal
mkdir -p "${UNIVERSAL_OUTPUTFOLDER}"
# Step 2. Build Device and Simulator versions
codebuild -target "${PROJECT_NAME}" ONLY_ACTIVE_ARCH=NO -configuration ${CONFIG} -sdk iphoneos BUILD_DIR="${BUILD_DIR}" BUILD_ROOT="${BUILD_ROOT}" clean build
xcodebuild -target "${PROJECT_NAME}" ONLY_ACTIVE_ARCH=NO -configuration ${CONFIG} -sdk iphonesimulator -arch x86_64 -arch i386 BUILD_DIR="${BUILD_DIR}" BUILD_ROOT="${BUILD_ROOT}" clean build
# Step 3. Copy the framework structure to the universal folder. Subsequently copy the files of the swiftmodule (in Modules directory) of -iphonesimulator to the swiftmodule of universal framework directory.
cp -R "${BUILD_DIR}/${CONFIG}-iphoneos/${PROJECT_NAME}.framework" "${UNIVERSAL_OUTPUTFOLDER}/"
cp -R "${BUILD_DIR}/${CONFIG}-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}/${CONFIG}-iphonesimulator/${PROJECT_NAME}.framework/${PROJECT_NAME}" "${BUILD_DIR}/${CONFIG}-iphoneos/${PROJECT_NAME}.framework/${PROJECT_NAME}"
If you still have any doubts, you can look at the video tutorial.
You didn't compile your iOSBundle for both(Step 10) and directly attempt to merge both iOS simulator and device(Step 12).
Basically what Step 10 is doing?
Its's just creating Framework for both Simulator and Device, So for some reason your build folder gets empty and your script not able find framework for iOS-Simulator and Device both or any one.
Quick resolution :
Perform Step 10, one more time before Step 12, this will create iOS-simulator Framework and Device Framework both, After that build project for your Aggregate scheme, this will merge both framework.
You can find all three(iOS-Simulaor, Device, Merged) framework at below
/Users/jaym/Library/Developer/Xcode/DerivedData/iOSFramework-doeqysadgntrrlguuvcivuhapnlr/Build/Products/
In your case, /Users/pdl/Library/Developer/Xcode/DerivedData/InnerID-iOS-SDK-dgyjuudeootshidhpzlejhbyqvco/Build/Products/