Writing Custom Universal Framework in Xcode 10.2 and iOS 12
Writing Custom Universal Framework in Xcode 10.2 and iOS 12
As a developer, we want to write reusable set of code as much as possible so that we can later use those components with multiple applications and to make our life easy.
A framework is a modular and reusable set of code that is used as the building blocks of higher-level pieces of software. Frameworks have three major purposes:
- Code encapsulation
- Code modularity
- Code reuse
The best reason to use frameworks is that they can be built once and be reused an infinite number of times!
Getting Started
Lets start with creating custom framework and make it universal so that it can be use on simulator as well as device.
Let’s open Xcode and create a new project. Select the iOS tab,
scroll down to
Framework & Library
and select
Cocoa Touch Framework
.
- Choose a template to for your framework project
2. Enter product name and fill other details
once you fill all the details and press next, your project is ready to build like below -
If you build the project, it will produce TestFramework.framework as product which will support either simulator or device based on the option choosen by developer.
Add Code and Resources
Your current state is a framework without code, and that is about as appealing as straight chocolate without sugar. Add your logic or features in framework and try to build it. We are focusing on creating universal framework so writing code and resources part is left for the developers to explore more or wait for another part.
Let’s make it universal framework
Now its time to learn , how to make custom framework as universal framework which can be used on both simulator as well as device.
3. Create new scheme, Select Project Target → New Schema
Please enter new schema name — ProjectName-Universal.
Its time to use this schema for making universal frameworks. I wrote a “Run Script” which generates the Universal Framework.
Select Project Target → Edit Schema → Archive → Post-actions → Press “+” → New Run Script Action.
then copy paste below script code.
UNIVERSAL_OUTPUTFOLDER=${BUILD_DIR}/${CONFIGURATION}-Universal
# Make sure the output directory exists
mkdir -p "${UNIVERSAL_OUTPUTFOLDER}"
# Next, work out if we're in SIMULATOR or REAL DEVICE
xcodebuild -target "${PROJECT_NAME}" -configuration ${CONFIGURATION} -sdk iphonesimulator ONLY_ACTIVE_ARCH=NO BUILD_DIR="${BUILD_DIR}" BUILD_ROOT="${BUILD_ROOT}" clean build
xcodebuild -target "${PROJECT_NAME}" ONLY_ACTIVE_ARCH=NO -configuration ${CONFIGURATION} -sdk iphoneos 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
BUILD_PRODUCTS="${SYMROOT}/../../../../Products"
cp -R "${BUILD_PRODUCTS}/Debug-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_PRODUCTS}/Debug-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}"
fi
Once you are done with copy paste above script into your project, it will look similar to this -
This run script would be executed after the Archive is completed. And the Universal Framework would be generated and opened in project directory itself.
You are ready to share your universal framework. WOW!!
For sharing framework, Please right click on softlink of framework and choose show original path for framework option, then you can copy and use it in your project.
Let’s add it into your project
Copy/Drag the Universal Framework to this project. While coping the framework in Project Explorer, check “Copy items if needed”.
Select the Project, Choose Target → Project Name → Select General → Scroll to “Embedded Binaries”. Press “+” and Add the framework.
Remember
Now the universal framework will run on both simulators and Devices. But still there is a problem.
Let’s assume an application uses our custom universal framework on production, we we need to remove unused architectures. Because Apple doesn’t allow the application with unused architectures to the App Store.
Please make sure that you have Remove Unused Architectures Script added in your project while releasing your app to app store.
Remove Unused Architectures:
Select the Project, Choose Target → Project Name → Select Build Phases → Press “+” → New Run Script Phase → Name the Script as “Remove Unused Architectures Script”.
FRAMEWORK="TestFramework"
FRAMEWORK_EXECUTABLE_PATH="${BUILT_PRODUCTS_DIR}/${FRAMEWORKS_FOLDER_PATH}/$FRAMEWORK.framework/$FRAMEWORK"
EXTRACTED_ARCHS=()
for ARCH in $ARCHS
do
lipo -extract "$ARCH" "$FRAMEWORK_EXECUTABLE_PATH" -o "$FRAMEWORK_EXECUTABLE_PATH-$ARCH"
EXTRACTED_ARCHS+=("$FRAMEWORK_EXECUTABLE_PATH-$ARCH")
done
lipo -o "$FRAMEWORK_EXECUTABLE_PATH-merged" -create "${EXTRACTED_ARCHS[@]}"
rm "${EXTRACTED_ARCHS[@]}"
rm "$FRAMEWORK_EXECUTABLE_PATH"
mv "$FRAMEWORK_EXECUTABLE_PATH-merged" "$FRAMEWORK_EXECUTABLE_PATH"
Thats all !!
This run script removes the unused Simulator architectures only while pushing the Application to the App Store.
Now the Custom iOS Framework is complete and it remains Universal.
Please find the attached sample working project
Hope this article is useful for people looking to create custom Universal iOS framework, Please ❤️ to recommend this post to others 😊. Let me know your feedback. :)
References:-