Invalid Bundle, The bundle contains disallowed nested bundles, contains disallowed file 'Frameworks' - ios

I added a shared framework to share code between app and watch extension. Later I removed the shared framework since it cause lots of problems. I can build
and run my app on iphone and watch. However when I submit to app store, I see these two errors:
ERROR ITMS-90205: "Invalid Bundle. The bundle at 'xxx WatchKit Extension.appex' contains disallowed nested bundles."
ERROR ITMS-90206: "Invalid Bundle. The bundle at 'xxx WatchKit Extension.appex' contains disallowed file 'Frameworks'."
I have tried all the solutions mentioned on stackoverflow(this , this, this) None of them works for me. How do I fix the error? Errors message from apple really doesn't give a clue what I should to.

I still do not fully understand what causes the issue, but I've stumbled upon an answer that has finally solved the issue for me.
https://github.com/CocoaPods/CocoaPods/issues/4203
Specifically, the post by mikehouse on Oct 12, 2015 was the solution to the the problem.
Add the following run script to ALL you embedded extension targets. In my case I had to add the run script as a build phase to my Today extension and my Apple Watch App extension.
cd "${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/"
if [[ -d "Frameworks" ]]; then
rm -fr Frameworks
fi

The "ITMS-90206" error was resolved in this post: Validation Error: Invalid Bundle. The bundle at ... contains disallowed file 'Frameworks'
The setting needs to be changed from Yes to No within the Build options of your WatchKit Extension:
Embedded Content Contains Swift Code: No

The above didn't work for me.
Embedded Content Contains Swift Code: NO
Didn't really do anything for me.
I experienced this issue using a dynamic framework.
My dynamic framework contained other dynamic frameworks which made it OK
to have:
Embedded Content Contains Swift Code: YES
And instead having the other dynamic frameworks set it to No instead.
But instead of that I had to set
Always Embed Swift Standard Libraries: NO
under Build Phases.
Having this one set to YES generated the frameworks folder causing upload to ITC fail.

In the main target add:
cd "${CODESIGNING_FOLDER_PATH}"
find ./PlugIns -type d -name Frameworks | xargs rm -rf
The problem is that adding SPM packages on multiple targets of the same project will duplicate the dependencies. The frameworks on this extension are probably on the main target so this should be enough. Otherwise use the full script below on the main target, which will deduplicate the frameworks if needed by moving them to the app.
Do NOT add this to your extension target. It tries to remove the duplicated framework but it has no effect because it runs before the framework is copied to the extension:
# this has no effect if you add it to your extension target
cd "${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/"
if [[ -d "Frameworks" ]]; then
rm -fr Frameworks
fi
I ran into this problem in a project that uses Rx as a SPM package in the main target, frameworks, and extensions. If you have the same or similar problem (e.g. Firebase), you can fix it with the following script in the main target:
if ! [ "${CONFIGURATION}" == "Release" ] ; then
echo "early exit"
exit 0
fi
cd "${CODESIGNING_FOLDER_PATH}/Frameworks/"
# copy frameworks to TeamworkProjects.app/Frameworks
for framework in *; do
if [ -d "$framework" ]; then
if [ -d "${framework}/Frameworks" ]; then
echo "Moving embedded frameworks from ${framework} to ${PRODUCT_NAME}.app/Frameworks"
cp -R "${framework}/Frameworks/" .
rm -rf "${framework}/Frameworks"
fi
fi
done
# remove leftover nested frameworks
for framework in *; do
if [ -d "$framework" ]; then
if [ -d "${framework}/Frameworks" ]; then
echo "Removing embedded frameworks from ${framework} to ${PRODUCT_NAME}.app/Frameworks"
rm -rf "${framework}/Frameworks"
fi
fi
done
# Remove Frameworks from PlugIns
cd "${CODESIGNING_FOLDER_PATH}"
find ./PlugIns -type d -name Frameworks | xargs rm -rf
# codesign for Debugging on device
if [ "${CONFIGURATION}" == "Debug" ] & [ "${SDKROOT}" != *Simulator* ] ; then
echo "Code signing frameworks..."
find "${CODESIGNING_FOLDER_PATH}/Frameworks" -maxdepth 1 -name '*.framework' -print0 | while read -d $'\0' framework
do
# only sign frameworks without a signature
if ! codesign -v "${framework}"; then
codesign --force --sign "${EXPANDED_CODE_SIGN_IDENTITY}" --preserve-metadata=identifier,entitlements --timestamp=none "${framework}"
echo "Added missing signature to '${framework}'"
fi
done
fi
Most of this script came from user pewe at forums.swift.org: Swift packages in multiple targets results in duplication of library code.

I had a framework that builded with the following build settings:
Always Embed Swift Standard Libraries: YES
Allow Non-Modular includes in Framework Modules: YES
So I changed both to NO and build framework again.
Always Embed Swift Standard Libraries: NO
Allow Non-Modular includes in Framework Modules: NO
I added new build of framework to my project so It uploaded to iTunes Connect successfully.

I add a swift package, which is dynamic library, into sub-projects, and into my main project. When uploading to TestFlight, I encounter this issues too.
As the picture, I change Embed & Sign to Do Not Embed for the sub-project, and then this issue is resolved.
It keeps Embed & Sign for my main project. But in sub-projects, I change them to Do Not Embed.

I had a today extension which uses a custom framework I implemented it.
I tried all the solutions but nothing worked for me.
I needed the custom framework only in the today extension, so I linked and embedded this framework in the today extension only.
What the error is saying is:
that the bundle contains disallowed frameworks
Today extension should not embed any framework, shall only link to it.
So I removed the framework from the today extension and added it to the parent app.
Note that:
the parent app should use this framework since it's added to it, an import shall do the job.

Related

How to access my app’s derived data folder itself?

I’m in the middle of moving my iOS app’s Firebase dependency from CocoaPods to Swift Package Manager.
Firebase’s Crashlytics requires a script to be executed while the app is building (using the Run Script build phase). Back in the CocoaPods days, I used to call the script the way documented by Google: "${PODS_ROOT}/FirebaseCrashlytics/run".
After I’ve switched to SPM, Firebase files are no longer in ${PODS_ROOT}, and there’s no such variable available at all. I know the file I need is now located in the DerivedData folder, specifically it’s at ~/Library/Developer/Xcode/DerivedData/MyApp-abcde/SourcePackages/checkouts/firebase-ios-sdk/Crashlytics/run. The problem is, the MyApp-abcde folder is not easily referenced.
A Medium post I found suggested using the ${BUILD_DIR} build variable (in regard to the example above, it would resolve to <…>/MyApp-abcde/Build/Products), and calling the dirname command to move up the directory hierarchy.
This hack worked only for running the app. When I tried to archive it, ${BUILD_DIR} resolved to another path, namely <…>/MyApp-abcde/Build/Intermediates.noindex/ArchiveIntermediates/MyApp/BuildProductsPath. I tried a few more build variables, such as ${SYMROOT}, in place of ${BUILD_DIR}, but they also produce different paths depending on the operation.
So, here comes the question…
Is there a way to reliably reference my app’s derived data folder’s root (i.e. ~/Library/Developer/Xcode/DerivedData/MyApp-abcde) using Xcode’s build variables?
You were close. This should work:
${BUILD_DIR%Build/*}SourcePackages/checkouts/firebase-ios-sdk/Crashlytics/run
Crashlytics run script
To build&run from Xcode:
${BUILD_DIR%Build/*}SourcePackages/checkouts/firebase-ios-sdk/Crashlytics/run
To archive for distribution from Xcode Server at CI/CD:
${XCS_DERIVED_DATA_DIR%/*}/Dependencies/checkouts/firebase-ios-sdk/Crashlytics/run
To work for both at the same time:
if [[ "${XCS_DERIVED_DATA_DIR}" == "" ]]; then
${BUILD_DIR%Build/*}SourcePackages/checkouts/firebase-ios-sdk/Crashlytics/run
else
${XCS_DERIVED_DATA_DIR%/*}/Dependencies/checkouts/firebase-ios-sdk/Crashlytics/run
fi
I'm reworking my answer as I realized I haven't answered your question..
I have a run script that copies the build targets into a new folder. This works for both Build and Archive. Note that you need the -L on copy to follow the symlink
# Copy the built framework into a sibling to the project folder
if [[ "$CONFIGURATION" == "Debug" ]]; then
mkdir -p "$PROJECT_DIR/../../iwins-ios-sdk/debug"
rm -rf "$PROJECT_DIR/../../iwins-ios-sdk/debug/IWiNS_SDK.framework"
cp -LR "$BUILD_DIR/Debug-iphoneos/IWiNS_SDK.framework" "$PROJECT_DIR/../../iwins-ios-sdk/debug"
else
mkdir -p "$PROJECT_DIR/../../iwins-ios-sdk/release"
rm -rf "$PROJECT_DIR/../../iwins-ios-sdk/release/IWiNS_SDK.framework"
cp -LR "$BUILD_DIR/Release-iphoneos/IWiNS_SDK.framework" "$PROJECT_DIR/../../iwins-ios-sdk/release"
fi
Also, you can find all of the build envvars here:
https://gist.github.com/gdavis/6670468
So, it appears that $BUILD_DIR is different for build/release, but by copying the files to a known location at build time, you'll know where to find them.

Failed to verify bitcode while exporting archive for ad hoc distribution - tried Xcode 8.3.3 & Xcode 9

Apps containing our framework complains about missing bitcode while exporting archive for Ad-hoc distribution.
I have gone through the documentation provided by Apple in this regard
Technical Note TN2432. The documentations' listed possible root causes do not resemble our scenario. (We are not using assembly instructions or have malformed info.plist file)
I have gone through following similar questions posted on SO
Error while exporting with Bitcode enabled (symbol not found for architecture armv7)
Is it possible to create a universal iOS framework using bitcode?
New warnings in iOS 9
But the provided solutions do not seem to work.
I have tried adding BITCODE_GENERATION_MODE flag in User-Defined build settings. I also tried adding -fembed-bitcode-marker & -fembed-bitcode in Other C flags in framework target.
I check if bitcode segments are present in my generated framework using the suggested command
otool -l -arch arm64 <framework_name> | grep __LLVM
It shows 2 segments
segname __LLVM
segname __LLVM
But while exporting the archive, Xcode still complains about absent bitcode.
I tried to upload app on App store to verify if this issue is due to Xcode versions (I tried 8.3.3. and 9.0), but I get following email about build import error from iTunes Store.
While processing your iOS app, APP_NAME 1.0(4), errors occurred in the app thinning process, and your app couldn’t be thinned. If your app contains bitcode, bitcode processing may have failed. Because of these errors, this build of your app will not be able to be submitted for review or placed on the App Store. For information that may help resolve this issue, see Tech Note 2432.
PS: Disabling bitcode is not an option for us as host app need to support bitcode.
The error description took me in the wrong direction to find the solution.
This error is not related to bitcode.
It appeared when the framework contained simulator slices (i386 x86_64)
Removing them before archiving resolved the issue.
Adding a run script phase to build phases of the target with following code helped in getting rid of the error.
APP_PATH="${TARGET_BUILD_DIR}/${WRAPPER_NAME}"
# This script loops through the frameworks embedded in the application and
# removes unused architectures.
find "$APP_PATH" -name '*.framework' -type d | while read -r FRAMEWORK
do
FRAMEWORK_EXECUTABLE_NAME=$(defaults read "$FRAMEWORK/Info.plist" CFBundleExecutable)
FRAMEWORK_EXECUTABLE_PATH="$FRAMEWORK/$FRAMEWORK_EXECUTABLE_NAME"
echo "Executable is $FRAMEWORK_EXECUTABLE_PATH"
EXTRACTED_ARCHS=()
for ARCH in $ARCHS
do
echo "Extracting $ARCH from $FRAMEWORK_EXECUTABLE_NAME"
lipo -extract "$ARCH" "$FRAMEWORK_EXECUTABLE_PATH" -o "$FRAMEWORK_EXECUTABLE_PATH-$ARCH"
EXTRACTED_ARCHS+=("$FRAMEWORK_EXECUTABLE_PATH-$ARCH")
done
echo "Merging extracted architectures: ${ARCHS}"
lipo -o "$FRAMEWORK_EXECUTABLE_PATH-merged" -create "${EXTRACTED_ARCHS[#]}"
rm "${EXTRACTED_ARCHS[#]}"
echo "Replacing original executable with thinned version"
rm "$FRAMEWORK_EXECUTABLE_PATH"
mv "$FRAMEWORK_EXECUTABLE_PATH-merged" "$FRAMEWORK_EXECUTABLE_PATH"
done
Credits: http://ikennd.ac/blog/2015/02/stripping-unwanted-architectures-from-dynamic-libraries-in-xcode/
If you don't know how to add a run script phase to your Xcode project, because maybe you're building a project with Cordova or Ionic and you never were taught much about Xcode, here's how you do that:
Open your project in Xcode.
Make sure you're looking at your project in the "Project Navigator" by clicking on the left-most icon in the left pane of Xcode (the one that says "show Project Navigator" when you point at it.
Click on your project at the top of the navigator window, so that it is selected as your target
At that point, in the middle portion of the Xcode window, you'll see several things appear near the top. General, Capabilities, Resource Tags, Info, among others. One of them is Build Phases -- click on it.
Click the + that's near the top-left of the middle portion of the Xcode Window. It will say Add New Build Phase if you point at it long enough.
Select "New Run Script Phase" from the menu that popped up when you clicked on the +
Click on the arrow next to the Run Script that just appeared.
Copy and paste the above script into the appropriate area just below the word "Shell". You shouldn't have to change anything else.
Build/Archive your project like normal, only now you won't get those annoying "failed to verify bitcode" errors. :-)
I had to set Enable Bitcode to 'NO' in Build Settings
Try the following:
Make sure this framework is added under Copy Frameworks Script in Build Phases.
Use BITCODE_GENERATION_MODE instead of BITCODE_GENERATION_CODE
I was facing the same issue. But in my case, I found out after one day of struggle that my system was running out of memory. As soon as I created some space in the system all worked fine.

Cocoa Touch Framework fails to debug on simulator in embedding project

I've got a Cocoa Touch framework built with XCode 6 targetted towards iOS >= iOS8.
This framework's target architecture settings are default, meaning that I haven't changed anything.
The architectures are set to standard (which doesn't include x86_64, more on that later).
The framework itself contains both Swift and Objective-C code, so building it using the static library workaround from Ray Wenderlich won't work.
Now, if I create a new project and add the framework project to it, the project builds for both the device and simulator, which is fine.
However, if I take the .framework file and add it to a different project just like you'd add any other framework, the project won't build for the simulator. Well, it does build, but it crashes because it can't find the relevant classes. It works fine on the device and archiving works just as expected as well.
The framework project itself already gives me a warning;
"Apple Mach-O Linker Warning - Directory not found for option ....(Debug-ophoneos)".
Any help would be highly appreciated!
I have finally found the solution to this issue.
As it turns out, XCode no longer creates fat binaries out of the box. No idea what Apple's reasoning behind this might be, too me it just seems like sometimes the guys responsible for XCode like to make fun of the developers using their product...
Anyways, you can find the definitive guide as to how to create a fat binary for simulator and all iOS devices (yes, you even have to lipo different architectures in order to get a framework that works on newer and older devices): https://kodmunki.wordpress.com/2015/03/04/cocoa-touch-frameworks-for-ios8-remix/
In short;
Create a Cocoa Touch Framework
Set the Architectures to arm64, armv7, and armv7s
Set "Build Active Architecture" to "NO"
Set "Valid Architectures" to arm64, armv1, and armv7s
Add the following script to the framework's build Scheme as an Archive Post-action;
set -e
DEVICE_BIN="${OBJROOT}/UninstalledProducts/${TARGET_NAME}.framework"
SIMULATOR_BIN="${SYMROOT}/../../../../Products/Debug- iphonesimulator/${TARGET_NAME}.framework"
ARCHIVE_PATH="${SRCROOT}/_Archive"
rm -rf "${ARCHIVE_PATH}"
mkdir "${ARCHIVE_PATH}"
if [ "${CONFIGURATION}" = "Release" ]; then
if [ -d "${DEVICE_BIN}" ]; then
DEVICE_PATH="${ARCHIVE_PATH}/Release"
mkdir "${DEVICE_PATH}"
cp -r "${DEVICE_BIN}" "${DEVICE_PATH}"
fi
if [ -d "${SIMULATOR_BIN}" ]; then
SIMULATOR_PATH="${ARCHIVE_PATH}/Debug"
mkdir "${SIMULATOR_PATH}"
cp -r "${DEVICE_BIN}" "${SIMULATOR_PATH}"
lipo -create "${DEVICE_BIN}/${TARGET_NAME}" "${SIMULATOR_BIN}/${TARGET_NAME}" -output "${SIMULATOR_PATH}/${TARGET_NAME}.framework/${TARGET_NAME}"
fi
fi
exit 0;
This will create an _Archive directory in your project's directory where you can find the frameworks for both debug and release.
Important: As of today (May 22nd 2015) you'll have to build the project with the simulator first, and then archive with a device. Otherwise you won't get a universal binary!
This post has been created in order to avoid dead link errors, for updates regarding the packaging process, please ALWAYS try the steps posted on the kodmunki website I've linked above first as the steps in this post might have been outdated already!

When added an embedded framework in an Xcode project, how do you differentiate between Debug and Release?

When I add a framework to my Xcode project, to be embedded in my app bundle, how do I make two different options for whether it's Debug or Release (I have two versions of the framework, one compiled for release and one for debug).
This is what I'm referring to:
As you see, with that configuration, it'll just copy the one on CEF/Debug regardless of whether it's in being compiled in Release or Debug mode.
Ideally I want something like you have for setting:
You can manage frameworks to embed with your custom Run Script in Build Phases:
#!/bin/bash
# Your frameworks to embed
FRAMEWORK="Debug.framework"
if [ $CONFIGURATION == "Release" ]; then
FRAMEWORK="Release.framework"
fi
# Destination to copy inside the app's frameworks folder
NAME=$(basename $FRAMEWORK)
DESTINATION=${BUILT_PRODUCTS_DIR}/${FRAMEWORKS_FOLDER_PATH}/$NAME
# Don't copy if it's already copied
if [ ! -d $DESTINATION ]; then
# Copy the framework to the app's frameworks folder
cp -r $FRAMEWORK $DESTINATION
# Sign (if needed)
codesign --force --sign ${EXPANDED_CODE_SIGN_IDENTITY} ${OTHER_CODE_SIGN_FLAGS:-} --preserve-metadata=identifier,entitlements $DESTINATION
fi
Note that you can bring in different shared libraries (such as frameworks) by setting the environment var DYLD_IMAGE_SUFFIX for your app. So if inside your (one) framwork you had CEF.framework/Versions/Curent/CEF and CEF.framework/Versions/Curent/CEF_debug and you set the env var DYLD_IMAGE_SUFFIX=_debug it will load the second for that run.
You don't need to. Embedded frameworks will build according to the build of the consumer app.
You can test it by adding a build schema on the app (like Debug2) and then compiling. You will receive an error from the embedded because it tried to compile it with the Debug2 schema, which is not available in the embedded framework. Now duplicate some schema and call it Debug2. It will build.

Embedding a framework within a framework (iOS 8+)

iOS applications built with Xcode 6 or higher allow embedding dynamic iOS frameworks within them. I am building a shared framework and would like to embed a sub-framework. How can I accomplish this?
Note: This is possible and is being used in production (for e.g., with Swift frameworks in CocoaPods).
Found the answer. Here's how it's done:
Navigate to Target > Build Phases
Click the small "+" icon and select "New Run Script Build Phase"
Paste the following:
cd $BUILT_PRODUCTS_DIR
mkdir $PROJECT_NAME.framework/Frameworks &>/dev/null
for framework in *.framework; do
if [ $framework != $PROJECT_NAME.framework ]; then
cp -r $framework $PROJECT_NAME.framework/Frameworks/ &>/dev/null
fi
done
#Vatsal Manot's answer was very helpful for me. I modified it a bit and also had a need to sign the copied embedded framework. My script is below.
cd $BUILT_PRODUCTS_DIR/$PRODUCT_NAME.app/Frameworks/Custom.framework/Frameworks
for framework in *.framework; do
mv $framework $BUILT_PRODUCTS_DIR/$PRODUCT_NAME.app/Frameworks/
/usr/bin/codesign --force --sign "iPhone Developer" --preserve-metadata=identifier,entitlements --timestamp=none $BUILT_PRODUCTS_DIR/$PRODUCT_NAME.app/Frameworks/$framework
done
To create a Umbrella Framework that contains a Sub-Framework you can follow the step-by-step guide written down here: Umbrella framework

Resources