/universal-framework

Universal Framework example for iOS, iPadOS, macOS, watchOS or tvOS.

Primary LanguageShellGNU General Public License v3.0GPL-3.0

How to make a Universal (Fat) Framework

Why

If you're building for iphonesimulator, you'll get a framework with an x86 slice but no ARM slice. If you build for iphoneos, you'll get a framework with arm slice(s), but no simulator support.

This script compiles for both platforms and all potential slices, merges the binaries produced from each, and produces a completed framework using the structure from either of the first two, single platform builds.

Info

This example uses and tested with this configuration:

  • Tested on the Xcode versions listed below:
    • 11.1 (11A1027) (this is where we started...)
    • 11.2 (11B52)
    • 11.2.1 (11B500)
    • 11.3 (11C29)
    • 11.3.1 (11C504)and above...
  • and the Cocoapods (CocoaPods is a dependency manager for Swift and Objective-C Cocoa projects)

That's why in the script file we're using the workspace instead of the target. So, if you have a project without a workspace please update your xcodebuild lines in the script file with code below:

xcodebuild -target "${PROJECT_NAME}" 

final result is something like this:

xcodebuild -target "${PROJECT_NAME}" -configuration ${CONFIGURATION} -sdk iphonesimulator ONLY_ACTIVE_ARCH=NO BUILD_DIR="${BUILD_DIR}" BUILD_ROOT="${BUILD_ROOT}" -UseModernBuildSystem=NO clean build
  • ⚠️ If your project is unable to build via xcodebuild command for some reason, this script will not help you, and you'll get a build error. First, be sure that your project can build on the terminal and try this project.

Add a new scheme

Warning: This step is not mandatory. You can directly add in your current sheme. But I found a it's little bit risky for newbies.

If you're using the Cocoapods you need to copy all the other settings under your scheme. That's why we will duplicate our scheme instead of creating a new one.

Duplicate your scheme under Product → Scheme → Manage Schemes... menu. Make sure that the shared box is selected.

Edit your scheme name like line below:

YourProjectName-Universal
  • ⚠️ we will use this naming convention in our script file.

Run Script Action

Select Project Target → Edit Scheme → Archive → Post-actions → Press “+” → New Run Script Action

  • copy-paste the script from this file.
  • at the top of script file find the Global Variables section. And fill your target's architecture like giving example below the line:

iOS

DEVICE_ARCH="iphoneos"
DEVICE_SIM_ARCH="iphonesimulator"

All Avilable Architectures

Device Simulator
macosx -
iphoneos iphonesimulator
appletvos appletvsimulator
watchos watchsimulator
  • ⚠️ Under the Provide Build Settings From menu YourProjectName must be selected. ⚠️

Archive

Then run the Build > Archive on your Xcode.

The Post Script will be executed after the Archive is completed. And the Universal Framework would be generated and opened in project directory itself.

Sending to the App Store

So, you move your archived Universal framework in your desired project. But, while you sending your application to the App Store you will face "Operation Error: Unsupported architectures" error. You have to remove the unused architectures from your Fat (Universal) framework before sending to the App Store. For this select the Project, Choose Target → Project Name → Select Build Phases → Press “+” → New Run Script Phase and than Name the Script as “Remove Unused Architectures”.

And add the script from this file.

  • ⚠️ Don't forget to change the line below with your Universal framework's name:
FRAMEWORK="YOUR_FRAMEWORK_NAME"

Thats All!

Best of luck! ✌️

TODO

  • Support for multiple frameworks in cleanforappstore.sh. But not all (this will cause an error because of Cocoapods frameworks are not fat frameworks). Use an static array 🤔.

Author

Muhammed Gurhan Yerlikaya, gurhanyerlikaya@gmail.com

License

"universal-framework" is available under the GNU General Public License v3.0 license. See the LICENSE file for more info.