/universal-framework

Universal Framework Script for iOS, iPadOS, macOS, watchOS, or tvOS. It includes a lunatic example that has Objective-C Framework used in the SwiftUI project 🤯

Primary LanguageShellGNU General Public License v3.0GPL-3.0

How to make a Universal (Fat) Framework

💡Before Starting

Before starting to reading the craziest things please check the Demo Project.

An example can explain more than the words.🔍

What is a FAT library?

The iOS framework includes a FAT (multi-architecture) binary that contains slices for armv7, arm64, i386, and x86_64 CPU architectures. ARM slices are used by physical iOS devices, while i386 and x86_64 are used by Simulator and are stripped from your app during the build and archive process. When a user downloads the app from the App Store, they receive only the architecture that their device requires.

Why We Need?

  • 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 🤔.
  • While developing your application, you need a Framework that works on both platforms. You can't rebuild your framework every time for Simulator or Device.

Good News!

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.

In other words This script creates a Fat Framework that includes both.

Demo Project

  • Demo workspace includes 2 projects:
    • A Framework project named fat, that written in Objective-C 🤯
    • A Demo project named demo, that written in Swift 5 and uses SwiftUI 🥳
  • The demo project uses the fat framework in it
  • For more details please download and check the demo project.

How to add in your Framework Project

As you can see in the demo project, noting is complicated. 🤓 👉🏻 Remember that your project must be created as a Framework project for this script works, otherwise, this script won't help you out.

STEP 1: Add a new scheme

Warning: If you're using the ** ** in your project start from here, otherwise this step is not mandatory. You can directly add in your current sheme.

⚠️ 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
  • ⚠️ Remember: We'll use this naming convention in our script file later.

STEP 2: Add a 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.

STEP 3: 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.

STEP 4: 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! ✌️

Possible Errors

  • 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.
  • 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

Test

This script

with this configurations:

  • 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)
    • 11.5 (11E608c)
    • 11.6 (11E708)
  • Also, tested with a project that uses the Cocoapods. (CocoaPods is a dependency manager for Swift and Objective-C Cocoa projects)

Resources

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 🤔.
  • Add a demo project

Communication

If you see a way to improve the project :

  • If you need help, use Stack Overflow. (Tag ios-universal-framework)
  • If you'd like to ask a general question, use Stack Overflow.
  • If you found a bug, and can provide steps to reliably reproduce it, open an issue.
  • If you have a feature request, open an issue.
  • If you want to contribute, submit a pull request. It's better to begin with an issue rather than a pull request, though, because we might disagree whether the proposed change is an actual improvement. 😉

Thanks! ✌️

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.