Xcode distribute individual frameworks with common dependency framework(s)

Vignesh
3 min readNov 29, 2021

Requirement

In my recent project, there was a requirement as follows

  1. Our organization supports N number of BLE (Bluetooth Low Energy) devices.
  2. Our clients will build their own app which uses 1 or more BLE devices.
  3. We have to share a BLE framework which should have API for the devices which our client is interested in.
  4. We should not explore the API of other devices that client is not interested in.
  5. Also we should not share the source code with any of our client.

Approach

Created a base Swift Package as BaseBLE which has a dependency of a 3rd party BLE based Swift Package. And this package will have source code with all basic BLE communication logic.

Then created N number of Swift Packages for individual devices, which depends on BaseBLE swift package.

Then we can use this in our sample iOS application and can able to communicate with all the supported BLE devices.

Now we have to convert this into Frameworks or XCFrameworks, so we can share it with our client obscuring the source code.

Swift Packages to XCFrameworks conversion

BaseBLE package to XCFrameworks

  • Navigate to BaseBLE package directory from terminal.
  • Create GenerateXcodeproj.xcconfig with following content.

MACOSX_DEPLOYMENT_TARGET = 10.10

IPHONEOS_DEPLOYMENT_TARGET = 9.0

WATCHOS_DEPLOYMENT_TARGET = 2.0

TVOS_DEPLOYMENT_TARGET = 9.0

BUILD_LIBRARY_FOR_DISTRIBUTION = YES

SWIFT_ACTIVE_COMPILATION_CONDITIONS = $(inherited) XCODE_PROJECT

  • Our BaseBLE package has resource bundle. To work seamlessly when we build either using Swift package or using framework, we add XCODE_PROECT as active compilation flag. Please find the below sample code

#if XCODE_PROJECT

private static var bundle = Bundle(for: BaseBLE.self)

#else

private static var bundle = Bundle.module

#endif

  • Generate a XCode project with following command.

swift package generate-xcodeproj — xcconfig-overrides GenerateXcodeproj.xcconfig

  • Open the generated XCode project.
  • Mark all dependent framework and libraries as Do Not Embed. (As we will generate these individual XCFramework from these each dependent framework and will share it with our client, do avoid duplicating these dependencies in individual device framework)
  • Add required resources against BaseBLE target.
  • Add BaseBLE scheme under Manage Schemes.
  • Execute following script from project directory.

Sample command,

./GenerateBaseBLEXCFramework.sh -p iOS, iOS Simulator

XCFrameworks for BaseBLE and all its dependency frameworks will get generated in build directory.

Repeat the above steps whenever we make changes in the BaseBLE source code.

BLEDevice package to XCFramework

  • Navigate to BLEDevice package in terminal.
  • Create GenerateXcodeproj.xcconfig with following content, the reason for the use of XCODE_PROJECT is explained above

MACOSX_DEPLOYMENT_TARGET = 10.10

IPHONEOS_DEPLOYMENT_TARGET = 9.0

WATCHOS_DEPLOYMENT_TARGET = 2.0

TVOS_DEPLOYMENT_TARGET = 9.0

BUILD_LIBRARY_FOR_DISTRIBUTION = YES

SWIFT_ACTIVE_COMPILATION_CONDITIONS = $(inherited) XCODE_PROJECT

  • Generate a XCode project with following command.

swift package generate-xcodeproj — xcconfig-overrides GenerateXcodeproj.xcconfig

  • Open the generated XCode project.
  • Mark all dependent framework and libraries as Do Not Embed. (As we have generated the dependent XCFrameworks above.)
  • Add required resources against BLEDevice target.
  • Add BLEDevice scheme under Manage Schemes.
  • Execute following script from project directory.

Sample command,

./GenerateBLEDeviceXCFramework.sh -p iOS, iOS Simulator

XCFramework for BLEDevice will get generated in build directory.

Repeat the above steps whenever we make changes in the BLEDevice source code.

Repeat BLEDevice to XCFramework conversion for each device.

Conclusion

Share the BaseBLE XCFramework and its dependency XCFrameworks generated above and required BLEDevices’ XCFrameworks with corresponding client.

--

--

Vignesh

iOS and Flutter Application Developer, Learning Spring Boot, Passion to learn new technologies and try Hello World!