Xcode 10: Code Signing my App+Framework fails, bec

2020-05-25 07:00发布

I have an Xcode 10 - iOS12 swift project that links against My own framework (also Xcode 10 + iOS12).

The app project is referencing my framework project as a sub-project reference.

My Framework project references PromiseKit.framework (a universal framework - fat library), made using the following build script:

# Merge Script

# 1
# Set bash script to exit immediately if any commands fail.
set -e

# 2
# Setup some constants for use later on.
FRAMEWORK_NAME="PromiseKit"

# 3
# If remnants from a previous build exist, delete them.
if [ -d "${SRCROOT}/build" ]; then
rm -rf "${SRCROOT}/build"
fi

# 4
# Build the framework for device and for simulator (using
# all needed architectures).
xcodebuild -target "${FRAMEWORK_NAME}" -configuration Release -arch arm64 only_active_arch=no defines_module=yes -sdk "iphoneos"
xcodebuild -target "${FRAMEWORK_NAME}" -configuration Release -arch x86_64 only_active_arch=no defines_module=yes -sdk "iphonesimulator"

# 5
# Remove .framework file if exists on Desktop from previous run.
if [ -d "${SRCROOT}/${FRAMEWORK_NAME}.framework" ]; then
rm -rf "${SRCROOT}/${FRAMEWORK_NAME}.framework"
fi

# 6
# Copy the device version of framework to Desktop.
cp -r "${SRCROOT}/build/Release-iphoneos/${FRAMEWORK_NAME}.framework" "${SRCROOT}/${FRAMEWORK_NAME}.framework"

# 7
# Replace the framework executable within the framework with
# a new version created by merging the device and simulator
# frameworks' executables with lipo.
lipo -create -output "${SRCROOT}/${FRAMEWORK_NAME}.framework/${FRAMEWORK_NAME}" "${SRCROOT}/build/Release-iphoneos/${FRAMEWORK_NAME}.framework/${FRAMEWORK_NAME}" "${SRCROOT}/build/Release-iphonesimulator/${FRAMEWORK_NAME}.framework/${FRAMEWORK_NAME}"

# 8
# Copy the Swift module mappings for the simulator into the
# framework.  The device mappings already exist from step 6.
cp -r "${SRCROOT}/build/Release-iphonesimulator/${FRAMEWORK_NAME}.framework/Modules/${FRAMEWORK_NAME}.swiftmodule/" "${SRCROOT}/${FRAMEWORK_NAME}.framework/Modules/${FRAMEWORK_NAME}.swiftmodule"

# 9
# Delete the most recent build.
if [ -d "${SRCROOT}/build" ]; then
rm -rf "${SRCROOT}/build"
fi

When I go to archive my Parent App Project using Xcode 10 (And also 9.4.1) with Bitcode ON (that contains My Framework reference, and PromiseKit Fat library), I get the following error on the Signing stage: (Failed to verify bitcode in PromiseKit.framework/PromiseKit: error Cannot extract bundle from /var/folders..../(x86_64) - which suggests that it's simulator slice related) enter image description here

If I turn the "Rebuild from Bitcode" option in the Organizer to OFF, then I get a different error: (Code signing "PromiseKit.framework" failed) enter image description here

However, if I use Xcode 9.4.1 With Bitcode OFF, then it exports and signs fine.

Why is it trying to individually re-sign sub frameworks, and what can I do to alleviate the issues? I need the archiving to work normally with Xcode 10, along with any future third party dependencies being added to my framework target. (This is the first dynamic framework dependency added to my Framework target. Before I was "baking in" - in-boarding all 3rd parties for ease of development purposes, but PromiseKit is difficult to inboard due to extensive dependencies on Objective-c).

The Xcode Archive log is:

 {
        code = 330;
        description = "Failed to resolve linkage dependency PromiseKit x86_64 -> @rpath/libswiftFoundation.dylib: Unknown arch x86_64";
        info =             {
        };
        level = WARN;
    },
            {
        code = 330;
        description = "Failed to resolve linkage dependency PromiseKit x86_64 -> @rpath/libswiftObjectiveC.dylib: Unknown arch x86_64";
        info =             {
        };
        level = WARN;
    },
            {
        code = 0;
        description = "Failed to verify bitcode in PromiseKit.framework/PromiseKit:\nerror: Cannot extract bundle from /var/folders/q5/hm9v_6x53lj0gj02yxqtkmd40000gn/T/IDEDistributionOptionThinning.RJD/Payload/MyAppName.app/Frameworks/PromiseKit.framework/PromiseKit (x86_64)\n\n";
        info =             {
        };
        level = ERROR;
        type = "malformed-payload";
    }
);

Some other solutions I tried was using a Project Reference to PromiseKit, instead of a Framework reference, however this doesn't work - in that I still need a framework reference from my main project, because I will get "library not loaded" error at runtime, if running without a FW reference. Same issue occurs when archiving while using a project reference.

4条回答
姐就是有狂的资本
2楼-- · 2020-05-25 07:03

This is what worked for me, I have application and 2 in-house built frameworks, say A $ B.

Application needs A, but A needs B and since Apple doesn't recommend nesting frameworks, so both A and B had to be included in the app.

This is what my Xcode project looks like.

structure of the application in Xcode

SOLUTION

In the application, under Frameworks, Libraries and Embedded Content, select Embed & Sign for all necessary frameworks. (as shown below)

application frameworks

But for all the custom framework projects, under Frameworks and Libraries section, select Do Not Embed. (as shown below) This fixed the issue for me

custom frameworks

查看更多
▲ chillily
3楼-- · 2020-05-25 07:11

I was able to in-board (compile as part of my framework) - the third party framework code, without referencing it as a Framework. I had to refactor --> rename a few of the classes which conflicted in naming with my own. I didn't want to have this added complexity of inter-framework references and missing / extra architecture slices. Since I am prioritizing simplicity over everything else, this solution worked for me best.

查看更多
小情绪 Triste *
4楼-- · 2020-05-25 07:20

Same issue here. The only workaround I've found is to use static library instead of framework.

In case you are not able to use static library, you'd better file a bug report to Apple.

查看更多
Animai°情兽
5楼-- · 2020-05-25 07:22

Try this! It worked for me and many other people:

Goto

Build phases > Add > New Run Script Phase

The code should work for any default shell, but I recommend just using /bin/sh

and include the following code:

# Type a script or drag a script file from your workspace to insert its path.
# skip if we run in debug
if [ "$CONFIGURATION" == "Debug" ]; then
echo "Skip frameworks cleaning in debug version"
exit 0
fi

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

It seems hat some frameworks ship architectures, that will not be used in the application. Xcode will refuse to sign them. The above script removes unused architectures.

Credits: Some guy at GitHub, I can't find the exact source anymore.

查看更多
登录 后发表回答