Prevent framework dependencies from being embedded when using Swift Package Manager

Viewed 385

I'm working on an iOS app (A) which embeds an internally-developed framework (B). When building the app, the framework's dependencies are being embedded within the framework itself, which causes the App Store validation process to reject the app with the error:

ERROR ITMS-90206: "Invalid Bundle. The bundle at 'A.app/Frameworks/B.framework' contains disallowed file 'Frameworks'

Inspecting the built .app bundle confirms this.

Dependencies for both the app and internal framework are managed with Swift Package Manager, and this is set up for both by adding the required package dependencies to each Project and each target's "Frameworks and Libraries" + "Link Binary With Libraries". All the framework B's dependencies are shared by the app, and B is itself not a Swift Package.

I was previously using Carthage for dependency management, and avoided this issue by setting the app's dependencies to "Embed & Sign" and the framework's dependencies to "Do Not Embed" under "Frameworks and Libraries". This setup ensured all framework dependencies were contained in A.app/Frameworks/, and B.framework linked against these. However, SPM doesn't give any visible option to modify the behaviour in this way.

Assuming I'm not approaching the problem the wrong way, how do you ensure that Xcode doesn't embed the framework's SPM dependencies within the framework itself but instead dynamically links them to the app's version?

1 Answers

I'm seeing the exact same behavior. With Xcode < 13.3, we were using the following script:

#!/bin/bash

# See https://bugs.swift.org/browse/SR-14292
set -euxo pipefail

cp -r "${BUILT_PRODUCTS_DIR}"/InternalFramework.framework/Frameworks/* "${TARGET_BUILD_DIR}"/"${FRAMEWORKS_FOLDER_PATH}"

rm -rf "${TARGET_BUILD_DIR}"/"${FRAMEWORKS_FOLDER_PATH}"/InternalFramework.framework/Frameworks/

This doesn't work for Xcode 13.3 because Xcode 13.3 doesn't embed the frameworks in the Frameworks/ folder of InternalFramework.framework.

The alternative is likely to do something like this where you explicitly list the frameworks you want to embed:

frameworks=(
  AWSCore.framework AWSS3.framework
  …
)

for framework in "${frameworks[@]}"
do
  rm -rf "${TARGET_BUILD_DIR:?}"/"${FRAMEWORKS_FOLDER_PATH}/$framework"
  cp -r "${BUILT_PRODUCTS_DIR}"/$framework "${TARGET_BUILD_DIR}"/"${FRAMEWORKS_FOLDER_PATH}"
done

This will work for the simulator and probably App Store submission. For running on device, this will require re-signing the frameworks first.

Related